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

그림 색을 눌러서 배경과 떼어 놓고 있었다

움직일 쪽은 그림이 아니라 배경이었다

캔버스에서 아직 안 채운 칸은 배경색으로 보인다. 그림 색이 배경과 비슷하면 채운 칸인지 아닌지 구별이 안 되니, 둘 사이에 최소 거리를 강제하고 있었다. 그 거리를 못 넘기면 그림 색을 어둡게 눌렀다.

문제는 배경을 만드는 방식이었다. 배경을 그 도안의 주조색에서 뽑으니 배경이 그림 색 근처에 놓일 수밖에 없다. 연한 그림은 어떤 값으로도 기준을 못 넘기고, 결국 그림이 눌린다. 전체 1,629종 중 473종이 그렇게 눌리고 있었다.

배경은 우리가 만들어 내는 값이고 그림은 그린 사람의 것이다. 순서를 뒤집어 배경을 그림과 무관하게 고르기로 했다. 그렇게 하니 생일케이크 하나만 봐도 가능한 배경 후보가 색 공간의 81%였다. 색이 뭉쳐 등록에서 떨어졌던 도안 129종도 배경만 옮기니 통과했다.

앞선 TIL 8에서 흰색을 살려 놓고 그 흰색을 다시 누르지 않으려고 배경을 내리는 쪽을 택했다. 같은 결의 판단을 이번에는 도안 전체에 적용한 셈이다.

  • 제약을 못 지킬 때 무엇이 양보할지부터 정한다. 받은 것과 만든 것이 부딪히면 대개 만든 쪽이 움직여야 한다

어떤 배경이 어울리는지는 숫자로 못 고른다

기준을 넘기는 배경 후보는 도안마다 수천 개다. 그중 무엇이 그림과 어울리는지는 숫자로 못 정한다.

그래서 직접 고르기로 했다. 도안마다 후보 다섯 개를 깔고 추천 하나를 미리 골라 둔 페이지를 만들게 해서, 마음에 안 드는 것만 바꾸면 되게 했다. 어떤 배경을 깔아도 별로인 그림은 “사용 안 함”으로 뺄 수 있게 했고, 그 판단은 쌓아 두어 다시 묻지 않는다.

602종을 직접 골랐고 149종이 빠졌다. 시계·화살표·금지 표지처럼 퍼즐 도안으로 안 맞는 것들이었다.

  • 사람이 판단해야 할 자리와 자동으로 될 자리를 나눈다. 어울림은 사람이, 거리 기준은 코드가 본다
  • 사람에게 묻는 도구는 묻는 횟수를 줄이는 게 품질이다. 기본값을 잘 채워 두면 훑고 지나갈 수 있어서 600종도 할 만했다
  • 한 번 내린 판단은 다시 묻지 않는다. 같은 걸 두 번 고르게 하면 도구를 안 쓰게 된다

그림을 안 건드리게 했더니 검사까지 꺼졌다

배경을 지정한 도안은 그림 색을 건드리지 않게 했다. 그런데 그러면서 그림과 배경 사이 거리를 재는 검사까지 통째로 꺼졌다.

배경 후보를 고를 때 잰 건 색을 줄이기 전의 원본 색이라 근사치였다. Claude가 최종 색으로 다시 재 보니, 색을 줄이면서 새로 생긴 평균색이나 면적이 작아 후보 계산에서 빠진 색이 배경에 묻어 있었다. 139종이 그렇게 됐고 그중 49개가 실제 레벨에 들어가 있었다. 한 레벨은 눈 흰자와 배경의 거리가 기준 85에 한참 못 미치는 10.7이었다.

검사를 다시 켰다. 이 보정은 이미 기준을 넘긴 색은 그대로 두기 때문에, 켜 두어도 못 넘긴 색에만 걸린다. 그 레벨은 눈 흰자만 조정되고 나머지 색은 원본 그대로 남았다. 어떻게 해도 배경과 구별 안 되는 색이 있는 16종은 풀에서 뺐다.

  • “그림을 안 건드린다”가 목적이었는데 그 보정은 “읽을 수 없는 판을 막는다”는 역할도 겸하고 있었다. 기능을 끌 때는 그 기능이 겸하던 역할이 있는지 본다
  • 끄는 것과 범위를 좁히는 것은 다르다. 원하는 게 “멀쩡한 건 건드리지 마”라면 끌 게 아니라 못 넘긴 것에만 걸리게 하면 된다

최고 난이도가 여전히 안 어려웠다

전날 고쳤다고 한 문제가 그대로였다

앞선 TIL 24에서 최고 난이도를 손봤는데 또 헐거운 판이 나왔다. 원인이 셋이었다. 축소판 측정을 금지했는데 판을 걸러 내는 단계는 아직 축소판으로 재고 있었고, 바구니 최소 개수는 실제로 검사하는 곳이 없어 조용히 잘리고 있었고, 기믹을 확정으로 배정하는 목록에서 최고 난이도만 빠져 있었다. 가장 어려워야 할 판이 그 아래 난이도보다 기믹을 덜 받고 있었다.

셋을 다 고쳤다. 그리고 하나를 더 바꿨다. “이보다 쉬우면 안 된다”는 상한은 나쁜 판을 버리기만 했지 어려운 판을 찾으러 가지는 않았다. 목표 구간에 드는 첫 판에서 멈췄으니 “어려운 판”이 아니라 “안 쉬운 판”을 통과시키고 있던 셈이다. 상위 난이도는 구간 안에서 계획이 가장 어려운 판을 고르게 했다.

  • 거르는 것과 찾는 것은 다르다. 원하는 방향이 있으면 통과 조건이 아니라 고르는 기준에 적는다
  • 정한 규칙이 실제로 모든 자리에 적용됐는지는 따로 확인해야 한다. 금지했다고 다 금지된 게 아니었다

라벨은 나중에 붙는데 바닥은 처음에 정해졌다

셋을 다 고쳤는데도 최고 어려움 14개 중 10개가 여전히 바구니가 모자랐다.

앞선 TIL 16에서 실제로 재 보고 더 어렵게 나온 판은 라벨을 올리기로 했다. 그런데 판을 얼마나 촘촘히 만들지는 처음에 계획 난이도로 정한다. 계획이 보통인 400탄대 판이 헐겁게 만들어졌다가 운 좋게 어렵게 측정되면, 라벨만 최고 어려움이 붙는다. 최고 어려움의 바닥을 아무리 강제해도 이 판은 처음에 “보통”이었으니 안 걸린다.

그래서 난이도가 아니라 레벨 번호로 바닥을 깔기로 했다. 후반이면 난이도와 상관없이 바구니와 벽이 일정 수 이상이다. 500탄 기준 바구니 25개, 벽 4개다. 300탄 이후 판의 바구니가 20개대 중심에서 24~32개 중심으로 올라갔다.

  • 조건에 쓰는 값이 언제 정해지는지 본다. 나중에 바뀌는 값으로 앞에서 조건을 걸면 그 사이에 구멍이 생긴다
  • 나중에 바뀌지 않는 값(레벨 번호)에 걸면 라벨이 어떻게 붙든 바닥이 지켜진다

광고 닫기 버튼이 또 안 떴다

고쳤다고 본 게 세 번이었다

앞선 TIL 24에서 몰입 모드를 광고에 알려 주는 것으로 전면 광고의 X를 살렸다. 그런데 다음 날 같은 코드에서 X가 다시 안 떴다.

그사이 Claude가 방법을 세 가지 넣었고, 넣을 때마다 실기기에서 광고를 띄워 확인했다. 매번 X가 떠서 고쳐졌다고 봤다. 그런데 이 증상은 원래 가끔만 나는 것이었다. 아무것도 안 고쳐도 절반은 뜬다.

  • 가끔 나는 증상은 한 번 사라졌다고 고쳐진 게 아니다. 여러 번 연달아 확인한다
  • “이번엔 됐다”와 “이제 된다”는 다른 말이다

“다른 게임은 표시줄 숨겨도 광고 잘 나오잖아”

세 가지 시도는 전부 광고를 띄우기 직전에 우리 화면 설정을 손보는 것이었다. 광고가 떠 있는 동안 몰입 모드를 어떻게 두느냐, 화면이 어느 쪽을 잡고 있느냐 같은 것이다. Claude는 계속 그 화면 설정을 원인으로 보고, 표시줄을 숨기는 것 자체를 의심하고 있었다. 같은 설명이 거듭되니 답답했다.

그래서 “다른 게임은 표시줄 숨기는데도 광고 잘 나오잖아”라고 했다. 숨기는 게 문제라면 다른 게임도 다 안 돼야 한다. 숨기는 게 문제가 아니라면 숨기는 시점이 다를 수 있다.

그 말로 방향이 바뀌었다. 원인은 광고 근처가 아니라 훨씬 앞이었다. 앞선 TIL 14에서 몰입 모드를 화면마다 켜고 끄지 않고 앱이 켜질 때 한 번 걸기로 했는데, 그게 첫 화면이 자리 잡기도 전이었다. 그 상태로 시작하면 나중에 뜨는 광고가 닫기 버튼을 그릴 자리를 못 찾는다. 숨기는 것을 첫 화면이 그려진 뒤로 미루자 해결됐다. 화면상 차이는 거의 없다.

숨기지 않고 띄우면 광고가 정상이었고, 광고를 닫고 다시 숨긴 뒤의 광고들도 정상이었다. 갈랐던 것은 앱이 처음 뜰 때의 상태 하나였다.

  • 증상이 나는 자리와 원인이 있는 자리는 다를 수 있다. 앱을 켤 때의 순서 문제는 한참 뒤에 다른 모습으로 나타난다
  • 같은 원인 설명이 세 번째 되풀이되면 그 방향을 의심한다. 다른 게임에서는 되는 걸 들이밀면 “이게 되긴 되는 일인가”에서 “그럼 뭐가 다른가”로 질문이 바뀐다

그 밖

승리 화면에서 X를 두 번 누르면 화면이 까매졌다

승리 화면에서 X를 두 번 눌렀더니 화면이 까맣게 멈췄다. 광고를 띄우는 자리가 셋인데 한 곳에만 연타 방지가 없었다. 연타 방지를 각 화면이 아니라 광고를 띄우는 한 곳 안으로 옮겼다.

  • 앞선 TIL 8에서 같은 판단을 두 곳에서 하면 언젠가 갈라진다고 했다. 여러 화면이 지켜야 하는 약속도 같다. 부르는 쪽 셋이 각자 지키게 하지 말고 불리는 쪽 하나가 지키게 한다

11탄까지는 전면 광고를 안 띄운다

앞선 TIL 24에서 전면 광고를 매 판 띄우도록 늘렸다. 그대로면 튜토리얼이 끝나기도 전에 광고가 뜰 수 있다.

11탄까지는 전면 광고를 안 띄우기로 했다. 1탄이 튜토리얼이고 6·7·8탄에서 아이템을 처음 준다. 게임을 배우는 그 구간을 광고로 끊으면 초반에 떠난다. 이 구간에서는 광고 횟수를 세는 클리어 수도 안 센다. 세 두면 보호 구간이 끝나자마자 밀린 몫이 한꺼번에 나온다.

  • 앞선 TIL 7에서 광고는 얼마나 자주 띄우느냐가 더 큰 결정이라고 했다. 빈도만이 아니라 언제부터 띄우느냐도 같은 손잡이다
  • 보호 구간을 두면 그 구간 동안 쌓이는 것도 같이 멈춰야 보호가 끝나는 순간 터지지 않는다

처음 연 날에는 일일 보상을 안 준다

처음 앱을 연 사람에게 일일 보상 카드가 먼저 떴다. 첫 판을 하러 들어온 사람을 보상 화면으로 막고 있었다. 처음 연 날에는 주지 않기로 했다.

첫날인지는 앱을 켠 횟수가 아니라 날짜로 본다. 켠 횟수로 보면 앱을 껐다 켜는 것만으로 첫날에도 받을 수 있다.

  • 보상도 타이밍이 틀리면 방해물이다. 처음 온 사람이 원하는 건 게임이지 보상이 아니다

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