🎯 오늘은 아침에 코딩 정리 및 추가 학습을 하고, 개인 과제에 들어가기 앞서 헷갈리거나 어려운 강의를 복습하는 시간을 가졌다.
그리고 Mac 개발 세팅과 프로젝트 생성 및 연동까지 완료하고, 개인 과제 초기 구조 작업까지 완료했다.
✅ 1개씩 증가하는 *
void main() { for (var i = 0; i < 5; i++) { var star = "*"; star += "*"*i; print(star); } } /* 출력 * ** *** **** ***** */👉 다른 코드
void main() { for (var i = 1; i <= 5; i++) { print('*' * i); } }
✅ 1개씩 감소하는 *
void main() { for (var i = 5; i >= 1; i--) { print('*' * i); } }👉 우측 정렬
void main() { for (var i = 5; i >= 1; i--) { var space = ' ' * (5 - i); var star = '*' * i; print(space + star); } } /* 출력 ***** **** *** ** * */
✅ *로 정사각형 만들기
void main() { for (var i = 0; i <= 5; i++) { var star = "*"*5; print(star); } } /* 출력 ***** ***** ***** ***** ***** ***** */👉 다른 코드 1
void main() { int rows = 5; // 개수 for (var i = 0; i < rows; i++) { var stars = "*" * rows; print(stars); } }👉 다른 코드 2
void main() { int rows = 5; // 개수 for (var i = 0; i < rows; i++) { var star = ""; for (var j = 1; j <= 5; j++){ star += "*"; } print(star); } }
✅ 다이아몬드
void main() { int n = 5; // 높이 (다이아몬드의 절반 높이) // 🔺 위쪽 삼각형 for (var i = 1; i <= n; i++) { var space = ' ' * (n - i); var star = '*' * (i * 2 - 1); print(space + star); } // 🔻 아래쪽 삼각형 for (var i = n - 1; i >= 1; i--) { var space = ' ' * (n - i); var star = '*' * (i * 2 - 1); print(space + star); } } /* 출력 * *** ***** ******* ********* ******* ***** *** * */
✅ 테두리 별 피라미드
void main() { int n = 5; // 피라미드 높이 // for (var i = 1; i <= n; i++) { var space = ' ' * (n - i); if (i == 1) { print(space + '*'); } else if (i == n) { print(space + '*' * (i * 2 - 1)); } else { var middleSpace = ' ' * (i * 2 - 3); print(space + '*' + middleSpace + '*'); } } } /* * * * * * * * ********* */💬 직접 작성한 코드와 정리한 코드, 해설 시간에 배운 코드, 새로 찾아본 코드 등 쭉 정리해봤다. 이것 말고도 함수를 이용한다던가, 재사용 가능한 코드 등 다양한 방법이 있었다.
List와join,StringBuffer, 재귀함수 같은게 있었는데 아직 안배운 방법? 처음보는 것들이라서 디테일하게 파기보다는 이런 방법도 있구나 하고 넘겼다.
다른 코드에서는 필요할지 모르지만 알고리즘 코드 작성에서는 최대한 간결하고, 가독성 좋게 코드를 작성하는게 중요할 것 같았다.
그리고, 이것저것 쓰는 것 보다 아는 코드를 즉 기본 코드, 기초 문법을 써도 상관 없지않나 싶기도 하고...
💬 알고리즘이 중요하다고 생각하는데, 우선 지금 배움의 초보자에게는 굳은 생각을 말랑말랑하게 할 수 있는게 실전 외에 더 접하기 쉬운게 알고리즘이라 생각한다.
코드가 생각이 안나도 최대한 써보고 출력해보고 수정해가면서 코드를 직접적으로 익히니 좋은 것 같다.
그리고 정답은 없겠지만, 물론 출력값은 잘 나와야할 것 여러 방법이 있다는게 새로운 경험을 하니 새로운 배움이 느는 것 같다.
이제 매일아침에 코딩수업을 들으면 조금 더 다른 방식으로 코드를 작성해본다던가, 또다른 방법이 있는지 AI를 활용하여 접하는 것도 괜찮은 것 같아서 별다른 일이 없다면 학습 루틴에 추가해볼까 한다.
💬 이번 과제는 예외 처리 및 비동기 방식을 구현하는 것에 초점이 맞춰져 있다고 하여, 해당 프로그래밍 부분 강의를 복습하였다.
지난 주에 들었을 때, 다 듣긴 했지만 예외 처리와 오류, 비동기 방식이 좀 어렵다고 느껴졌다. 예외랑 오류는 그 종류가 많고 그걸 코드로 작성하는게 어려워 보였다.
비동기 방식은 단순히 어떠한 코드를 쓴다는 점에서는 알기 쉬웠지만, 깊게 파고들수록 코드가 조금만 추가되어도 코드가 바로 안읽히고 해석하는데 좀 걸린다는 것이다.
그래서 우선 강의를 천천히 다시 들어보기로 하였고, 여전히 알쏭달쏭... 궁금증이 가득한 것들은 학습 자료를 보거나, 다시 앞으로 돌려서 보는 등 이해하고 넘어가고자 했다.
Future<void> introduce(String name) async { print('$name의 자기소개'); // await Future.delayed(Duration(seconds: 2), () { print('안녕 ? 나는 $name'); }); print('$name의 자기소개 끝 !'); return '이름은 $name'; //반환값이 필요한 경우 작성 } // void main() async { var nickname = await introduce('hayancode'); var name = await introduce('Mini'); print("나의 $nickname, $name"); } /* hayancode의 자기소개 안녕 ? 나는 hayancode hayancode의 자기소개 끝 ! Mini의 자기소개 안녕 ? 나는 Mini Mini의 자기소개 끝 ! 나의 닉네임은 hayancode, 이름은 Mini */지난 시간에 들었을 때 놓친게 있었는데,
❕ 여기서main에는Future이 없어 다음nickname과name이await introduce에 종속되어 있기 때문에 순차적으로 출력된다.
Stream<String> emitNames(List<String> names) async* { for (var i = 0; i < names.length; i++) { yield '${i + 1}번째는 ${names[i]} ~'; } } void main() { List<String> names = ['가', '나', '다']; emitNames(names).listen((element) { print(element); }); }❕ 여기서
yield는Future에서return과 비슷하다고 생각하면 되는데,listen을 사용해서 방출된 값을 받아 사용한다.
그리고 잊지 말아야하는 건 async가 아닌async*를 사용해야 한다.
💬 저번에는 윈도우 환경에서 사용해보았으니, 이번에는 맥환경에서 작업해보기 위해 먼저 개발 환경을 세팅해주었다. 저번에 과제했을 때, 잘 작동하는지 확인하기 위해 기본 설치 및 세팅을 완료하였으나, 혹시 안되어있는 것이 있는지 확인했다.
flutter doctor를 돌렸을 때 정상적으로 체크 표시가 나타나며 이상이 없는 것을 알 수 있다.
VScode, Git, Fork 등 윈도우에서 사용하는 프로그램을 실행시켜서 잘 작동하는지 확인까지 완료했다.
그리고, 파일 경로나 아래 생성한 프로젝트 파일을 등록 및 클론까지 잘되는 것을 볼 수 있었다.
💬 다만 강의 링크나 velog 로그인, 북마크 등이 하나도 되어있지 않기 때문에 이러한 기본 세팅도 해두는게 좋을 것 같았다.
dart create -t console-full rpg_game💬 우선
rpg_gmae으로 콘솔 프로젝트를 생성했다.
명령어는 윈도우와 맥이 동일했고, -full 을 붙여서, 폴더 구조나 기본 세팅까지 같이 만드는 것이다.
플러터 프로젝트를 만들 때는flutter create를 입력하면 된다고 한다.
solo_proj_rpg_game
💬 그리고 git에는 해당 이름으로 저장소를 생성했고, 파일을 업로드했다.
solo_proj_rpg_game
💬 동일한 이름으로fork에clone해서 프로젝트 생성을 완료했다.
💬 우선 아직 심화 작업이 어려운 코드나 처음 사용하는 기능 때문에 작업에 들어가기 앞서 어떤 순서로 작업할지, 어떤 부분에서 지식이 필요한지 정리하는 시간을 가졌다.
작업 순서와 기능 구현 등 구상이 끝나고 처음보는 데이터 불러오기나 활용하기, 추상 클래스 사용하는 것과@override의 예제를 추가로 찾아봤고, 어떻게 사용하는지 학습했다.
그리고 나아가 이걸 어떻게 활용할지, 파일 구조는 어떻게 나눌지 고려해보기로 했다.
프로젝트 구상
1️⃣ 기능 목록 정리
플레이어는 무엇을 할 수 있는지
몬스터와 어떻게 싸우는지
옵션이 있다면 어떻게 동작하는지
게임 종료 조건은?
💡 무엇을 만들지 설계
2️⃣ 클래스 설계
게임
플레이어
몬스터
쓰러진 몬스터
3️⃣ 기본 데이터 설계
플레이어 정보 → 이름, 체력, 공격력, 방어력
몬스터 정보 → 이름, 체력, 공격력, 방어력
4️⃣ 메뉴와 게임 흐름 설계
캐릭터 및 몬스터 데이터 파일 불러오기
캐릭터 이름 입력
몬스터 등장
행동 선택
게임 종료
게임 종료시 결과를 파일에 저장
5️⃣ 작동 순서 구상
시작 → 캐릭터 및 몬스터 데이터 입력 → 캐릭터 이름 입력 → 몬스터 랜덤 등장 출력 → 행동 선택 → 결과 → 다음 몬스터를 잡을지 선택
6️⃣ 코드 작업 순서
캐릭터 클래스 만들기
몬스터 클래스 만들기
기본 전투 로직 테스트
출력 로직 만들기
기능 연결
추가 기능 넣기 (아이템 등 도전 기능)
❗주의!
❗ 예외 처리를 통해 파일이 없거나 잘못된 형식의 데이터를 읽었을 때 프로그램이 종료되지 않도록 할 것
❗ 사용자 입력에 대해 검증하여 예상치 못한 입력으로 인한 오류를 방지할 것
❗ 코드의 재사용성과 가독성을 높이기 위해 함수와 클래스를 적절히 활용할 것
dev_dependencies: test: ^1.24.0dev_dependencies: lints: ^4.0.0 test: ^1.24.0💬
pubspec.yaml에 해당 코드를 추가하면 테스트 폴더의 파일에서 코드를 테스트 할 수 있다고 한다.
그런데 -full로 콘솔을 만들었더니, 이미 저렇게 입력이 되어있었다.
dart pub get💬 당연히? 해당 라이브러리도 설치해준다.
dart test💬 이제 명령어를 입력하면 기능 동작 자동 검사를 하는 것이다.
실행하면 성공, 실패 여부가 자동으로 나온다고 해서 이 테스트 파일도 한번 써볼 예정이다.
테스트 대상 체크 항목 Player 생성자 작동, 공격, 체력 깎임, 사망 판정 Monster 생성자, 공격, 사망 판정 Battle 공격 순서, 데미지 계산, 승패 판정 Data CSV 로딩, 파일 저장/불러오기
✔️
lib/
utils.dart→ 공통 함수
player.dart→ 플레이어 클래스
monster.dart→ 몬스터 클래스
game.dart→ 캐릭터Character, 몬스터 리스트List<Monster>, 물리친 몬스터 개수int
battle.dart→ 전투 기능
data.dart→ CSV 불러오기, 파일 저장 기능(loadMonsters(),saveGame())
✔️
bin/
main.dart→ 게임 실행
✔️
test/
test.dart→ Player, Monster, Battle, Data 테스트
💬 우선 파일을 나누는 연습도 같이 하기로 하고, 이런 식으로 폴더 구조를 설정했다.
dependencies: csv: ^5.0.0💬 csv 형식으로 된 데이터 파일을 읽기 위해
pubspec.yaml에 해당 코드를 추가해준다.
import 'dart:io'; // void main() { final file = File('monster.csv'); final lines = file.readAsLinesSync();💬 이렇게 사용하면 파일을 읽어오는 것도 가능하다고 하는데 작업을 들어가봐야 알 것 같다.
abstract class Unit { ... } class Player extends Unit { ... } class Monster extends Unit { ... }💬 추상 클래스는 이런 식으로 만들어서 상속받아서 사용하면 될 것 같다.
class Unit { String name; int hp; Unit(this.name, this.hp); } class Player extends Unit { Player(String name, int hp, this.job) : super(name, hp); }💬 생성자에서는
super를 사용해서 부모 클래스의 생성자를 호출한다.
class Unit { void attack() { print('기본 공격!'); } } // class Player extends Unit { void attack() { super.attack(); // 부모의 attack() 호출 print('플레이어가 추가로 강하게 때린다!'); } }💬 메서드에서는 부모의 기능을 추가로 동작하거나 덮어쓸 때 사용한다고 한다.
✅ 초기 구조 작업
✔️ 작업 파일 구분
✔️ 데이터 파일 생성
🌱 오늘은 아침에 코딩을 좀 더 학습하고 분석? 해보면서 오전 시간을 좀 보냈다.
그리고 이해가 안되거나 헷갈리는 부분의 강의를 복습하면서 이해하고자 했는데, 아직 뭔가 부족한 것 같기도 하고...
과제 안내 받았을 때나 얼핏 본 과제 내용으로는 그 내용이 좀 방대하고 생각나는 코드가 없는 것도 있어서 지금의 지식 상태로 구현이 될지 모르겠다.
맥은 지금 마우스랑 호환이 안되어서 패드로... 터치나 드래그를 해야되기 때문에 고민을 했는데 콘솔은 이번이 아마 마지막일 것이라서 맥에서 과제를 해보는 것도 좋은 경험이라 판단해 맥에서 해보기로 하였다.
다만 방식은 비슷하고, 명령어도 같기 때문에 크게 다를게 없지만 저번 과제에서 생겼던 인코딩 오류가 윈도우 환경에서만 발생하고... 지금도 해결이 안되어서 버전문제인지? 작업하면서 중간중간 맥으로 체크하고 왔다갔다 하는 것도 괜찮은 것 같다.
이것저것 노션이나 강의, 자료 등 맥에도 북마크를 추가하였고, 어느정도 개발환경 세팅이 완료된 것 같다.
프로젝트 구상도 완료하였고, 파일도 분류하였으니 이를 토대로 작업을 진행하면 될 것 같다.
🚀 내일은 과제 본격적으로 시작할 예정인데, 만약 막히거나 어려운 부분이 많다면 사용해야되는 함수나 코드를 조금 더 학습해야 이걸 사용할 수 있을지도 모르겠다.
우선, 구상 > 풀어서 써보기까지 완료하였고, 코드 작업 순서대로 진행할 예정이다.
한가지 고민인건 저번에 파일을 2개로 나눠서 작업을 진행했는데, 이게 import 하면서 추가적인 작업이 필요하다는 것이다. 이게 왜 고민이냐면 보기엔 깔끔하고, 입출력 부분과 클래스, 매서드 부분이 분리가 되어있어서 좋다는 것인데...
과제 내용을 생각하면 분량이 방대하다고 생각되어서 분리하는게 맞을지도 모르겠다. 근데 분리하면 또 복잡하나 싶고... 💫
❕ 결국 파일을 분류하기로 결정했는데, 무엇보다 실무에서도 파일을 나누고 관리해야하기 때문에 이런식으로 잘게 쪼갠다고 한다.
과제 내용은 그정도 많지는 않지만 많긴 하지만 미리 연습하고 파일 관리를 하는 습관을 들이는게 좋을 것 같다.