{
"id": "296",
"prompt": "A PIN lock screen in three phases: SET (type 4 digits on a 3x4 keypad - 1 through 9, CLR, 0, OK - and OK stores the pin), LOCKED (same keypad, OK compares against the stored pin, a wrong code flashes a red strip and bumps a FAILS counter), and UNLOCKED (a LOCK button re-arms it). Entered digits render as * so the code stays masked; entry value, entry length, the pin, the phase and the fail count all persist in state slots.",
"solution_rl": "fn frame(t: i32) {\n host::display::clear(0x0d0e12);\n let down: i32 = host::display::pointer_down();\n let prev: i32 = host::display::state_get(0);\n host::display::state_set(0, down);\n let mut click: i32 = 0;\n if down == 1 && prev == 0 {\n click = 1;\n }\n let phase: i32 = host::display::state_get(1);\n let len: i32 = host::display::state_get(3);\n\n if phase == 0 {\n host::display::draw_string(180, 40, \"SET A PIN\", 0xffffff, 2);\n } else if phase == 1 {\n host::display::draw_string(176, 40, \"ENTER PIN\", 0xffffff, 2);\n } else {\n host::display::draw_string(170, 40, \"UNLOCKED\", 0x33ff88, 2);\n }\n\n if phase == 2 {\n host::display::fill_rect(60, 130, 392, 60, 0x152a1a);\n host::display::draw_string(120, 150, \"THE VAULT IS OPEN\", 0x99ffbb, 2);\n host::display::fill_rect(186, 260, 140, 60, 0xdddddd);\n host::display::draw_string(220, 280, \"LOCK\", 0x000000, 2);\n if click == 1 {\n let px: i32 = host::display::pointer_x();\n let py: i32 = host::display::pointer_y();\n if px >= 186 && px < 326 && py >= 260 && py < 320 {\n host::display::state_set(1, 1);\n host::display::state_set(2, 0);\n host::display::state_set(3, 0);\n }\n }\n } else {\n let mut i: i32 = 0;\n while i < len {\n host::display::draw_char(200 + i * 30, 90, 42, 0xffffff, 3);\n i = i + 1;\n }\n let flash: i32 = host::display::state_get(5);\n if flash > 0 {\n host::display::fill_rect(0, 0, 512, 6, 0xbb2222);\n host::display::draw_string(320, 460, \"WRONG PIN\", 0xbb3333, 1);\n host::display::state_set(5, flash - 1);\n }\n host::display::draw_string(60, 460, \"FAILS\", 0x556677, 1);\n host::display::draw_number(110, 458, host::display::state_get(6), 0xffffff, 1);\n\n let mut k: i32 = 0;\n while k < 12 {\n let kx: i32 = 166 + (k % 3) * 62;\n let ky: i32 = 150 + (k / 3) * 62;\n host::display::fill_rect(kx, ky, 56, 56, 0x1f242e);\n if k < 9 {\n host::display::draw_number(kx + 24, ky + 20, k + 1, 0xffffff, 2);\n } else if k == 9 {\n host::display::draw_char(kx + 24, ky + 20, 67, 0xbb5533, 2);\n } else if k == 10 {\n host::display::draw_number(kx + 24, ky + 20, 0, 0xffffff, 2);\n } else {\n host::display::draw_char(kx + 24, ky + 20, 62, 0x33ff88, 2);\n }\n k = k + 1;\n }\n\n if click == 1 {\n let px2: i32 = host::display::pointer_x();\n let py2: i32 = host::display::pointer_y();\n if px2 >= 166 && px2 < 352 && py2 >= 150 && py2 < 398 {\n let kc: i32 = (px2 - 166) / 62;\n let kr: i32 = (py2 - 150) / 62;\n if kc < 3 && kr < 4 {\n let key: i32 = kr * 3 + kc;\n let entry: i32 = host::display::state_get(2);\n if key < 9 && len < 4 {\n host::display::state_set(2, entry * 10 + key + 1);\n host::display::state_set(3, len + 1);\n } else if key == 10 && len < 4 {\n host::display::state_set(2, entry * 10);\n host::display::state_set(3, len + 1);\n } else if key == 9 {\n host::display::state_set(2, 0);\n host::display::state_set(3, 0);\n } else if key == 11 && len == 4 {\n if phase == 0 {\n host::display::state_set(4, entry);\n host::display::state_set(1, 1);\n } else if entry == host::display::state_get(4) {\n host::display::state_set(1, 2);\n } else {\n host::display::state_set(6, host::display::state_get(6) + 1);\n host::display::state_set(5, 24);\n }\n host::display::state_set(2, 0);\n host::display::state_set(3, 0);\n }\n }\n }\n }\n }\n host::display::present();\n}\n",
"tags": [
"app",
"state-machine",
"keypad"
]
}