이 글은 Today I Learn 시리즈의 98번째 기록입니다. (총 213개)

색이 3개면 무슨 그림인지 모른다

65레벨까지 해 보니 3색 판은 알아볼 수가 없었다

65레벨까지 직접 해 봤다. 색이 3개인 판은 무엇을 그린 건지 알아볼 수 없었다. 이 게임에서 다 부은 뒤 그림을 알아보는 건 보상인데, 뭔지 모르면 깬 맛이 없다.

그래서 도안은 색이 4개 이상이어야 한다고 정했다.


4색으로 늘렸는데도 안 읽혔다

색을 4개 이상으로 맞췄는데도 안 읽히는 판이 나왔다. 재 보니 색은 5개인데 그중 셋이 거의 같은 하늘색과 회색이었다. 화면에서는 두 색으로 보였다.

색 수와 색 구분은 다른 문제였다. 색끼리 최소한 이만큼은 떨어져 있어야 한다는 거리 기준을 하나 더 넣었다.

  • 색 수는 세면 되지만 구분은 눈이 한다. 눈으로 본 기준을 숫자로 옮길 때는 둘 다 옮긴다

벌려서 고치려 했더니 배경이 깨졌다

비슷한 색끼리 밝기를 벌려 봤다. 전경끼리는 떨어졌는데 그중 하나가 배경 쪽으로 밀려났다.

지금          전경끼리 비슷한 도안 176종 / 배경과 비슷한 도안  1종
밝기 벌린 뒤   전경끼리 비슷한 도안  77종 / 배경과 비슷한 도안 36종

100종을 고치고 35종을 새로 깼다. 원래 비슷한 색으로 그려진 그림은 벌린다고 나아지지 않는다. 그림 자체가 그런 그림이다.

  • 한 기준을 억지로 맞추면 다른 기준이 깨진다. 고친 수와 새로 깬 수를 같이 세야 남는 게 있는지 보인다

그래서 버리기로 했다

기준을 못 지키는 도안은 고치지 않고 빼기로 했다. 필요한 건 500종, 가진 건 1088종, 기준을 통과한 건 566종이었다.

  • 여유가 있으면 기준을 깎는 것보다 버리는 쪽이 낫다. 모자라면 소스를 더 구하면 된다
  • 버릴 수 있는지는 필요한 수와 가진 수를 세 봐야 안다

기다리는 시간

35분짜리 확인을 하루에 다섯 번 기다렸다

설정을 하나 바꾸고 결과를 보려면 레벨 전체를 다시 만들어야 했다. 한 번에 35분, 이날만 다섯 번을 기다렸다.

몇 레벨만 골라 만드는 미리보기를 만들었더니 15초가 됐다. 다만 미리보기는 진짜 생성과 같은 길을 타야 한다. 도안을 하나로 고정해 두는 식으로 길을 바꾸면 실제 배정과 다른 것을 보게 된다.

  • 느린 확인을 반복하고 있으면 그 확인부터 빠르게 만든다. 기다린 시간이 만드는 시간보다 훨씬 길었다
  • 미리보기는 진짜와 같은 길을 타야 한다. 다른 길로 본 결과는 다른 것을 본 것이다

그다음엔 80분을 기다려야 했다

레벨이 늘자 500레벨을 다시 만드는 데 80분이 걸렸다. CPU를 보니 8코어 중 하나만 일하고 있었다.

레벨끼리는 서로 참조하지 않으니 나눠서 동시에 돌릴 수 있다(병렬 처리). 나눴더니 3분이 됐다.

  • 서로 기대지 않는 일은 코어 수만큼 그대로 빨라진다. 기다리는 게 길면 먼저 “이게 꼭 한 줄로 서 있어야 하나”를 본다

테스트를 다 통과한 채 숨어 있던 것들

이날 잡은 것 중 여럿이 자동 검사를 전부 통과한 상태였다. 규칙상 문제가 없어서 안 걸렸고, 직접 플레이하거나 숫자를 다시 재 보고 나서야 드러났다.

레일이 6칸인 판이 있었다

레일은 5칸이다. 그런데 37개 레벨이 6칸으로 나가고 있었다. 생성기가 조건에 맞는 배치를 못 찾으면 레일을 한 칸 늘려 풀리게 만드는 안전망이 있었던 것이다.

레일 5칸은 플레이어가 배우는 규칙이고, 화면의 n/5 표시와 광고로 칸을 늘리는 버튼의 뜻이 거기 묶여 있다. 레벨마다 다르면 안 된다.

그래서 못 맞출 때 무엇부터 포기할지 순서를 정했다.

1. 목표 난이도 맞추기    먼저 포기
2. 색 규칙              그다음 (로그에 남김)
3. 도안 안 겹치기        마지막 (로그에 남김)
4. 깰 수 있음 · 레일 5칸  절대 양보 안 함
  • 무엇을 먼저 포기할지 정해 두지 않으면 코드가 그때그때 편한 걸 포기한다
  • 안전망도 규칙 안에서 움직여야 한다. 풀리게 하려고 규칙을 바꾸면 그건 다른 게임이다

바스켓을 늘리라고 했더니 난이도가 틀어졌다

보드에 바스켓이 너무 적어 보여서 최소 10개는 되게 하자고 했다. 그랬더니 난이도가 목표를 크게 벗어났다. 알고 보니 난이도를 맞출 때 바스켓 개수와 벽 개수가 서로 영향을 받고 있었다.

생성기가 난이도를 맞추려고 실제로 움직여 보는 값이 바스켓 수 하나뿐이었다. 그 값을 못 박으니 난이도를 조절할 손잡이가 사라진 것이다. 최소만 두고 위로는 여지를 남겼다.

  • 무언가를 고정하기 전에 그게 다른 무엇을 조절하는 손잡이는 아닌지 본다
  • 두 목표가 같은 값을 나눠 쓰면 하나를 못 박는 순간 다른 하나가 안 움직인다

직접 만든 호랑이 도안이 한 번도 안 나왔다

한국 도안을 늘리면서 호랑이를 직접 만들어 넣었는데 레벨에 한 번도 안 쓰이고 있었다. 외부에서 받은 도안 중에도 같은 이름(tiger)이 있었고, 이미 쓴 도안인지를 이름으로만 판정하니 하나가 쓰이면 나머지는 영영 안 나왔다.

이름 앞에 출처를 붙여 구분했다. 같은 이름을 출처별로 다른 칸에 두는 걸 네임스페이스라고 한다.

  • 이름으로 같은 것을 판정하면 출처만 다른 같은 이름이 조용히 사라진다. 경고도 안 나고 테스트도 통과한다

난이도 배지가 사라졌다

좁은 화면에서 레벨 번호 옆 난이도 배지가 넘쳐 삐져나왔다. 남는 폭에 맞춰 줄어드는 칸(Flexible)에 넣었더니 넘침은 사라졌는데 배지가 아예 안 보였다.

넘침을 사라짐으로 바꾼 셈이었다. 번호와 배지를 두 줄로 나눠 폭을 다툴 일 자체를 없앴다.

  • 오류 표시가 사라졌다고 고쳐진 게 아니다. 넘침은 눈에 띄는 버그고 사라짐은 안 띄는 버그다

아이템을 쓰려던 손이 구매 창으로 샜다

아이템 버튼 구석에 개수 배지를 달았더니 그 배지가 탭을 가로챘다. 아이템을 쓰려고 누른 손가락이 배지에 걸리면 구매 창이 떴다.

배지는 개수를 보여 주기만 하면 된다. 아예 탭을 안 받게 해서(IgnorePointer — 자기는 탭을 받지 않고 뒤로 흘려보내는 위젯) 뒤의 아이템 버튼이 받게 했다.

  • 보여 주기만 하는 것은 누르는 자리를 차지하지 않게 한다. 작은 표시가 큰 버튼의 일부를 먹는다

Series: Today I Learn

1 C++ 자료형(Data Type) 2 MD5 vs pHash 3 C++에서 함수의 선언과 정의 4 Tkinter padx, pady 5 메모리와 포인터 변수 6 Call by Value, Call by Reference, Call by Pointer 비교 7 const 8 Gemfile — Jekyll 프로젝트의 의존성 파일 9 kramdown-parser-gfm — Jekyll의 GFM 파서 10 파서(Parser) 11 AHU vs OHU 12 I might try it vs I'll try it 뉘앙스 차이 13 SESSION_EXPIRE_AT_BROWSER_CLOSE=True 14 configuration key 15 Git stash vs discard 16 subprocess.Popen으로 Windows 탐색기에 명령어를 전달 17 Post 잔디 분석하기 18 Google Sheets Sync 최적화 19 DSL (Domain Specific Language)과 GPL (General Purpose Language) 20 마크다운 표 그리는 방법 21 쿼리 파라미터(Query Parameter). 기존 QR코드 재활용 22 Django 보안 취약점 점검 및 수정 23 OOP Object-Oriented Programming 객체 지향 프로그래밍 24 Fernet 대칭 암호화 25 Jekyll 코드블록 안의 Liquid 태그 26 습관만들기 Pawbit TIL 1 27 insertOnConflictUpdate vs DoUpdate(target) 28 세션 필터 29 아코디언(Accordiaon) UI를 펼친상태로 만들기 30 input의 step 31 습관만들기 Pawbit TIL 2 32 습관만들기 Pawbit TIL 3 33 Word Cloud 34 Google Sheets를 데이터 버스로(with AppSheet) 35 Django 모델 텍스트 필드 자동 수집 패턴 36 localStorage로 섹션 토글 상태 유지 37 순차 ID 생성(`select_for_update()` + `max()` 조합) 38 역참조 검색과 distinct() 39 xlsx 다운로드와 로딩 오버레이 충돌 40 Android 파일 공유 MIME 타입 41 AssetManifest — Flutter 빌드 타임 asset 목록 런타임 조회 42 크레센도 Phaser + TypeScript TIL 1 43 크레센도 Phaser + TypeScript TIL 2 44 크레센도 Phaser + TypeScript TIL 3 45 크레센도 Phaser + TypeScript TIL 4 46 크레센도 Phaser + TypeScript TIL 5 47 여둘까 Office Layout TIL 1 48 습관만들기 Pawbit TIL 4 49 여둘까 Office Layout TIL 2 50 여둘까 Office Layout TIL 3 51 크레센도 Phaser + TypeScript TIL 6 52 UTF-8 BOM과 PowerShell 파일 쓰기 53 소리꽃 KeyBloom TIL 1 54 습관만들기 Pawbit TIL 5 55 여둘까 Office Layout TIL 4 56 소리꽃 KeyBloom TIL 2 57 소리꽃 KeyBloom TIL 3 58 메트로놈 Simple Metronome TIL 1 59 소리꽃 KeyBloom TIL 4 60 메트로놈 Simple Metronome TIL 2 61 소리꽃 KeyBloom TIL 5 62 습관만들기 Pawbit TIL 6 63 크레센도 Phaser + TypeScript TIL 7 64 메트로놈 Simple Metronome TIL 3 65 소설 타임라인 관리 도구 Lumior TIL 1 66 습관만들기 Pawbit TIL 7 67 정적 블로그 SEO 정비와 Pagefind 검색 도입 68 크레센도 Phaser + TypeScript TIL 8 69 메트로놈 Simple Metronome TIL 4 70 습관만들기 Pawbit TIL 8 71 안드로이드 AudioTrack 연속 재생, 실측 피커 정렬, 카메라 토치 플래시 72 메트로놈 Simple Metronome TIL 5 73 모래게임 Sandrop TIL 1 74 습관만들기 Pawbit TIL 9 75 메트로놈 Simple Metronome TIL 6 76 모래게임 Sandrop TIL 2 77 모래게임 Sandrop TIL 3 78 습관만들기 Pawbit TIL 10 79 습관만들기 Pawbit TIL 11 80 메트로놈 Simple Metronome TIL 7 81 모래게임 Sandrop TIL 5 82 모래게임 Sandrop TIL 4 83 습관만들기 Pawbit TIL 12 84 모래게임 Sandrop TIL 6 85 소리꽃 KeyBloom TIL 6 86 모래게임 Sandrop TIL 7 87 모래게임 Sandrop TIL 8 88 소리꽃 KeyBloom TIL 7 89 모래게임 Sandrop TIL 9 90 소리꽃 KeyBloom TIL 8 91 모래게임 Sandrop TIL 10 92 소리꽃 KeyBloom TIL 9 93 콘티온 ContiOn TIL 1 94 소리꽃 KeyBloom TIL 10 95 콘티온 ContiOn TIL 2 96 습관만들기 Pawbit TIL 13 97 콘티온 ContiOn TIL 3 98 모래게임 Sandrop TIL 11 읽는 중 99 소리꽃 KeyBloom TIL 11 100 여둘까 Office Layout TIL 5 101 모래게임 Sandrop TIL 12 102 모래게임 Sandrop TIL 13 103 콘티온 ContiOn TIL 4 104 모래게임 Sandrop TIL 14 105 소리꽃 KeyBloom TIL 12 106 습관만들기 Pawbit TIL 14 107 모래게임 Sandrop TIL 15 108 모래게임 Sandrop TIL 16 109 소리꽃 KeyBloom TIL 13 110 온실 GreenHouse TIL 1 111 콘티온 ContiOn TIL 5 112 모래게임 Sandrop TIL 17 113 소리꽃 KeyBloom TIL 14 114 온실 GreenHouse TIL 2 115 콘티온 ContiOn TIL 6 116 모래게임 Sandrop TIL 18 117 콘티온 ContiOn TIL 7 118 모래게임 Sandrop TIL 19 119 소리꽃 KeyBloom TIL 15 120 모래게임 Sandrop TIL 20 121 모래게임 Sandrop TIL 21 122 소리꽃 KeyBloom TIL 16 123 소리꽃 KeyBloom TIL 17 124 소리꽃 KeyBloom TIL 18 125 여둘까 Office Layout TIL 6 126 소리꽃 KeyBloom TIL 19 127 소리꽃 KeyBloom TIL 20 128 콘티온 ContiOn TIL 8 129 콘티온 ContiOn TIL 9 130 로그스톤 상표 셀프 출원 TIL 1 131 소리꽃 KeyBloom TIL 21 132 로그스톤 샵 LogStone Shop TIL 1 133 소리꽃 KeyBloom TIL 22 134 로그스톤 샵 LogStone Shop TIL 2 135 소리꽃 KeyBloom TIL 23 136 모래게임 Sandrop TIL 22 137 모래게임 Sandrop TIL 23 138 소리꽃 KeyBloom TIL 24 139 로그스톤 샵 LogStone Shop TIL 3 140 모래게임 Sandrop TIL 24 141 소리꽃 KeyBloom TIL 25 142 모래게임 Sandrop TIL 25 143 MiniMacro TIL 1 144 모래게임 Sandrop TIL 26 145 콘티온 ContiOn TIL 10 146 Astro가 무엇인지, 왜 옮기는지 147 모래게임 Sandrop TIL 27 148 소리꽃 KeyBloom TIL 26 149 MiniMacro TIL 2 150 로그스톤 샵 LogStone Shop TIL 4 151 메트로놈 Simple Metronome TIL 8 152 모래게임 Sandrop TIL 28 153 여둘까 Office Layout TIL 7 154 메트로놈 Simple Metronome TIL 9 155 블로그 Astro 이관 TIL 156 여둘까 Office Layout TIL 8 157 로그스톤 샵 LogStone Shop TIL 5 158 모래게임 Sandrop TIL 29 159 오픈데이 Openday TIL 1 160 로그스톤 샵 LogStone Shop TIL 6 161 모래게임 Sandrop TIL 30 162 오픈데이 Openday TIL 2 163 모래게임 Sandrop TIL 31 164 Unreal Engine MCP TIL 1 165 모래게임 Sandrop TIL 32 166 소리꽃 KeyBloom TIL 27 167 콘티온 ContiOn TIL 11 168 오픈데이 Openday TIL 3 169 로그스톤 샵 LogStone Shop TIL 7 170 모래게임 Sandrop TIL 33 171 소리꽃 KeyBloom TIL 28 172 오픈데이 Openday TIL 4 173 여둘까 Office Layout TIL 9 174 오픈데이 Openday TIL 5 175 ScorePlayer TIL 1 176 모래게임 Sandrop TIL 34 177 BuildingHub TIL 1 178 ScorePlayer TIL 2 179 여둘까 Office Layout TIL 10 180 BuildingHub TIL 2 181 ScorePlayer TIL 3 182 Unreal Engine MCP TIL 2 183 궁 미로 PalaceMaze TIL 1 184 메트로놈 Simple Metronome TIL 10 185 메트로놈 Simple Metronome TIL 11 186 오픈데이 Openday TIL 6 187 BuildingHub TIL 3 188 Obsidian vault에서 코드만 빼기 — directory junction 189 ScorePlayer TIL 4 190 여둘까 Office Layout TIL 11 191 오픈데이 Openday TIL 7 192 URL은 바뀔 수 있는 것에 묶지 않는다 193 도구는 기능이 아니라 내 일에 맞는지로 고른다 194 돌이키기 힘든 변경은 작게 먼저 확인한다 195 궁 미로 PalaceMaze TIL 2 196 궁 미로 PalaceMaze TIL 3 197 소리꽃 KeyBloom TIL 29 198 오픈데이 Openday TIL 8 199 BuildingHub TIL 4 200 ScorePlayer TIL 5 201 로그스톤 샵 LogStone Shop TIL 8 202 여둘까 Office Layout TIL 12 203 오픈데이 Openday TIL 9 204 BuildingHub TIL 5 205 MiniMacro TIL 3 206 소리꽃 KeyBloom TIL 30 207 오픈데이 Openday TIL 10 208 여둘까 Office Layout TIL 13 209 소리꽃 KeyBloom TIL 31 210 궁 미로 PalaceMaze TIL 4 211 로그스톤 샵 LogStone Shop TIL 9 212 로그스톤 샵 LogStone Shop TIL 10 213 소리꽃 KeyBloom TIL 32