chore(js): polish pong keys, held mapping and m09 main test

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
Lucas Winther
2026-10-29 00:02:23 +01:00
co-authored by Claude Sonnet 5.5
parent 3146bb630a
commit 59bece5443
10 changed files with 209 additions and 16 deletions
+3 -3
View File
@@ -8,14 +8,14 @@ import { keyDowns, keyUps, interval, map, filterMap, merge, scan, startWith } fr
export const FRAME_MS_PONG = 30
const keys = {
ArrowUp: 'Up', w: 'Up',
ArrowDown: 'Down', s: 'Down',
ArrowUp: 'Up', w: 'Up', W: 'Up',
ArrowDown: 'Down', s: 'Down', S: 'Down',
}
// hasOwn, not `key in keys`: "constructor" and "toString" are inherited, not keys we mapped.
export const pongKey = (isDown, key) =>
Object.hasOwn(keys, key) ? (isDown ? PongAction.Press : PongAction.Release)(keys[key])
: key === 'r' && isDown ? PongAction.Restart
: (key === 'r' || key === 'R') && isDown ? PongAction.Restart
: null
export const pongActions = merge(
+8 -2
View File
@@ -56,10 +56,16 @@ const frame = (state) => {
return scorer === null ? next : serve(next, scorer)
}
// Only the keys the model knows ('Up', 'Down') are held; anything else leaves the state alone.
const heldFlag = { Up: 'up', Down: 'down' }
const setHeld = (state, key, value) =>
Object.hasOwn(heldFlag, key) ? { ...state, held: { ...state.held, [heldFlag[key]]: value } } : state
export const pongUpdate = (state, action) => {
switch (action.tag) {
case 'Press': return { ...state, held: { ...state.held, [action.key.toLowerCase()]: true } }
case 'Release': return { ...state, held: { ...state.held, [action.key.toLowerCase()]: false } }
case 'Press': return setHeld(state, action.key, true)
case 'Release': return setHeld(state, action.key, false)
case 'Restart': return initialPong(state.seed)
case 'Frame': return frame(state)
default: return state