업데이트
무엇이 언제 바뀌었는지만 적습니다. 날짜는 실제로 올린 날입니다.
-
카드놀이 열 갈래를 다 만들었다
다우트 · 스피드 · 신경쇠약 · 도둑잡기 · 같은 그림 찾기 다섯을 더 붙여
열 갈래가 다 찼다. 앞서 올린 원카드까지 여섯은 솔리테어 넷과 얼개가 다르다 —
상대가 있고, 상대 패를 못 본다.그래서 솔리테어 넷에서 쓰던 "풀리는 판만 낸다" 를 쓸 수 없다.
대신 갈래마다 검사로 못 박은 약속을 하나씩 두었다.- 원카드 — 판이 반드시 끝난다. 더미가 마르면 바닥을 뒤집어 다시 쓴다.
사백 판을 끝까지 두어 안 끝나는 판이 하나도 없음을 확인한다.
그리고 컴퓨터에게는 걸러 준 것만 넘어간다 — 검사가 그 경계에 무엇이 들었는지 통째로 캔다- 다우트 — 카드 값이 상대 쪽으로 새면 놀이가 무너진다. hidden() 이 경계고,
자리가 하나만 늘어도 검사가 떨어진다. 컴퓨터는 표정이 아니라 셈으로 의심한다 —
같은 끗수는 넉 장뿐이니 제 손에 몇 장 있는지만 세면 확실한 거짓말이 보인다- 스피드 — 시간이 규칙 안으로 들어온다. 그런데 시계를 엔진에 넣으면 검사를 못 한다.
그래서 엔진은 시간을 아예 안 본다. 언제 내느냐는 화면이 정한다
- 신경쇠약 — 컴퓨터의 기억을 판에서 떼어 따로 든다. 난이도가 곧 "얼마나 잘 외우는가" 다
- 도둑잡기 — 뽑는 쪽은 남의 패를 자리로만 본다
- 같은 그림 찾기 — 판마다 짝이 딱 한 쌍이어야 한다. deal 이 보장하고 검사가 캔다
만들면서 두 번 크게 틀렸다.
다우트가 안 끝났다. 삼백 판 중 서른세 판만 끝났다. 진 사람이 다시 내게 해 두었는데,
손이 마흔 장쯤 되면 어느 끗수든 넉 장을 다 쥐고 있어서 상대의 거짓말이 셈만으로 전부
들통난다. 진 사람이 또 내고 또 걸리고 한 장을 도로 받는 일이 끝없이 돌았다.
무덤을 안 가져간 쪽이 다음에 내도록 바꾸니 오백 판이 전부 끝났다.도둑잡기 요령을 거꾸로 넣었다. 컴퓨터가 도둑을 가운데 숨기게 했는데,
끝만 집는 상대에게 400판에 184 대 244 로 더 졌다. 당연했다 —
도둑은 감출 것이 아니라 넘길 것이다. 안 뽑혀 가면 내가 든 채 끝난다.
잘 뽑히는 자리에 두게 바꾸니 307 대 244 가 됐다.여섯 갈래 모두 솔리테어의 옷을 입혔다. 초록 천 바탕, 같은 카드 짜임,
금색 격자 뒷면, 아래 떴다 사라지는 쪽지, 손가락용 44px 단추. -
솔리테어 넷의 옷을 하나로 맞췄다
피라미드 · 골프 · 트라이픽스 · 유콘을 만들고 나서 나란히 놓아 보니
같은 사이트로 안 보였다. 빛깔도 카드 짜임도 저마다 달랐다.솔리테어(games/solitaire/)를 본으로 삼아 네 갈래의 첫 style 덩이를 통째로 갈아 끼웠다.
- 초록 천 바탕과 빛깔 이름 한 벌
- 카드 앞면은 왼쪽 위 끗수 · 작은 무늬 · 오른쪽 아래 큰 무늬
- 뒷면은 금색 격자
- 더미 장수는 카드 귀퉁이 배지로
- 쪽지는 판 아래에 떴다가 스스로 사라진다
- 손가락으로 쓰는 화면에서는 단추가 44px
카드가 세로로 겹치는 갈래(골프·유콘)에서 끗수를 가운데 두었더니 위 카드에 잘려
글자가 반쪽만 나왔다. 진짜 카드처럼 왼쪽 위 귀퉁이에 적으니 다 읽힌다.[하는 법] 단추가 빈 칸(.sp) 안에 들어가 왼쪽에 홀로 떨어져 있었다.
빈 칸 바로 뒤로 옮겨 오른쪽 단추 무리에 붙였다. -
카드놀이를 다섯 갈래 더 만들었다
피라미드 · 골프 · 트라이픽스 · 유콘 · 원카드. 앞의 넷은 혼자 하는 것이고
마지막 하나는 컴퓨터와 겨루는 것이다.피라미드 — 두 장을 더해 13 이면 걷는다. K 는 13 이라 혼자 걷힌다.
아무렇게나 깔면 45% 만 풀려서, 씨앗을 하나씩 올려 가며 끝까지 걷히는 판을 찾는다.골프 — 규칙이 카드놀이 가운데 제일 짧다. 한 끗 위나 한 끗 아래를 이어 붙이는 것뿐이다.
짧아서 얻는 것이 하나 있다 — 판이 풀리는지를 어림이 아니라 끝까지 따질 수 있다.
줄에서는 맨 아래 한 장만 쓰니, 판의 형편이 (줄 일곱의 남은 장수 · 더미 장수 ·
쌓은 데 맨 위) 아홉 개 수로 다 적힌다. 예산을 두고 끊을 필요가 없었다.트라이픽스 — 이어 붙이는 규칙은 골프와 같고 판 모양만 다르다.
잇달아 걷을수록 점수가 크게 붙는다. 열 장을 내리 걷으면 55점, 한 장씩 열 번이면 10점이다.
자리마다 덮는 자리를 표로 박아 두었다 — 셈으로 뽑으려다 한 칸씩 어긋나 두 번 갈아엎었다.유콘 — 더미가 없다. 쉰두 장이 처음부터 다 깔리고, 앞면이면 어느 카드든
위에 얹힌 것과 통째로 옮긴다. 차례가 안 맞아도 된다. 그래서 한 자리에서 둘 수 있는 수가
스무 개를 넘는다. 끝까지 훑는 것은 어림도 없어 좋아 보이는 자리부터 파고든다.원카드 — 여기부터 얼개가 바뀐다. 상대가 있고, 상대 패를 못 본다.
그래서 "풀리는 판만 낸다" 를 쓸 수 없다. 대신 두 가지를 검사로 못 박았다.- 판이 반드시 끝난다. 더미가 마르면 바닥을 뒤집어 다시 쓴다.
사백 판을 끝까지 두어 안 끝나는 판이 하나도 없음을 확인한다
- 컴퓨터가 남의 패를 훔쳐보지 않는다. AI 에게는 걸러 준 것만 넘어간다 —
검사가 그 경계에 무엇이 들었는지 통째로 캔다
다섯 갈래 모두 솔리테어의 옷을 그대로 입혔다. 초록 천 바탕, 같은 카드 짜임,
금색 격자 뒷면, 더미 장수 배지, 아래 떴다 사라지는 쪽지. 저마다 다른 모양이면
같은 사이트로 안 보인다.덮인 카드를 흐리게(opacity) 죽였더니 스물여덟 장이 한 덩어리 그림자로 뭉쳐서
피라미드 모양조차 안 읽혔다. 낯빛만 죽이고 테두리와 글씨는 남기니 그제야 판으로 보인다. -
도움말이 아니라 훈수다
옆에서 훈수 두는 것이지 설명서가 아니다. 설명서는 하는 법이 따로 있으니
이름이 겹치기도 했다.- 여덟 갈래의 [도움말] 과 스도쿠·윷의 [힌트] 를 훈수로 바꿨다
- 매뉴얼 · 게임 안 안내글 · 단축키 안내(H) · 사진 설명글까지 같이 고쳤다
- 사진 59장을 다시 찍었다. 단추에 옛 이름이 박혀 있었다
바둑의 [?] 와 타자의 [도움말] 은 그대로 뒀다. 저건 훈수가 아니라 정말 설명이다.
같은 날 장기가 안 열리던 것도 고쳤다. 장기는 engine 을
<script type="text/plain">에 담아 두고(0, eval)(...)로 돌린다.eval(만 찾아보고 "안 쓴다" 고 판단해 CSP 를 조였더니 판이 아예 안 떴다.
되돌리고, 검사도 고쳤다 — 이제 CSP 가 열려 있는지를 실제로 쓰는지와 맞춰 본다. -
갈래마다 자세한 설명을 붙였다
게임 안 [하는 법] 은 두다 말고 잠깐 읽는 것이라 짧다.
처음부터 배우려는 사람에게는 그것으로 모자란다.그래서
/manual/<갈래>/를 갈래마다 하나씩 세웠다. 마디가 아홉에서 열여섯이고,
실제 게임 화면 사진이 마디마다 붙는다. 초등학생이 읽고 바로 앉을 수 있게 썼다.사진은 손으로 찍지 않는다.
deploy/shots.mjs가 크롬을 머리 없이 띄우고
판을 설명하기 좋은 모습으로 만들어 놓은 다음 찍는다. 붙이는 것은 하나도 안 늘렸다 —
노드에 딸려 오는fetch와WebSocket으로 크롬과 이야기한다.- 게임 안 짧은 글과 자세한 설명이 같은 글이면 안 된다. 검사가 그것을 캔다
- 한 문장이 120자를 넘으면 검사가 떨어진다. 길면 안 읽힌다
- 매뉴얼이 부르는 사진이 실제로 있는지도 검사가 본다
-
스파이더를 만들었다
열세 번째. 카드 두 벌로 하고, 같은 무늬로 K 부터 A 까지 세우면 한 벌을 걷는다.
- 1무늬와 2무늬만 낸다. 4무늬는 지금 풀이로 확인이 안 돼서 안 낸다.
확인 못 한 것은 안 내는 것이 이 자리의 약속이다
- 풀이를 좁은 깊이 우선에서 좋은 자리부터 펴는 방식으로 바꿨다.
여덟 판 중 하나를 5.2초 걸려 풀던 것이, 여덟 중 일곱을 0.4초에 푼다
- 조작을 솔리테어·프리셀과 같은 끌기로 맞췄다. 셋이 따로 놀면 안 된다
카드 값이 두 벌이라 겹친다. 그래서 되돌릴 때 어느 장인지 알아보려고
카드마다 이름표를 따로 달았다. 한 벌을 걷을 때 열세 장이 통째로 사라지는데,
줄 번호만 적어 두었더니 되돌리기가 그 열세 장을 삼켰다. -
윷놀이를 만들었다
열두 번째. 우리 것이고 폰에 잘 맞는다.
만들고 나서 AI 승률이 51.7% 밖에 안 나왔다. "윷놀이는 어차피 운" 이라고
접으려던 참에 진짜 까닭이 나왔다 — 말 네 개가 한꺼번에 나가고 있었다.
안 나간 말을 한 덩어리로 세다 보니 대기 중인 말이 전부 같이 움직였다.
고치니 89.3% 가 됐다. 운으로 보이던 것이 사실은 버그였다.- 윷가락을 판 왼쪽에 크게 세웠다. 아래에 작게 눕혀 두었더니 무엇이 나왔는지
한눈에 안 들어왔다
- 한 차례에 던진 것을 다 적어 둔다. 윷·모가 나오면 값이 쌓이는데
윷가락은 마지막 것만 보여 주므로 앞에 뭐가 났는지 사라진다
- 판이 뒤집혀 있던 것도 고쳤다. 자리를
[y,x]로 넣어 두고 화면은[x,y]로 읽었다
-
지뢰찾기를 만들었다
열한 번째. 찍을 일이 없는 판만 낸다.
보통 지뢰찾기는 끝에 가서 반드시 찍어야 하는 자리가 나온다 — 두 자리 중 하나에
지뢰가 있는데 어느 쪽인지 알 길이 없는 자리다. 거기서 지면 억울하다.
여기서는 판을 내기 전에 사람이 쓰는 방법만으로 끝까지 풀리는지 확인한다.
안 풀리면 지뢰를 다시 뿌린다. 어려움(14×20, 55개)도 평균 53번 만에 찾아내고 2ms 걸린다.쓰는 방법은 둘뿐이다. 숫자만큼 깃발이 꽂혔으면 남은 둘레는 안전하고,
남은 가려진 칸이 남은 지뢰 수와 같으면 그것들은 전부 지뢰다.
더 어려운 방법(두 칸을 겹쳐 보기 등)은 일부러 안 쓴다 — 쉬운 방법만으로 풀려야 안 억울하다.- 첫 칸은 늘 안전하다. 그것도 판을 만들 때 정한다 — 눌러 놓고 옮기는 것이 아니라
그 자리와 둘레를 비워 두고 뿌린다. 그래야 첫 수에 넓게 열린다
- 파기와 깃발을 아래에서 바꾼다. 길게 눌러도 깃발이 꽂힌다
- 죽어도 되돌려서 이어 할 수 있다. 어차피 찍을 일이 없는 판이니 다시 보면 보인다
-
노노그램을 만들었다
열 번째. 가장자리 숫자만 보고 그림을 찾아내는 놀이다.
이름을 노노그램으로 둔 이유가 있다. "피크로스" 는 닌텐도 상표다.
리버시와 같은 자리다 — 규칙은 자유롭고 이름은 아닐 수 있다.- 찍을 일이 없는 판만 낸다. 답이 하나뿐인 것만으로는 모자라다.
답이 하나라도 여러 줄을 한꺼번에 따져야 찾아지는 판이 있는데 그건 사람이 못 푼다.
그래서 한 걸음 더 간다 — 줄만 차례로 보아 끝까지 풀리는 판만 내놓는다.
사람이 실제로 푸는 방식이 그것이다- 도움말이 답을 알려 주지 않는다. 지금 아는 것만으로 확실한 칸 하나를 짚고,
왜 그런지(몇 번째 줄만 봐도 안다) 말해 준다. 검사에서 도움말만 따라가도 끝까지 풀린다
- 끌면 여러 칸이 한 번에 칠해진다. 다 풀면 그림을 크게 보여 준다
검사를 쓰다가 세 개가 헛돌았다. 제일 재미있던 것은 대각선이다 —
5×5 대각선은 가로도 세로도 힌트가 전부 [1] 이라 답이 120가지다.
줄만 보고 풀릴 리가 없는데, 나는 그게 풀려야 한다고 검사를 써 놓았다. -
빙고를 만들었다
아홉 번째. 교실에서 하던 그 빙고다.
숫자가 뽑혀 나오는 빙고는 사람이 고를 것이 없다 — 그건 놀이가 아니라 추첨이다.
여기 것은 두 사람이 저마다 판을 채워 두고 번갈아 숫자를 부른다.
그리고 부른 숫자는 두 판에서 같이 지워진다. 그래서 무엇을 부를지가 전부다 —
내 줄을 채우는 숫자가 상대 줄도 채워 주면 안 되기 때문이다.- 두 판을 나란히 보여 준다. 상대 판이 안 보이면 고를 수가 없다
- 도움말을 켜면 내 줄만 채우는 숫자(금색)와 상대 줄도 채우는 숫자(붉은색)를 물들인다
- 남은 숫자가 열둘쯤 되면 상대가 끝까지 다 읽는다. 그때부터는 어림이 아니다
- 이길 줄 수를 1~5줄에서 고른다
검사를 쓰다가 세 개가 헛돌았다. 상대 판을 내 판을 정확히 뒤집어 놓았더니
줄이 통째로 겹쳐서, 5를 부르면 둘이 같이 차서 이기는 게 아니라 비겼다.
AI 가 5를 안 부른 것이 맞는 판단이었다. 겹치지 않는 판을 찾아 쓰도록 고쳤다.숫자 단추가 폰에서 36px 이었다. 아홉 칸으로 나눠 놓아서다 —
칸 수를 박지 말고 최소 크기(44px)를 정해 주고 알아서 접히게 했다. -
오목을 만들었다
여덟 번째. 다섯을 먼저 이으면 이긴다.
- 금수를 지킨다. 흑이 먼저 두는 것이 워낙 유리해서 흑에게만 삼삼과 육목을 막는다.
금수 자리에는 ✕ 가 뜬다. 정통 렌주룰의 사사·복합 금수까지는 안 본다 —
그것까지 넣으면 casual 로 두기가 어려워진다. 화면에 그렇게 적어 두었다- AI 는 급한 것부터 본다. 지금 두면 이기는 자리 → 상대가 이기는 자리 → 그다음에 읽기.
이 차례를 안 지키면 깊이를 아무리 늘려도 코앞의 오목을 놓친다
- 손가락으로는 한 번 짚고 한 번 더 눌러야 놓인다. 열다섯 줄이면 폰에서 한 칸이
24px 이라 그냥은 못 짚는다 (바둑에서 배운 것이다)
두 가지를 고쳤다. 하나는 "첫 수인가" 를 기보 길이로 보던 것 — 판을 꾸며서 시작하면
돌이 놓여 있어도 기보는 비어 있어서, AI 가 코앞의 오목을 놓치고 한가운데만 두었다.
다른 하나는 속도 — 노드마다 금수를 판정하느라 깊이 4가 시간 안에 안 끝났다.검사가 처음에 "깊이가 값을 못 한다" 고 했는데, 재 보니 깊이 4는 깊이 2보다 세지 않았다.
검사는 참인 것을 재야 하므로 실제로 갈리는 자리(깊이 6 대 2)로 옮겼다 — 양쪽에서 다 이긴다. -
리버시를 만들었다
일곱 번째. 한 줄 사이에 낀 상대 돌이 전부 내 것이 되는 놀이다.
이름을 리버시로 둔 이유가 있다. 규칙은 1880년대 영국에서 나온 것이라 임자가 없는데,
1970년대에 붙은 "오델로" 라는 이름은 상표다. 규칙은 자유롭고 이름은 아닐 수 있다 —
테트리스에서 한 번 겪은 그 자리다.- 기기 안에서 도는 AI. 알파–베타로 읽는다. 바둑(끝까지 두어 보기)과 다른 길인데,
리버시는 둘 데가 적고 판을 재는 잣대가 꽤 믿을 만해서 깊이 읽는 편이 세다
- 끝이 가까우면 끝까지 다 읽는다. 남은 칸이 열두어 개면 갈래를 다 볼 수 있고,
그때부터는 어림이 아니라 답이다. 그때 화면이 그렇다고 말해 준다
- 판세 눈금을 달았다. 돌이 많은 쪽이 이기고 있는 게 아니다 —
중반에는 오히려 적은 쪽이 낫다. 뒤집을 자리가 남아 있다는 뜻이기 때문이다.
잣대가 돌 수만 세고 있으면 검사에서 걸리게 해 두었다- 둘이서도 둘 수 있고, 기보를 주소로 나눌 수 있다
AI 에서 진짜 버그를 하나 잡았다. 반복 깊이 루프가 2부터 돌아서, 깊이 1을 달라고 하면
탐색을 아예 안 하고 자리값 1등을 그냥 냈다. 검사가 그걸 "약한 상대" 로 알고 있었던 탓에
한참 헤맸다. 고치고 나니 깊이 8이 깊이 4를 50:14, 59:4 로 이긴다.그 밖에
- 게임 화면의 인라인 스크립트를 읽어 보는 검사를 붙였다. 따옴표 하나만 어긋나도
화면이 통째로 안 뜨는데, 파일은 멀쩡해 보이고 빌드도 그냥 통과한다.
리버시를 만들다 실제로 겪었다 — 눌러 보기 전에는 몰랐다 -
프리셀을 만들었다
여섯 번째. 엎어진 카드가 하나도 없어서 운이 아니라 궁리인 놀이다.
- 판 번호가 다른 프리셀과 같다. 1번 판은 어디서나 1번 판이다.
널리 쓰이는 그 셈법(214013·2531011 을 쓰는 난수)을 그대로 넣고,
알려진 1번 판 일곱 줄과 한 글자도 안 틀리는지 검사로 못 박아 두었다- 11982번은 안 풀린다 — 옛 32000판 중 유일하게 풀리지 않는 판으로 알려져 있다.
우리 것도 끝까지 뒤져서 "없다" 고 답한다. 예산이 모자란 것과 정말 없는 것을 갈라 말한다.
이 검사 하나가 판 번호와 푸는 쪽을 한꺼번에 확인해 준다- 한 번에 몇 장 옮길 수 있는지를 지킨다. (빈칸+1) × 2^(빈 줄) 이다.
못 옮기는 무더기를 집으면 붉게 튕기면서 왜 안 되는지 알려 준다 —
프리셀에서 제일 헷갈리는 자리다- 아직 이길 수 있는지 물어볼 수 있다. 프리셀은 빈칸을 다 채워 놓고 막히는 일이 잦다
- 번호를 적어 열 수 있고, 그 번호가 풀리는 판인지도 미리 봐 준다
푸는 쪽을 한 번 갈아엎었다. 수의 종류로 차례를 매겼더니 200판 중 21판밖에 못 풀었다.
프리셀은 거의 다 풀리는 놀이인데 그러면 안 된다. 수를 두어 보고 나온 판을 재서
좋은 쪽부터 파고들게 바꾸니 192판이 되었다 (평균 93000판 → 6000판, 51초 → 2.7초). -
장기를 사이트 안으로, 배포를 하나로
장기만 목록에서 바깥으로 튀었다. 방 코드 연결과 점수 걸린 판 때문에
Durable Object 가 필요한데 Cloudflare Pages 는 그걸 못 올려서, 장기만 제 워커에
따로 있었기 때문이다.그래서 반대로 했다 — 사이트 전체를 워커 하나로 옮겼다.
- 이제
/g/janggi/다. 목록에서 바깥으로 안 튄다 - 대국 연결(
/peerjs)·점수 걸린 판(/game)·건의함이 사이트와 같은 주소다 - 배포도 하나다:
npm run deploy - 주소가 바뀌었다. 옛 주소로 오면 새 주소로 넘겨준다
머리표(CSP 등)도 워커가 붙인다. Pages 의
_headers에는 함정이 있었다 —
규칙이 여러 개 맞으면 머리표를 다 보내고, CSP 가 두 줄 나가면 브라우저는
둘의 교집합을 쓴다. 워커에서는 한 주소에 한 줄만 고른다.그 밖에
- 첫 화면을 갈래로 나눴다 — 판 놀이 · 카드 · 퍼즐 · 익히기.
열 개가 넘어가면 그냥 늘어놓아서는 무엇이 있는지 한눈에 안 들어온다.
위에 갈래 차림표를 두어 누르면 그 자리로 내려간다.
자바스크립트를 안 썼다 — 자리표(#)와 CSS 만으로 된다- 서비스 워커의 VERSION 을 담을 파일들의 내용에서 뽑는다. 손으로 올리게 두면
반드시 잊는데, 잊으면 티가 안 난다 —
index.html은 그물 먼저라 바로 바뀌지만
engine.js같은 것은 캐시 먼저라 이미 다녀간 사람만 옛 것을 계속 본다 - 이제
-
오프라인이 조용히 깨져 있던 것을 고쳤다
"오프라인에서도 돕니다" 를 재 보다가 찾았다.
서비스 워커는 설치할 때 한 번 파일을 담는다. 그런데 브라우저는 저장소가 모자라거나
한동안 안 들르면 캐시를 말없이 비운다 (사파리는 이레 만에). 그때 워커는 그대로 살아 있어서
설치가 다시 돌지 않는다. 그러면 망이 끊긴 그때서야 안 열리는 걸 알게 된다.- 워커가 설 때마다, 그리고 화면이 열릴 때마다 빠진 것만 다시 채운다. 있는 것은 안 건드린다
- 서비스 워커를 게임마다 베껴 두던 것을 원본 하나(
games/_template/sw.js)로 모았다.
npm run sync:sw로 퍼뜨리고, 갈라지면npm test가 막는다- 담을 파일 목록을 폴더를 훑어서 스스로 채운다. 파일을 새로 만들고 목록에 안 넣어
오프라인에서만 깨지는 일이 없게 — 그게 제일 늦게 들킨다
- 넘겨준(redirect) 응답을 캐시에 넣으려다 조용히 실패하던 것도 걸렀다
-
솔리테어를 만들었다
클론다이크. 다섯 번째 만든 것이다.
- 이길 수 있는 판만 낸다. 판을 내기 전에 끝까지 두어 보고, 풀리는 길이 있는 것만 내놓는다.
스도쿠에서 "답이 하나뿐인 판만" 을 확인하고 냈던 것과 같은 자리다.
판 하나에 5ms 쯤 걸린다 — 평균 두 번쯤 만에 걸린다- 아직 이길 수 있나? 를 물어볼 수 있다. 솔리테어는 어느 순간 이미 진 판이 되는데
보통은 끝까지 두어 봐야 안다. 일꾼(Web Worker)이 대신 두어 보고 알려 준다.
"이길 수 있다 · 이미 졌다 · 모르겠다" 를 갈라 말한다- 끌어서 옮기고, 한 번 누르면 갈 데가 뻔한 곳으로 간다. 되돌리기는 끝까지 된다
- 한 장씩 / 세 장씩, 오늘의 판, 판 나누기(주소), 하던 판 이어 하기
- 검사 55개. 그중 핵심은 둘 — 무작위로 두고 전부 되돌리면 처음 판으로 돌아오는가,
그리고 풀이라고 내놓은 수순을 실제로 두면 정말 이기는가. 말만 믿지 않는다
- 폰에서도 된다. 판에
touch-action:none을 걸어야 손가락으로 끌 수 있다 —
기본값이면 브라우저가 끌기를 화면 넘기기 몸짓으로 보고 들고 있던 카드를 놓아 버린다.
손가락으로 잡으면 카드를 손 위로 띄우고, 떨어뜨릴 자리는 손가락이 아니라 들고 있는 카드로 정한다그 밖에
- 타자 목록 그림이 자리표시자("그림을 그려 넣으세요")인 채로 올라가 있었다. 그려 넣었다
- 타자: 영문을 치는데 자판 그림은 한글(ㅂㅈㄷㄱ…)이었다. 자판을 한 번 그리고 잠가 두어서
한/영을 바꿔도 그대로였다. 이제 치는 말에 맞춰 다시 그린다
- 타자: 말을 골랐다. 스페이스바를 "빈칸" 이라 부르고 있었는데 그건 스도쿠 말이다 —
"스페이스" 로 바꿨다. consistency 를 "고르기" 라 해 두었더니 "연습 고르기" 의
고르기와 뜻이 부딪쳐 더 헷갈렸다 — "일관성" 으로 바꿨다 -
타자·바둑 손보기
- 타자: 조합 중인 글자를 오타로 세던 것을 고쳤다. 한글 IME 는 한 글자를 만드는 동안
"ㅎ" → "하" → "한" 을 차례로 내보내는데, 이걸 목표와 그대로 견주고 있었다.
글자마다 삑 소리가 나고 정확도가 엉망이었다. 이제 조합이 끝난 글자만 판정한다- 타자: 자판 안내가 한참 앞의 옛 오타 자리를 계속 가리키던 것을 고쳤다.
일곱째 글자를 치는 중에 둘째 자리를 밝히면 안내가 아니라 방해다. 지금 칠 자리를 가리킨다
- 타자: 치다가 그만둘 수 있게 했다 (위 막대 · Esc). 중간에 끊은 판은 기록에 넣지 않는다
- 타자: 받침 이주를 제대로 다룬다. "속도는" 을 칠 때 ㄴ 을 누르면 IME 가 그것을
앞 글자의 받침으로 먼저 붙여 "돈" 을 만든다. 그런데 화면은 목표 글자 "도" 를 그대로 두고
있어서, ㄴ 을 이미 눌렀다는 것을 알 수가 없었다. 자판은 다음 자리(ㅡ)를 밝히는데
화면은 아직 ㄴ 을 안 친 것처럼 보이니 안내가 틀린 것처럼 느껴졌다.
이제 친 글자를 그대로 보여 준다 — 화면에 "돈" 이 뜬다.
정확도도 이런 조합 중인 글자를 오타로 세지 않는다 (100% 인데 50% 로 나오던 것)- 타자: 막 시작한 순간 타수가 몇만으로 튀던 것을 막았다
- 타자: 영문 연습을 넣었다. 한/영을 골라 칠 수 있고, 영문은 WPM 으로 잰다
- 바둑: 급수 측정을 위 막대에서 바로 열 수 있게 했다. 두던 판이 있으면 먼저 물어본다
- 바둑: 창이 아주 낮을 때 칸 크기가 음수가 되어 판 그리기가 터지던 것을 고쳤다
- 타자: 커서가 글자에서 밀리던 것을 고쳤다. 원인이 둘이었다.
하나는 줄 번호를 셀 때 줄 높이 자리에 글자 높이(35px)를 넣은 것 — 실제 줄 높이는
65px 이라 줄 번호가 배로 나와 커서가 딴 줄로 갔다.
다른 하나는 창에 보이는 줄 수를 담은ROWS가 자판 그림의ROWS와 이름이 겹친 것 —
var는 끌어올려져서 나중 것이 이기니, 줄 높이가NaN이 되고 커서가 통째로 어긋났다.
오류도 안 나고 화면도 멀쩡해 보여서 눈으로는 찾기 어려웠다- 커서 자리 셈을 엔진으로 옮겨 화면 없이도 검사한다. 전역 이름이 겹치면
npm test가 막는다
-
한글 타자 다시 만듦
처음 만든 판의 화면이 좋지 않아 Monkeytype 소스(GPL — 방식만 배우고 코드는 새로 씀)를
보고 다시 만들었다.- 자판 안내가 조합을 따라간다 — ㅅ → ㅐ → ㅇ 처럼 초성·중성·종성 차례로.
처음 판은 초성만 계속 가리키는 채로 죽어 있었다
- 받침 이주를 안다 — "우물" 을 치면 입력기가 "움" 을 거쳐 간다.
이것을 틀렸다고 표시하던 것을 고쳤다. 겹받침 도중("값" 의 "갑")도 마찬가지
- 틀린 글자는 내가 친 글자가 빨갛게 보인다. 목표 글자가 아니라
- 세 줄 흐름 화면 — 치는 줄이 가운데에 오도록 감긴다
- 재는 방식을 고른다 — 낱말 30·60개, 30·60초, 글 하나
- 치는 동안 둘레가 흐려진다. 고르기(타수가 얼마나 흔들렸나) 값 추가
- 약한 키 찾기를 지수이동평균으로 바꿨다 — 실력이 늘면 점수가 따라 내려온다.
연습문은 표본 스무 개 중 가장 약한 낱말을 고른다
- 산성비 — 떨어지는 낱말을 쳐서 없애는 게임
-
한글 타자
- 자리 연습 9단계(홈 행 → 겹받침), 낱말·짧은 글·긴 글, 내 글 붙여넣기
- 자주 틀리거나 느린 자리를 찾아 그 자리가 많이 나오는 연습문을 만든다
- 타수는 한컴 방식으로 센다 — 초·중·종성 각 1타, 겹받침 2타, 쌍자음은 1타
- 자판 그림이 다음에 누를 자리를 밝힌다. 손가락도 알려 준다
- 실시간 타수 그래프, 지난 기록 그래프
- 붙여넣기를 막았다. 사람이 칠 수 없는 속도는 기록에 넣지 않는다
- 키보드가 없는 화면에서는 연습 대신 안내를 보여 준다
-
검사 자동화와 구조 정리
- 검사 282개. 붙일 것이 0개라
node test/run.mjs면 돈다. 밀어 올릴 때마다 자동으로 돈다 - 장기에 자동 검사가 처음 붙었다 —
index.html안의 엔진 블록을 떼어 검사한다 - 스도쿠 규칙을
engine.js로 떼어 냈다. 이제 네 게임 모두 규칙과 화면이 나뉘어 있다 npm run new:game— 게임 뼈대를 만들고 목록에 붙이고 검사까지 얹는다docs/GAME.md— 게임을 늘릴 때 볼 것. 데어 본 것들을 이유까지 적었다- 효과음을 WebAudio 로 합성한다. 받아 오는 파일이 0바이트다
- 장기: 형세바가 크게 움직이면 소리가 난다. 착수가 막힐 때도 소리를 붙였다
(전에는 진동만 있어서, 소리를 켠 사람에게는 아무 일도 안 일어난 것처럼 보였다)
검사가 버그를 하나 잡았다 — 세로줄(
|)로 시작하는데 표가 아닌 줄이 오면
글 변환기가 제자리걸음에 빠졌다. 그런 글을 한 편 쓰면 빌드가 끝나지 않는다. - 검사 282개. 붙일 것이 0개라
-
바둑
- 9·13·19줄. 따내기·자충수·패·되풀이 금지를 규칙대로 지킨다
- 컴퓨터는 거기서부터 아무렇게나 끝까지 두어 보고 이긴 비율로 수를 고른다(MCTS).
9줄에서 초당 4만 6천 판. 별도 일꾼에서 돌아 화면이 멈추지 않는다
- 판세 눈금 — 지금 누가 얼마나 좋은지
- 지금 계가 — 두 번 쉬기 전에도 "이대로 끝나면 몇 집" 을 보여 준다.
자리마다 임자를 세므로 죽은 돌도 저절로 걸러진다
- 급수 측정 — 이기면 상대가 세지고 지면 약해진다. 이 컴퓨터를 기준으로 한 어림이다
- 기보 나누기(
?g=), 이어서 두기, 오프라인
-
스도쿠
- 답이 하나뿐인 판만 낸다. 한 칸을 뺄 때마다 답이 갈리는지 세어 보고, 갈리면 도로 넣는다
- 난이도는 남긴 숫자 수 + "쉬운 기법만으로 풀리는가" 로 정한다
- 판 나누기(
?p=), 오늘의 문제, 메모, 후보 채우기, 이어 하기, 오프라인 - 한 판 만드는 데 1밀리초
-
검색 준비
robots.txt·sitemap.xml·canonical· 구조화 데이터 · Open Graph- 미리보기 그림을 PNG 로 구웠다. 카카오톡·트위터는 SVG 를 읽지 않는다
- Google Search Console 소유 확인
-
게임 하나를 내림
권리 문제가 걸려 내렸다. 무엇이었고 왜였는지는
docs/STATUS.md의 "지운 것" 에 있다.지우면서 알게 된 것 — Cloudflare 는 지워진 파일의 캐시를 비우지 않는다.
배포본 주소로는 없는데 운영 주소는 옛것을 계속 내주고 있었다. 기본 캐시가 일주일이다.
그래서 지운 자리에 빈 것을 덮어 올려 밀어낸다. -
자리를 옮김
- Cloudflare 에 올렸다
- 올리자마자 게임이 통째로 안 떴다. 보안 머리표(CSP)가 게임의 인라인 코드를 막고 있었다.
Cloudflare 는 맞는 규칙의 머리표를 전부 보내기 때문에, 두 줄이 나가면
브라우저가 둘의 교집합(더 엄한 쪽)을 쓴다. 글 쪽과 게임 쪽에 하나씩만 붙이도록 고쳤다 -
시작
- 만든 것들을 한곳에 모으는 자리를 세웠다. 게임 하나가 폴더 하나다
- 명인 장기를 여기로 옮겼다. 다만 장기는 자기 서버가 따로 있어서
이 자리에 정적으로 복사하지 않는다 — 그러면 온라인 대전이 죽는다