mirror of
https://github.com/MCKero6423/uv-k5-v3-emulator.git
synced 2026-10-07 21:27:30 +00:00
Rounds 91-92: the framebuffer is page-major, and the game draws
Round 91 put the count on the glass instead of in a bar: eleven pixels of n on row 0 and a marker at (0,0). The result was ink 52, marker 0, all bits 0, n = 0 -- draw() leaves the framebuffer empty, and the app's own marker did not appear either. That ruled out the bar's width and pointed at api->fb itself. Reading app_api.h:71 rather than reasoning: 'The framebuffer is the resident gFrameBuffer[FRAME_LINES][128]'. gFrameBuffer is 1024 bytes, eight pages of 128, so fb's first index is the PAGE and the pixel within it is a bit: A->fb[y >> 3][x] |= 1u << (y & 7). The app had been writing fb[y][x] with y up to 63, eight times past the end, and the round 89 change from bit-packed to one byte per pixel moved it from wrong to differently wrong. The frame now arrives and the ASCII reader makes it readable: the game's header, drawn by print_tiny at y=1, in a box from columns 42 to 84. Rows 7 and below are empty and that is correct -- every cell of a fresh game is closed and unflagged, so the 81-cell loop has nothing to paint. Two habits: when a contradictory measurement appears, make the next one unarguable, and when a type is in doubt read the header that defines it -- the answer was two lines above the typedef. Next: press MENU inside the game and watch the field appear.
This commit is contained in:
1 parent
f190892826
commit
b9291c22a6
2 files changed
+89
No files matched your search
@@ -3055,3 +3055,47 @@ wrote minutes ago needs the same scepticism as one written rounds ago.
|
||||
Next measurement, and it is designed to be unarguable: have the app write the count itself into a few bytes of
|
||||
the framebuffer as bits -- 11 bits of n, in known positions -- and read them straight out of the panel hex.
|
||||
No bar, no width, no decode: the number is on the glass or it is not.
|
||||
|
||||
**Rounds 91-92: the framebuffer is page-major, the game draws, and the page now says so.**
|
||||
|
||||
Round 91 settled the contradiction by putting the number on the glass instead of in a bar: the app writes
|
||||
the framebuffer's non-zero byte count as eleven pixels on row 0 and a marker pixel at (0,0), then blits.
|
||||
|
||||
after MENU ink 52, marker pixel 0, all eleven bits 0, n = 0
|
||||
|
||||
n = 0 -- draw() leaves the framebuffer empty -- and the app's own marker did not appear either. That ruled out
|
||||
the bar's width as the explanation and pointed at api->fb itself, so the next thing was to read the API's own
|
||||
documentation rather than reason about it. app_api.h:71 says it in one line:
|
||||
|
||||
/* The framebuffer is the resident gFrameBuffer[FRAME_LINES][128]; the app draws
|
||||
* into it and calls a blit_* to push it to the LCD. */
|
||||
typedef uint8_t (*app_fb_t)[128];
|
||||
|
||||
gFrameBuffer is 1024 bytes, which is eight pages of 128 -- so fb's first index is the PAGE, not the pixel row,
|
||||
and the pixel within a page is a bit:
|
||||
|
||||
A->fb[y >> 3][x] |= (uint8_t)(1u << (y & 7));
|
||||
|
||||
The app had been writing fb[y][x] with y up to 63, eight times past the end of the buffer, and the round 89
|
||||
"fix" from bit-packed to one byte per pixel moved it from wrong to differently wrong. Both helpers are now
|
||||
page-major and the arithmetic is the API's own.
|
||||
|
||||
The frame then arrives, and the ASCII reader makes it readable for the first time -- this is the game's header,
|
||||
drawn by print_tiny at y=1:
|
||||
|
||||
0|...........................................#########################################......
|
||||
1|..........................................##...#.#.#.#.#.#.#.#.######.##..##..###..##.....
|
||||
2|..........................................##.###.#.#.#.#.#.#...#####.#.#.#.#.#.#.####.....
|
||||
6|...........................................#########################################......
|
||||
|
||||
Rows 7 and below are empty, and that is correct rather than a fault: every cell of a fresh game is closed and
|
||||
unflagged, so draw()'s 81-cell loop has nothing to paint. What is on the glass is the title, the counter and the
|
||||
cursor, which is exactly the opening frame of the game.
|
||||
|
||||
Two habits from this round, both already in the file. When a contradictory measurement appears, make the next
|
||||
one unarguable -- eleven pixels of a number cannot be misread as a width. And when a type is in doubt, read the
|
||||
header that defines it and uses it: the answer was in a comment two lines above the typedef, and rounds 89 to 91
|
||||
were spent inferring what the compiler could have been told.
|
||||
|
||||
Next: press MENU inside the running game and watch the field appear, which is the last thing standing between
|
||||
this and playable.
|
||||
@@ -2728,3 +2728,48 @@ boot 485,随后 ink 43,第 2 行读到第 42..84 列、26 个亮 —— 那
|
||||
|
||||
**下一次测量,且它被设计成无可争辩** ✓:**让应用把那个数本身以位的形式写进帧缓冲的几个字节里** ✓ —— **`n` 的 11 个位,放在已知的位置上** ✓ ——
|
||||
**然后直接从面板的十六进制里读回来** ✓。**没有竖条、没有宽度、没有解码:那个数要么在玻璃上,要么不在** ✓。
|
||||
|
||||
**第 91–92 轮:帧缓冲是「页为主」的,游戏在画,而页面第一次说明了这一点。**
|
||||
|
||||
**第 91 轮用「把数字放到玻璃上」而不是「竖条」来终结那个矛盾** ✓:**应用把帧缓冲的非零字节数写成第 0 行上的十一个像素 ✓,并在 (0,0) 写一个标记像素 ✓,然后 blit** ✓。
|
||||
|
||||
```
|
||||
MENU 之后 ink 52,标记像素 0,十一个位全 0,n = 0
|
||||
```
|
||||
|
||||
**`n = 0` —— `draw()` 留下的帧缓冲是空的 ✓ —— 而应用自己的标记也没出现** ✗。
|
||||
**这就排除了「竖条宽度」这个解释 ✓,并把矛头指向 `api->fb` 本身 ✓ —— 所以下一步不是推理,而是去读 API 自己的文档** ✓。
|
||||
**`app_api.h:71` 一行就说清了** ✓:
|
||||
|
||||
```
|
||||
/* The framebuffer is the resident gFrameBuffer[FRAME_LINES][128]; the app draws
|
||||
* into it and calls a blit_* to push it to the LCD. */
|
||||
typedef uint8_t (*app_fb_t)[128];
|
||||
```
|
||||
|
||||
**`gFrameBuffer` 是 1024 字节 = 8 个页 × 128 ✓ —— 所以 `fb` 的第一个下标是「页」而不是「像素行」✓,
|
||||
页内的像素是一个位** ✓:
|
||||
|
||||
```
|
||||
A->fb[y >> 3][x] |= (uint8_t)(1u << (y & 7));
|
||||
```
|
||||
|
||||
**应用此前一直写 `fb[y][x]`、`y` 到 63 ✓ —— 越出缓冲末尾八倍** ✗;**而第 89 轮那次「从按位打包改成一字节一像素」的「修法」,只是把它从错的一种改成了错的另一种** ✗✓。
|
||||
**两个辅助函数现在都是页为主 ✓,算术就是 API 自己的** ✓。
|
||||
|
||||
**画面随之出现 ✓,而 ASCII 读法第一次让它可读** ✓ —— **下面是 `print_tiny` 在 y=1 画的表头** ✓:
|
||||
|
||||
```
|
||||
0|...........................................#########################################......
|
||||
1|..........................................##...#.#.#.#.#.#.#.#.######.##..##..###..##.....
|
||||
2|..........................................##.###.#.#.#.#.#.#...#####.#.#.#.#.#.#.####.....
|
||||
6|...........................................#########################################......
|
||||
```
|
||||
|
||||
**第 7 行往下是空的 ✓,而这是对的、不是故障** ✓:**新开一局的每个格子都未翻开、未插旗 ✓,`draw()` 的 81 格循环本来就无可画** ✓。
|
||||
**玻璃上的是标题、计数器与光标 ✓ —— 那正是游戏的开局画面** ✓✓。
|
||||
|
||||
**这一轮留下两条习惯,本文件其实都已有别的说法** ✓。**当出现互相矛盾的测量时,让**下一次**测量无可争辩** ✓ —— **一个数的十一个像素不可能被误读成宽度** ✓。
|
||||
**而当类型存疑时,去读定义并使用它的那个头文件** ✓:**答案就在 typedef 上方两行的注释里 ✓,而第 89 至 91 轮花在了推测编译器本可以告知的事情上** ✓✓。
|
||||
|
||||
**下一步:在运行中的游戏里按 MENU,看雷区长出来** ✓ —— **那是挡在「可玩」前面的最后一件东西** ✓✓。
|
||||
Reference in new issue
Block a user