loop-benchmarking

Controlled experiments across agentic coding configurations. Same task, one variable, what actually works.
git clone https://git.shiptheloop.com/loop-benchmarking.git
Log | Files | Refs | README

commit 626a12905a15dc3abd353945cc6a774083a19f2f
parent 57b74f96d1ff52223531c72a77bb145a43f51272
Author: Brian Graham <brian@buildingbetterteams.de>
Date:   Mon,  6 Apr 2026 10:07:57 +0200

Fix artifacts: dist/ was globally gitignored, breaking compiled games

The global dist/ in .gitignore was blocking artifacts/*/dist/ directories.
Many games compile TypeScript to dist/main.js - these were missing from
git and therefore missing from deploy. Changed to dashboard/dist/ so only
the Astro build output is ignored, not game artifacts.

267 previously-ignored dist files now tracked.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Diffstat:
M.gitignore | 2+-
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=javascript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/.scannerwork/.sonar_lock | 0
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=javascript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/.scannerwork/report-task.txt | 6++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.d.ts | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.d.ts.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js | 413+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 487+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 357+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 627+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 509+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 667+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 542+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/game.d.ts | 26++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/game.js | 226+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/index.d.ts | 1+
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/index.js | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/renderer.d.ts | 17+++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/renderer.js | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.js | 595+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/types.d.ts | 42++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/types.js | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/ui.d.ts | 24++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/ui.js | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 412+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 354+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 492+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 567+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 564+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js | 376+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 429+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js | 479+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 407+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.d.ts | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.d.ts.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.js | 380+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/board.d.ts | 16++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/board.d.ts.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/board.js | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/board.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/bundle.js | 563+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/game.d.ts | 24++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/game.d.ts.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/game.js | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/game.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/main.d.ts | 3+++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/main.d.ts.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/main.js | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/main.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/piece.d.ts | 8++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/piece.d.ts.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/piece.js | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/piece.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/renderer.d.ts | 25+++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/renderer.d.ts.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/renderer.js | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/renderer.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/types.d.ts | 44++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/types.d.ts.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/types.js | 13+++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/types.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/game.d.ts | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/game.d.ts.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/game.js | 463+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/game.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/index.html | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/styles.css | 210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js | 383+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/tetris.js | 362+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts | 32++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js | 287+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/input.d.ts | 10++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/input.js | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/input.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.d.ts | 1+
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js | 42++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.d.ts | 4++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.js | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.d.ts | 13+++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.js | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/types.d.ts | 19+++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/types.js | 5+++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/types.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js | 413+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 367+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 551+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 558+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=detailed_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 444+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 570+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 595+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 441+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 599+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 565+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 562+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 508+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/board.js | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/board.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js | 263+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/main.js | 12++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/main.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/pieces.js | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/pieces.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/renderer.js | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/renderer.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/types.js | 6++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/types.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 596+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 541+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 603+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 483+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run1/dist/tetris.js | 449+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run1/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run2/dist/tetris.js | 612+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/dist/tetris.js | 560+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/tetris.js | 351+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run2/dist/tetris.js | 416+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/tetris.js | 578++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js | 597+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/game.d.ts | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/game.js | 580+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/game.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run3/dist/tetris.js | 431+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run3/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 614+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 483+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 474+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 439+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 680+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js | 599+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=detailed_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 547+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 530+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 630+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js | 538+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 375+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 443+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 596+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 429+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 566+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 430+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 463+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 463+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 553+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run1/dist/tetris.js | 463+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run2/dist/tetris.js | 646+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/dist/tetris.js | 532+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/tetris.js | 440+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/tetris.js | 583+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js | 763+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/tetris.js | 627+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run3/dist/tetris.js | 606+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 524+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 577+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 439+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 584+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.d.ts | 30++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 620+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js | 660+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js.map | 7+++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 608+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 564+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts.map | 2++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js | 405+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js.map | 2++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 707+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/board.js | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/board.js.map | 2++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js | 290+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js.map | 2++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/main.js | 20++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/main.js.map | 2++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/pieces.js | 222+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/pieces.js.map | 2++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/renderer.js | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/renderer.js.map | 2++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/types.js | 4++++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/types.js.map | 2++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 510+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 406+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 479+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 641+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 395+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js | 374+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.d.ts | 38++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.d.ts.map | 2++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 404+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map | 2++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/bundle.js | 473+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts.map | 2++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js | 217+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js.map | 2++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/main.d.ts | 3+++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/main.d.ts.map | 2++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/main.js | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/main.js.map | 2++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/renderer.d.ts | 29+++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/renderer.d.ts.map | 2++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/renderer.js | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/renderer.js.map | 2++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/board.js | 46++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/board.js.map | 2++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js | 355+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js.map | 2++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js | 21+++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js.map | 2++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.js | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.js.map | 2++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.js | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.js.map | 2++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 486+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/bundle.js | 711+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/bundle.js.map | 7+++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js | 613+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js | 496+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aartifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js | 658+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
270 files changed, 56036 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore @@ -1,5 +1,5 @@ node_modules/ -dist/ +dashboard/dist/ .astro/ results/runs/*/workspace.tar.gz __pycache__/ diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=javascript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/.scannerwork/.sonar_lock b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=javascript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/.scannerwork/.sonar_lock diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=javascript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/.scannerwork/report-task.txt b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=javascript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/.scannerwork/report-task.txt @@ -0,0 +1,6 @@ +projectKey=tetris-test-run1 +serverUrl=http://localhost:9000 +serverVersion=25.5.0.107428 +dashboardUrl=http://localhost:9000/dashboard?id=tetris-test-run1 +ceTaskId=07305ac1-c81d-43e9-a9ee-f264f9370aaf +ceTaskUrl=http://localhost:9000/api/ce/task?id=07305ac1-c81d-43e9-a9ee-f264f9370aaf diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.d.ts @@ -0,0 +1,50 @@ +declare const COLS = 10; +declare const ROWS = 20; +declare const BLOCK_SIZE = 30; +declare const COLORS: string[]; +declare const TETROMINOES: number[][][]; +interface Piece { + x: number; + y: number; + type: number; + rotation: number; +} +declare class TetrisGame { + private canvas; + private ctx; + private board; + private currentPiece; + private nextPiece; + private gameRunning; + private gamePaused; + private score; + private level; + private lines; + private dropCounter; + private dropInterval; + private lastTime; + private nextCanvas; + private nextCtx; + constructor(); + private initBoard; + private setupEventListeners; + private handleKeyDown; + private startGame; + private togglePause; + private restartGame; + private createPiece; + private movePiece; + private dropPiece; + private rotatePiece; + private collision; + private placePiece; + private clearLines; + private getRotatedShape; + private drawBoard; + private drawBlock; + private drawNextPiece; + private updateUI; + private endGame; + private gameLoop; +} +//# sourceMappingURL=tetris.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.d.ts.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.d.ts","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"AACA,QAAA,MAAM,IAAI,KAAK,CAAC;AAChB,QAAA,MAAM,IAAI,KAAK,CAAC;AAChB,QAAA,MAAM,UAAU,KAAK,CAAC;AACtB,QAAA,MAAM,MAAM,UAQX,CAAC;AAGF,QAAA,MAAM,WAAW,cAkDhB,CAAC;AAEF,UAAU,KAAK;IACX,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,cAAM,UAAU;IACZ,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,GAAG,CAA2B;IACtC,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,OAAO,CAA2B;;IAa1C,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,SAAS;IAuBjB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,SAAS;IAajB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,SAAS;IAyBjB,OAAO,CAAC,UAAU;IA6BlB,OAAO,CAAC,UAAU;IAiClB,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,SAAS;IAmDjB,OAAO,CAAC,SAAS;IAoBjB,OAAO,CAAC,aAAa;IA8BrB,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,OAAO;IAgBf,OAAO,CAAC,QAAQ;CAqBnB"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js @@ -0,0 +1,412 @@ +"use strict"; +// Game constants +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 30; +const COLORS = [ + '#FF0000', // I - Red + '#FFD700', // O - Yellow + '#00FFFF', // T - Cyan + '#00FF00', // S - Green + '#FF00FF', // Z - Magenta + '#0000FF', // J - Blue + '#FFA500', // L - Orange +]; +// Tetromino shapes (4x4 grids) +const TETROMINOES = [ + // I + [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + // O + [ + [1, 1, 0, 0], + [1, 1, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + // T + [ + [0, 1, 0, 0], + [1, 1, 1, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + // S + [ + [0, 1, 1, 0], + [1, 1, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + // Z + [ + [1, 1, 0, 0], + [0, 1, 1, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + // J + [ + [1, 0, 0, 0], + [1, 1, 1, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + // L + [ + [0, 0, 1, 0], + [1, 1, 1, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], +]; +class TetrisGame { + constructor() { + this.board = []; + this.currentPiece = null; + this.nextPiece = null; + this.gameRunning = false; + this.gamePaused = false; + this.score = 0; + this.level = 1; + this.lines = 0; + this.dropCounter = 0; + this.dropInterval = 1000; + this.lastTime = 0; + this.canvas = document.getElementById('gameBoard'); + this.ctx = this.canvas.getContext('2d'); + this.nextCanvas = document.getElementById('nextPiece'); + this.nextCtx = this.nextCanvas.getContext('2d'); + this.initBoard(); + this.setupEventListeners(); + this.drawBoard(); + } + initBoard() { + this.board = []; + for (let y = 0; y < ROWS; y++) { + this.board[y] = new Array(COLS).fill(0); + } + } + setupEventListeners() { + document.addEventListener('keydown', (e) => this.handleKeyDown(e)); + document.getElementById('startBtn').addEventListener('click', () => this.startGame()); + document.getElementById('pauseBtn').addEventListener('click', () => this.togglePause()); + document.getElementById('restartBtn').addEventListener('click', () => this.restartGame()); + } + handleKeyDown(e) { + if (!this.gameRunning || this.gamePaused) + return; + switch (e.key.toLowerCase()) { + case 'arrowleft': + e.preventDefault(); + this.movePiece(-1); + break; + case 'arrowright': + e.preventDefault(); + this.movePiece(1); + break; + case 'arrowdown': + e.preventDefault(); + this.dropPiece(); + break; + case ' ': + e.preventDefault(); + this.rotatePiece(); + break; + case 'p': + e.preventDefault(); + this.togglePause(); + break; + } + } + startGame() { + if (this.gameRunning) + return; + this.gameRunning = true; + this.gamePaused = false; + this.score = 0; + this.level = 1; + this.lines = 0; + this.dropInterval = 1000; + this.initBoard(); + const startBtn = document.getElementById('startBtn'); + const pauseBtn = document.getElementById('pauseBtn'); + startBtn.disabled = true; + pauseBtn.disabled = false; + this.currentPiece = this.createPiece(); + this.nextPiece = this.createPiece(); + this.drawNextPiece(); + this.updateUI(); + this.gameLoop(0); + } + togglePause() { + if (!this.gameRunning) + return; + this.gamePaused = !this.gamePaused; + } + restartGame() { + this.gameRunning = false; + this.gamePaused = false; + const startBtn = document.getElementById('startBtn'); + const pauseBtn = document.getElementById('pauseBtn'); + startBtn.disabled = false; + pauseBtn.disabled = true; + document.getElementById('gameOverScreen').classList.add('hidden'); + this.initBoard(); + this.drawBoard(); + } + createPiece() { + const type = Math.floor(Math.random() * TETROMINOES.length); + return { + x: Math.floor(COLS / 2) - 2, + y: 0, + type, + rotation: 0, + }; + } + movePiece(direction) { + if (!this.currentPiece) + return; + this.currentPiece.x += direction; + if (this.collision()) { + this.currentPiece.x -= direction; + } + this.drawBoard(); + } + dropPiece() { + if (!this.currentPiece) + return; + this.currentPiece.y++; + if (this.collision()) { + this.currentPiece.y--; + this.placePiece(); + } + this.drawBoard(); + } + rotatePiece() { + if (!this.currentPiece) + return; + const oldRotation = this.currentPiece.rotation; + this.currentPiece.rotation = (this.currentPiece.rotation + 1) % 4; + if (this.collision()) { + this.currentPiece.rotation = oldRotation; + } + this.drawBoard(); + } + collision() { + if (!this.currentPiece) + return false; + const shape = this.getRotatedShape(this.currentPiece.type, this.currentPiece.rotation); + for (let row = 0; row < 4; row++) { + for (let col = 0; col < 4; col++) { + if (!shape[row][col]) + continue; + const x = this.currentPiece.x + col; + const y = this.currentPiece.y + row; + if (x < 0 || x >= COLS || y >= ROWS) { + return true; + } + if (y >= 0 && this.board[y][x]) { + return true; + } + } + } + return false; + } + placePiece() { + if (!this.currentPiece) + return; + const shape = this.getRotatedShape(this.currentPiece.type, this.currentPiece.rotation); + const colorIndex = this.currentPiece.type; + for (let row = 0; row < 4; row++) { + for (let col = 0; col < 4; col++) { + if (!shape[row][col]) + continue; + const x = this.currentPiece.x + col; + const y = this.currentPiece.y + row; + if (y >= 0 && y < ROWS && x >= 0 && x < COLS) { + this.board[y][x] = colorIndex + 1; + } + } + } + this.clearLines(); + this.currentPiece = this.nextPiece; + this.nextPiece = this.createPiece(); + this.drawNextPiece(); + if (this.collision()) { + this.endGame(); + } + } + clearLines() { + const linesToClear = []; + for (let y = ROWS - 1; y >= 0; y--) { + if (this.board[y].every((cell) => cell !== 0)) { + linesToClear.push(y); + } + } + if (linesToClear.length === 0) + return; + // Remove cleared lines + for (let i = linesToClear.length - 1; i >= 0; i--) { + this.board.splice(linesToClear[i], 1); + this.board.unshift(new Array(COLS).fill(0)); + } + // Update score + const multiplier = [40, 100, 300, 1200]; + const points = multiplier[linesToClear.length - 1] || 0; + this.score += points * this.level; + this.lines += linesToClear.length; + // Update level + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel > this.level) { + this.level = newLevel; + this.dropInterval = Math.max(100, 1000 - (this.level - 1) * 100); + } + this.updateUI(); + } + getRotatedShape(type, rotation) { + const shape = JSON.parse(JSON.stringify(TETROMINOES[type])); + for (let i = 0; i < rotation; i++) { + // Rotate 90 degrees clockwise + const rotated = [ + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ]; + for (let row = 0; row < 4; row++) { + for (let col = 0; col < 4; col++) { + rotated[col][3 - row] = shape[row][col]; + } + } + shape.splice(0, 4, ...rotated); + } + return shape; + } + drawBoard() { + // Clear canvas + this.ctx.fillStyle = '#1a1a1a'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid + this.ctx.strokeStyle = '#333'; + this.ctx.lineWidth = 0.5; + for (let x = 0; x <= COLS; x++) { + this.ctx.beginPath(); + this.ctx.moveTo(x * BLOCK_SIZE, 0); + this.ctx.lineTo(x * BLOCK_SIZE, ROWS * BLOCK_SIZE); + this.ctx.stroke(); + } + for (let y = 0; y <= ROWS; y++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, y * BLOCK_SIZE); + this.ctx.lineTo(COLS * BLOCK_SIZE, y * BLOCK_SIZE); + this.ctx.stroke(); + } + // Draw placed blocks + for (let y = 0; y < ROWS; y++) { + for (let x = 0; x < COLS; x++) { + if (this.board[y][x]) { + this.drawBlock(x, y, this.board[y][x] - 1); + } + } + } + // Draw current piece + if (this.currentPiece) { + const shape = this.getRotatedShape(this.currentPiece.type, this.currentPiece.rotation); + for (let row = 0; row < 4; row++) { + for (let col = 0; col < 4; col++) { + if (!shape[row][col]) + continue; + const x = this.currentPiece.x + col; + const y = this.currentPiece.y + row; + if (y >= 0) { + this.drawBlock(x, y, this.currentPiece.type); + } + } + } + } + } + drawBlock(x, y, colorIndex) { + const color = COLORS[colorIndex]; + const px = x * BLOCK_SIZE; + const py = y * BLOCK_SIZE; + // Main block + this.ctx.fillStyle = color; + this.ctx.fillRect(px + 1, py + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + // Highlight + this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)'; + this.ctx.lineWidth = 2; + this.ctx.strokeRect(px + 2, py + 2, BLOCK_SIZE - 4, BLOCK_SIZE - 4); + // Shadow + this.ctx.strokeStyle = 'rgba(0, 0, 0, 0.3)'; + this.ctx.lineWidth = 1; + this.ctx.strokeRect(px + 1, py + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + } + drawNextPiece() { + const canvas = this.nextCanvas; + const ctx = this.nextCtx; + ctx.fillStyle = '#f9f9f9'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + if (!this.nextPiece) + return; + const shape = TETROMINOES[this.nextPiece.type]; + const blockSize = canvas.width / 4; + const color = COLORS[this.nextPiece.type]; + for (let row = 0; row < 4; row++) { + for (let col = 0; col < 4; col++) { + if (!shape[row][col]) + continue; + const x = col * blockSize; + const y = row * blockSize; + ctx.fillStyle = color; + ctx.fillRect(x, y, blockSize - 1, blockSize - 1); + ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)'; + ctx.lineWidth = 1; + ctx.strokeRect(x, y, blockSize - 1, blockSize - 1); + } + } + } + updateUI() { + document.getElementById('score').textContent = this.score.toString(); + document.getElementById('level').textContent = this.level.toString(); + document.getElementById('lines').textContent = this.lines.toString(); + } + endGame() { + this.gameRunning = false; + document.getElementById('finalScore').textContent = this.score.toString(); + document.getElementById('finalLevel').textContent = this.level.toString(); + document.getElementById('finalLines').textContent = this.lines.toString(); + const gameOverScreen = document.getElementById('gameOverScreen'); + gameOverScreen.classList.remove('hidden'); + const startBtn = document.getElementById('startBtn'); + const pauseBtn = document.getElementById('pauseBtn'); + startBtn.disabled = false; + pauseBtn.disabled = true; + } + gameLoop(currentTime) { + if (!this.gameRunning) + return; + if (this.lastTime === 0) { + this.lastTime = currentTime; + } + const deltaTime = currentTime - this.lastTime; + this.lastTime = currentTime; + if (!this.gamePaused) { + this.dropCounter += deltaTime; + if (this.dropCounter > this.dropInterval) { + this.dropCounter = 0; + this.dropPiece(); + } + } + requestAnimationFrame((time) => this.gameLoop(time)); + } +} +// Initialize game when DOM is ready +document.addEventListener('DOMContentLoaded', () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":";AAAA,iBAAiB;AACjB,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,UAAU,GAAG,EAAE,CAAC;AACtB,MAAM,MAAM,GAAG;IACX,SAAS,EAAE,UAAU;IACrB,SAAS,EAAE,aAAa;IACxB,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,YAAY;IACvB,SAAS,EAAE,cAAc;IACzB,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,aAAa;CAC3B,CAAC;AAEF,+BAA+B;AAC/B,MAAM,WAAW,GAAG;IAChB,IAAI;IACJ;QACI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;KACf;IACD,IAAI;IACJ;QACI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;KACf;IACD,IAAI;IACJ;QACI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;KACf;IACD,IAAI;IACJ;QACI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;KACf;IACD,IAAI;IACJ;QACI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;KACf;IACD,IAAI;IACJ;QACI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;KACf;IACD,IAAI;IACJ;QACI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;KACf;CACJ,CAAC;AASF,MAAM,UAAU;IAiBZ;QAdQ,UAAK,GAAe,EAAE,CAAC;QACvB,iBAAY,GAAiB,IAAI,CAAC;QAClC,cAAS,GAAiB,IAAI,CAAC;QAC/B,gBAAW,GAAG,KAAK,CAAC;QACpB,eAAU,GAAG,KAAK,CAAC;QACnB,UAAK,GAAG,CAAC,CAAC;QACV,UAAK,GAAG,CAAC,CAAC;QACV,UAAK,GAAG,CAAC,CAAC;QACV,gBAAW,GAAG,CAAC,CAAC;QAChB,iBAAY,GAAG,IAAI,CAAC;QACpB,aAAQ,GAAG,CAAC,CAAC;QAKjB,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAsB,CAAC;QACxE,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;QACzC,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAsB,CAAC;QAC5E,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;QAEjD,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,SAAS,EAAE,CAAC;IACrB,CAAC;IAEO,SAAS;QACb,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5C,CAAC;IACL,CAAC;IAEO,mBAAmB;QACvB,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QACvF,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACzF,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAC/F,CAAC;IAEO,aAAa,CAAC,CAAgB;QAClC,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO;QAEjD,QAAQ,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;YAC1B,KAAK,WAAW;gBACZ,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;gBACnB,MAAM;YACV,KAAK,YAAY;gBACb,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBAClB,MAAM;YACV,KAAK,WAAW;gBACZ,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,IAAI,CAAC,SAAS,EAAE,CAAC;gBACjB,MAAM;YACV,KAAK,GAAG;gBACJ,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,IAAI,CAAC,WAAW,EAAE,CAAC;gBACnB,MAAM;YACV,KAAK,GAAG;gBACJ,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,IAAI,CAAC,WAAW,EAAE,CAAC;gBACnB,MAAM;QACd,CAAC;IACL,CAAC;IAEO,SAAS;QACb,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO;QAE7B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,SAAS,EAAE,CAAC;QAEjB,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAC1E,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAC1E,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;QACzB,QAAQ,CAAC,QAAQ,GAAG,KAAK,CAAC;QAE1B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACvC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACpC,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IAEO,WAAW;QACf,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAC9B,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;IACvC,CAAC;IAEO,WAAW;QACf,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAC1E,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAC1E,QAAQ,CAAC,QAAQ,GAAG,KAAK,CAAC;QAC1B,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;QAEzB,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAE,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACnE,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,SAAS,EAAE,CAAC;IACrB,CAAC;IAEO,WAAW;QACf,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QAC5D,OAAO;YACH,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC;YAC3B,CAAC,EAAE,CAAC;YACJ,IAAI;YACJ,QAAQ,EAAE,CAAC;SACd,CAAC;IACN,CAAC;IAEO,SAAS,CAAC,SAAiB;QAC/B,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAE/B,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,SAAS,CAAC;QAEjC,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YACnB,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,SAAS,CAAC;QACrC,CAAC;QAED,IAAI,CAAC,SAAS,EAAE,CAAC;IACrB,CAAC;IAEO,SAAS;QACb,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAE/B,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QAEtB,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YACnB,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,UAAU,EAAE,CAAC;QACtB,CAAC;QAED,IAAI,CAAC,SAAS,EAAE,CAAC;IACrB,CAAC;IAEO,WAAW;QACf,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAE/B,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC;QAC/C,IAAI,CAAC,YAAY,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QAElE,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YACnB,IAAI,CAAC,YAAY,CAAC,QAAQ,GAAG,WAAW,CAAC;QAC7C,CAAC;QAED,IAAI,CAAC,SAAS,EAAE,CAAC;IACrB,CAAC;IAEO,SAAS;QACb,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO,KAAK,CAAC;QAErC,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAEvF,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;YAC/B,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;gBAC/B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;oBAAE,SAAS;gBAE/B,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,GAAG,CAAC;gBACpC,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,GAAG,CAAC;gBAEpC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;oBAClC,OAAO,IAAI,CAAC;gBAChB,CAAC;gBAED,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC7B,OAAO,IAAI,CAAC;gBAChB,CAAC;YACL,CAAC;QACL,CAAC;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;IAEO,UAAU;QACd,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAE/B,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QACvF,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;QAE1C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;YAC/B,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;gBAC/B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;oBAAE,SAAS;gBAE/B,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,GAAG,CAAC;gBACpC,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,GAAG,CAAC;gBAEpC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC;oBAC3C,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,GAAG,CAAC,CAAC;gBACtC,CAAC;YACL,CAAC;QACL,CAAC;QAED,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACpC,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YACnB,IAAI,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC;IACL,CAAC;IAEO,UAAU;QACd,MAAM,YAAY,GAAa,EAAE,CAAC;QAElC,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACjC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC5C,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACzB,CAAC;QACL,CAAC;QAED,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEtC,uBAAuB;QACvB,KAAK,IAAI,CAAC,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAChD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACtC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,CAAC;QAED,eAAe;QACf,MAAM,UAAU,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,UAAU,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,CAAC,KAAK,IAAI,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC;QAClC,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC,MAAM,CAAC;QAElC,eAAe;QACf,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;QACjD,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;YACtB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QACrE,CAAC;QAED,IAAI,CAAC,QAAQ,EAAE,CAAC;IACpB,CAAC;IAEO,eAAe,CAAC,IAAY,EAAE,QAAgB;QAClD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAE5D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;YAChC,8BAA8B;YAC9B,MAAM,OAAO,GAAe;gBACxB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;aACf,CAAC;YAEF,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;gBAC/B,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;oBAC/B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;gBAC5C,CAAC;YACL,CAAC;YAED,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC;QACnC,CAAC;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;IAEO,SAAS;QACb,eAAe;QACf,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAE/D,YAAY;QACZ,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC;QAEzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC;YACnC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,EAAE,IAAI,GAAG,UAAU,CAAC,CAAC;YACnD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACtB,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC;YACnC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,UAAU,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC;YACnD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACtB,CAAC;QAED,qBAAqB;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5B,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBACnB,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC/C,CAAC;YACL,CAAC;QACL,CAAC;QAED,qBAAqB;QACrB,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YAEvF,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;gBAC/B,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;oBAC/B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;wBAAE,SAAS;oBAE/B,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,GAAG,CAAC;oBACpC,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,GAAG,CAAC;oBAEpC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;wBACT,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;oBACjD,CAAC;gBACL,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAEO,SAAS,CAAC,CAAS,EAAE,CAAS,EAAE,UAAkB;QACtD,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;QACjC,MAAM,EAAE,GAAG,CAAC,GAAG,UAAU,CAAC;QAC1B,MAAM,EAAE,GAAG,CAAC,GAAG,UAAU,CAAC;QAE1B,aAAa;QACb,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC;QAC3B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;QAElE,YAAY;QACZ,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,0BAA0B,CAAC;QAClD,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;QAEpE,SAAS;QACT,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,oBAAoB,CAAC;QAC5C,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;IACxE,CAAC;IAEO,aAAa;QACjB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC;QAEzB,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC1B,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAEhD,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAE5B,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;QACnC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAE1C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;YAC/B,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;gBAC/B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;oBAAE,SAAS;gBAE/B,MAAM,CAAC,GAAG,GAAG,GAAG,SAAS,CAAC;gBAC1B,MAAM,CAAC,GAAG,GAAG,GAAG,SAAS,CAAC;gBAE1B,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC;gBACtB,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC;gBAEjD,GAAG,CAAC,WAAW,GAAG,oBAAoB,CAAC;gBACvC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;gBAClB,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC;YACvD,CAAC;QACL,CAAC;IACL,CAAC;IAEO,QAAQ;QACZ,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QACtE,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QACtE,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC1E,CAAC;IAEO,OAAO;QACX,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QAEzB,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAE,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC3E,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAE,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC3E,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAE,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAE3E,MAAM,cAAc,GAAG,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAE,CAAC;QAClE,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAE1C,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAC1E,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAC1E,QAAQ,CAAC,QAAQ,GAAG,KAAK,CAAC;QAC1B,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC7B,CAAC;IAEO,QAAQ,CAAC,WAAmB;QAChC,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAE9B,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC;QAChC,CAAC;QAED,MAAM,SAAS,GAAG,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9C,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC;QAE5B,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACnB,IAAI,CAAC,WAAW,IAAI,SAAS,CAAC;YAE9B,IAAI,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;gBACvC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;gBACrB,IAAI,CAAC,SAAS,EAAE,CAAC;YACrB,CAAC;QACL,CAAC;QAED,qBAAqB,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IACzD,CAAC;CACJ;AAED,oCAAoC;AACpC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAC/C,IAAI,UAAU,EAAE,CAAC;AACrB,CAAC,CAAC,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,486 @@ +"use strict"; +// ─── Types ─────────────────────────────────────────────────────────── +// ─── Constants ─────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // pixel size of one cell +const COLORS = [ + "", // 0 = empty + "#00f0f0", // 1 = I (cyan) + "#f0f000", // 2 = O (yellow) + "#a000f0", // 3 = T (purple) + "#00f000", // 4 = S (green) + "#f00000", // 5 = Z (red) + "#0000f0", // 6 = J (blue) + "#f0a000", // 7 = L (orange) +]; +const BORDER_COLORS = [ + "", + "#009999", + "#999900", + "#660099", + "#009900", + "#990000", + "#000099", + "#996600", +]; +// Each tetromino defined with all rotation states (Super Rotation System shapes) +const TETROMINOES = [ + { + color: 1, + shapes: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + }, + { + color: 2, + shapes: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + }, + { + color: 3, + shapes: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + }, + { + color: 4, + shapes: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + }, + { + color: 5, + shapes: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + }, + { + color: 6, + shapes: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + }, + { + color: 7, + shapes: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], + }, +]; +// SRS wall kick data (non-I pieces) +const WALL_KICKS = [ + [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], // 0→1 + [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], // 1→2 + [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], // 2→3 + [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], // 3→0 +]; +// SRS wall kick data (I piece) +const WALL_KICKS_I = [ + [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], // 0→1 + [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], // 1→2 + [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], // 2→3 + [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], // 3→0 +]; +// Scoring: points per lines cleared +const LINE_POINTS = { + 1: 100, + 2: 300, + 3: 500, + 4: 800, +}; +// Gravity speed per level (ms per drop). Caps at level 20. +function getDropInterval(level) { + const speeds = [ + 800, 720, 630, 550, 470, 380, 300, 220, 160, 110, + 80, 70, 60, 50, 40, 35, 30, 25, 22, 20, + ]; + const idx = Math.min(level - 1, speeds.length - 1); + return speeds[idx]; +} +// ─── Game State ────────────────────────────────────────────────────── +const canvas = document.getElementById("game-canvas"); +const ctx = canvas.getContext("2d"); +const nextCanvas = document.getElementById("next-canvas"); +const nextCtx = nextCanvas.getContext("2d"); +const scoreEl = document.getElementById("score-display"); +const levelEl = document.getElementById("level-display"); +const linesEl = document.getElementById("lines-display"); +const overlay = document.getElementById("overlay"); +let grid; +let current; +let currentRotation; +let currentType; // index in TETROMINOES +let nextType; +let score; +let level; +let lines; +let gameOver; +let paused; +let started; +let lastDrop; +let dropInterval; +let animationId; +let bag; +// 7-bag randomizer for fair piece distribution +function fillBag() { + bag = [0, 1, 2, 3, 4, 5, 6]; + // Fisher-Yates shuffle + for (let i = bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [bag[i], bag[j]] = [bag[j], bag[i]]; + } +} +function nextFromBag() { + if (bag.length === 0) + fillBag(); + return bag.pop(); +} +// ─── Grid Helpers ──────────────────────────────────────────────────── +function createGrid() { + return Array.from({ length: ROWS }, () => new Array(COLS).fill(0)); +} +function collides(shape, px, py) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const nx = px + c; + const ny = py + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && grid[ny][nx] !== 0) + return true; + } + } + } + return false; +} +function lockPiece() { + const shape = current.shape; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const nx = current.x + c; + const ny = current.y + r; + if (ny >= 0 && ny < ROWS && nx >= 0 && nx < COLS) { + grid[ny][nx] = current.color; + } + } + } + } +} +function clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (grid[r].every((cell) => cell !== 0)) { + grid.splice(r, 1); + grid.unshift(new Array(COLS).fill(0)); + cleared++; + r++; // re-check this row + } + } + return cleared; +} +// ─── Piece Helpers ─────────────────────────────────────────────────── +function spawnPiece(type) { + const t = TETROMINOES[type]; + const shape = t.shapes[0]; + return { + shape: shape.map((row) => [...row]), + color: t.color, + x: Math.floor((COLS - shape[0].length) / 2), + y: -1, + }; +} +function rotateCW() { + const t = TETROMINOES[currentType]; + const newRot = (currentRotation + 1) % 4; + const newShape = t.shapes[newRot]; + const kicks = currentType === 0 ? WALL_KICKS_I : WALL_KICKS; + const kickSet = kicks[currentRotation]; + for (const [dx, dy] of kickSet) { + if (!collides(newShape, current.x + dx, current.y - dy)) { + current.shape = newShape.map((row) => [...row]); + current.x += dx; + current.y -= dy; + currentRotation = newRot; + return; + } + } +} +function ghostY() { + let gy = current.y; + while (!collides(current.shape, current.x, gy + 1)) { + gy++; + } + return gy; +} +// ─── Drawing ───────────────────────────────────────────────────────── +function drawBlock(context, x, y, colorIdx, alpha = 1, blockSize = BLOCK) { + const fill = COLORS[colorIdx]; + const border = BORDER_COLORS[colorIdx]; + context.globalAlpha = alpha; + context.fillStyle = fill; + context.fillRect(x * blockSize, y * blockSize, blockSize, blockSize); + // Highlight + context.fillStyle = "rgba(255,255,255,0.18)"; + context.fillRect(x * blockSize, y * blockSize, blockSize, blockSize * 0.15); + context.fillRect(x * blockSize, y * blockSize, blockSize * 0.15, blockSize); + // Border + context.strokeStyle = border; + context.lineWidth = 1.5; + context.strokeRect(x * blockSize + 0.75, y * blockSize + 0.75, blockSize - 1.5, blockSize - 1.5); + context.globalAlpha = 1; +} +function drawGrid() { + // Background grid lines + ctx.strokeStyle = "#1a1a3a"; + ctx.lineWidth = 0.5; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK, r * BLOCK, BLOCK, BLOCK); + } + } + // Locked blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] !== 0) { + drawBlock(ctx, c, r, grid[r][c]); + } + } + } +} +function drawGhost() { + const gy = ghostY(); + const shape = current.shape; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const nx = current.x + c; + const ny = gy + r; + if (ny >= 0) { + drawBlock(ctx, nx, ny, current.color, 0.2); + } + } + } + } +} +function drawCurrent() { + const shape = current.shape; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const nx = current.x + c; + const ny = current.y + r; + if (ny >= 0) { + drawBlock(ctx, nx, ny, current.color); + } + } + } + } +} +function drawNext() { + const bs = 24; + nextCtx.clearRect(0, 0, nextCanvas.width, nextCanvas.height); + const t = TETROMINOES[nextType]; + const shape = t.shapes[0]; + const offX = (nextCanvas.width / bs - shape[0].length) / 2; + const offY = (nextCanvas.height / bs - shape.length) / 2; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + drawBlock(nextCtx, offX + c, offY + r, t.color, 1, bs); + } + } + } +} +function drawScene() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + drawGrid(); + if (!gameOver) { + drawGhost(); + drawCurrent(); + } + drawNext(); + scoreEl.textContent = score.toLocaleString(); + levelEl.textContent = String(level); + linesEl.textContent = String(lines); +} +// ─── Game Loop ─────────────────────────────────────────────────────── +function drop() { + if (!collides(current.shape, current.x, current.y + 1)) { + current.y++; + } + else { + lockPiece(); + const cleared = clearLines(); + if (cleared > 0) { + score += (LINE_POINTS[cleared] || 0) * level; + lines += cleared; + const newLevel = Math.floor(lines / 10) + 1; + if (newLevel !== level) { + level = newLevel; + dropInterval = getDropInterval(level); + } + } + // Spawn next piece + currentType = nextType; + currentRotation = 0; + current = spawnPiece(currentType); + nextType = nextFromBag(); + // Check game over + if (collides(current.shape, current.x, current.y)) { + gameOver = true; + showOverlay("GAME OVER", `Score: ${score.toLocaleString()}`, "Press any key to restart"); + } + } +} +function hardDrop() { + const gy = ghostY(); + score += (gy - current.y) * 2; + current.y = gy; + drop(); // lock immediately +} +function tick(timestamp) { + if (!gameOver && !paused) { + if (timestamp - lastDrop > dropInterval) { + drop(); + lastDrop = timestamp; + } + drawScene(); + } + animationId = requestAnimationFrame(tick); +} +// ─── Overlay ───────────────────────────────────────────────────────── +function showOverlay(title, subtitle, hint) { + overlay.classList.remove("hidden"); + overlay.innerHTML = ` + <h1>${title}</h1> + <p>${subtitle}</p> + <div class="subtitle">${hint}</div> + `; +} +function hideOverlay() { + overlay.classList.add("hidden"); +} +// ─── Init / Reset ──────────────────────────────────────────────────── +function init() { + grid = createGrid(); + bag = []; + fillBag(); + score = 0; + level = 1; + lines = 0; + gameOver = false; + paused = false; + dropInterval = getDropInterval(1); + lastDrop = performance.now(); + currentType = nextFromBag(); + currentRotation = 0; + current = spawnPiece(currentType); + nextType = nextFromBag(); + drawScene(); +} +// ─── Input ─────────────────────────────────────────────────────────── +document.addEventListener("keydown", (e) => { + // Start / restart gate + if (!started) { + started = true; + hideOverlay(); + init(); + animationId = requestAnimationFrame(tick); + return; + } + if (gameOver) { + hideOverlay(); + init(); + return; + } + if (e.key === "p" || e.key === "P") { + paused = !paused; + if (paused) { + showOverlay("PAUSED", "", "Press P to resume"); + } + else { + hideOverlay(); + lastDrop = performance.now(); + } + return; + } + if (paused) + return; + switch (e.key) { + case "ArrowLeft": + if (!collides(current.shape, current.x - 1, current.y)) { + current.x--; + } + break; + case "ArrowRight": + if (!collides(current.shape, current.x + 1, current.y)) { + current.x++; + } + break; + case "ArrowDown": + if (!collides(current.shape, current.x, current.y + 1)) { + current.y++; + score += 1; + lastDrop = performance.now(); + } + break; + case "ArrowUp": + rotateCW(); + break; + case " ": + hardDrop(); + lastDrop = performance.now(); + break; + } + e.preventDefault(); + drawScene(); +}); +// Prevent scrolling on arrow / space +window.addEventListener("keydown", (e) => { + if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", " "].includes(e.key)) { + e.preventDefault(); + } +}); +// ─── Bootstrap ─────────────────────────────────────────────────────── +started = false; +grid = createGrid(); +bag = []; +score = 0; +level = 1; +lines = 0; +gameOver = false; +paused = false; +lastDrop = 0; +dropInterval = getDropInterval(1); +currentType = 0; +currentRotation = 0; +current = spawnPiece(0); +nextType = 1; +animationId = 0; +drawScene(); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,356 @@ +"use strict"; +// ── Types ──────────────────────────────────────────────────────────────────── +// ── Constants ──────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 32; +const PREVIEW_BLOCK = 20; +const TETROMINOES = [ + { shape: [[1, 1, 1, 1]], color: "#00f0f0" }, // I + { shape: [[1, 0, 0], [1, 1, 1]], color: "#0000f0" }, // J + { shape: [[0, 0, 1], [1, 1, 1]], color: "#f0a000" }, // L + { shape: [[1, 1], [1, 1]], color: "#f0f000" }, // O + { shape: [[0, 1, 1], [1, 1, 0]], color: "#00f000" }, // S + { shape: [[0, 1, 0], [1, 1, 1]], color: "#a000f0" }, // T + { shape: [[1, 1, 0], [0, 1, 1]], color: "#f00000" }, // Z +]; +const POINTS_PER_LINES = { 1: 100, 2: 300, 3: 500, 4: 800 }; +const BASE_INTERVAL = 800; // ms per gravity tick at level 1 +const SPEED_FACTOR = 0.08; // how much faster each level gets +const LINES_PER_LEVEL = 10; +const SOFT_DROP_INTERVAL = 50; +// ── Game state ─────────────────────────────────────────────────────────────── +let grid; +let current; +let next; +let score; +let lines; +let level; +let gameOver; +let paused; +let dropInterval; +let lastTick; +let animationId; +let softDropping; +// ── Canvas setup ───────────────────────────────────────────────────────────── +const canvas = document.getElementById("game-canvas"); +const ctx = canvas.getContext("2d"); +canvas.width = COLS * BLOCK_SIZE; +canvas.height = ROWS * BLOCK_SIZE; +const previewCanvas = document.getElementById("preview-canvas"); +const previewCtx = previewCanvas.getContext("2d"); +const scoreEl = document.getElementById("score"); +const linesEl = document.getElementById("lines"); +const levelEl = document.getElementById("level"); +const overlayEl = document.getElementById("overlay"); +const overlayTextEl = document.getElementById("overlay-text"); +// ── Helpers ────────────────────────────────────────────────────────────────── +function createGrid() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function randomTetromino() { + const t = TETROMINOES[Math.floor(Math.random() * TETROMINOES.length)]; + return { + shape: t.shape.map((r) => [...r]), + color: t.color, + pos: { x: Math.floor((COLS - t.shape[0].length) / 2), y: 0 }, + }; +} +function rotate(shape) { + const rows = shape.length; + const cols = shape[0].length; + const rotated = Array.from({ length: cols }, () => Array(rows).fill(0)); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + rotated[c][rows - 1 - r] = shape[r][c]; + } + } + return rotated; +} +function collides(shape, pos) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = pos.x + c; + const ny = pos.y + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && grid[ny][nx] !== null) + return true; + } + } + return false; +} +function lock() { + for (let r = 0; r < current.shape.length; r++) { + for (let c = 0; c < current.shape[r].length; c++) { + if (!current.shape[r][c]) + continue; + const ny = current.pos.y + r; + const nx = current.pos.x + c; + if (ny < 0) { + triggerGameOver(); + return; + } + grid[ny][nx] = current.color; + } + } + clearLines(); + spawn(); +} +function clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (grid[r].every((c) => c !== null)) { + grid.splice(r, 1); + grid.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check same row index + } + } + if (cleared > 0) { + lines += cleared; + score += (POINTS_PER_LINES[cleared] ?? 0) * level; + const newLevel = Math.floor(lines / LINES_PER_LEVEL) + 1; + if (newLevel !== level) { + level = newLevel; + dropInterval = Math.max(50, BASE_INTERVAL * Math.pow(1 - SPEED_FACTOR, level - 1)); + } + updateHUD(); + } +} +function spawn() { + current = next; + next = randomTetromino(); + if (collides(current.shape, current.pos)) { + triggerGameOver(); + } + drawPreview(); +} +function triggerGameOver() { + gameOver = true; + cancelAnimationFrame(animationId); + overlayTextEl.textContent = "GAME OVER \u2013 Press R to restart"; + overlayEl.classList.remove("hidden"); +} +function updateHUD() { + scoreEl.textContent = score.toString(); + linesEl.textContent = lines.toString(); + levelEl.textContent = level.toString(); +} +// ── Drawing ────────────────────────────────────────────────────────────────── +function drawBlock(context, x, y, color, size) { + context.fillStyle = color; + context.fillRect(x * size, y * size, size, size); + // highlight (top-left) + context.fillStyle = "rgba(255,255,255,0.25)"; + context.fillRect(x * size, y * size, size, 2); + context.fillRect(x * size, y * size, 2, size); + // shadow (bottom-right) + context.fillStyle = "rgba(0,0,0,0.25)"; + context.fillRect(x * size, (y + 1) * size - 2, size, 2); + context.fillRect((x + 1) * size - 2, y * size, 2, size); + // inner border + context.strokeStyle = "rgba(0,0,0,0.15)"; + context.strokeRect(x * size + 0.5, y * size + 0.5, size - 1, size - 1); +} +function ghostY() { + let gy = current.pos.y; + while (!collides(current.shape, { x: current.pos.x, y: gy + 1 })) { + gy++; + } + return gy; +} +function draw() { + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK_SIZE + 0.5, r * BLOCK_SIZE + 0.5, BLOCK_SIZE - 1, BLOCK_SIZE - 1); + } + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c]) { + drawBlock(ctx, c, r, grid[r][c], BLOCK_SIZE); + } + } + } + // Ghost piece + const gy = ghostY(); + for (let r = 0; r < current.shape.length; r++) { + for (let c = 0; c < current.shape[r].length; c++) { + if (!current.shape[r][c]) + continue; + const px = current.pos.x + c; + const py = gy + r; + if (py >= 0) { + ctx.fillStyle = "rgba(255,255,255,0.12)"; + ctx.fillRect(px * BLOCK_SIZE, py * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); + ctx.strokeStyle = "rgba(255,255,255,0.3)"; + ctx.strokeRect(px * BLOCK_SIZE + 0.5, py * BLOCK_SIZE + 0.5, BLOCK_SIZE - 1, BLOCK_SIZE - 1); + } + } + } + // Current piece + for (let r = 0; r < current.shape.length; r++) { + for (let c = 0; c < current.shape[r].length; c++) { + if (!current.shape[r][c]) + continue; + const px = current.pos.x + c; + const py = current.pos.y + r; + if (py >= 0) { + drawBlock(ctx, px, py, current.color, BLOCK_SIZE); + } + } + } +} +function drawPreview() { + previewCtx.fillStyle = "#1a1a2e"; + previewCtx.fillRect(0, 0, previewCanvas.width, previewCanvas.height); + const shape = next.shape; + const offX = Math.floor((previewCanvas.width / PREVIEW_BLOCK - shape[0].length) / 2); + const offY = Math.floor((previewCanvas.height / PREVIEW_BLOCK - shape.length) / 2); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + drawBlock(previewCtx, offX + c, offY + r, next.color, PREVIEW_BLOCK); + } + } + } +} +// ── Actions ────────────────────────────────────────────────────────────────── +function moveLeft() { + if (!collides(current.shape, { x: current.pos.x - 1, y: current.pos.y })) { + current.pos.x--; + } +} +function moveRight() { + if (!collides(current.shape, { x: current.pos.x + 1, y: current.pos.y })) { + current.pos.x++; + } +} +function moveDown() { + if (!collides(current.shape, { x: current.pos.x, y: current.pos.y + 1 })) { + current.pos.y++; + return true; + } + lock(); + return false; +} +function hardDrop() { + while (!collides(current.shape, { x: current.pos.x, y: current.pos.y + 1 })) { + current.pos.y++; + score += 2; + } + lock(); + updateHUD(); +} +function rotatePiece() { + const rotated = rotate(current.shape); + // Wall-kick offsets to try + const kicks = [0, -1, 1, -2, 2]; + for (const dx of kicks) { + if (!collides(rotated, { x: current.pos.x + dx, y: current.pos.y })) { + current.shape = rotated; + current.pos.x += dx; + return; + } + } +} +// ── Game loop ──────────────────────────────────────────────────────────────── +function tick(now) { + if (gameOver || paused) + return; + const interval = softDropping ? SOFT_DROP_INTERVAL : dropInterval; + if (now - lastTick >= interval) { + if (softDropping) + score += 1; + moveDown(); + updateHUD(); + lastTick = now; + } + draw(); + animationId = requestAnimationFrame(tick); +} +function startGame() { + grid = createGrid(); + score = 0; + lines = 0; + level = 1; + gameOver = false; + paused = false; + softDropping = false; + dropInterval = BASE_INTERVAL; + lastTick = performance.now(); + next = randomTetromino(); + current = randomTetromino(); + drawPreview(); + updateHUD(); + overlayEl.classList.add("hidden"); + cancelAnimationFrame(animationId); + animationId = requestAnimationFrame(tick); +} +// ── Input ──────────────────────────────────────────────────────────────────── +document.addEventListener("keydown", (e) => { + if (e.key === "r" || e.key === "R") { + startGame(); + return; + } + if (gameOver) + return; + if (e.key === "p" || e.key === "P") { + paused = !paused; + if (paused) { + overlayTextEl.textContent = "PAUSED \u2013 Press P to resume"; + overlayEl.classList.remove("hidden"); + } + else { + overlayEl.classList.add("hidden"); + lastTick = performance.now(); + animationId = requestAnimationFrame(tick); + } + return; + } + if (paused) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + e.preventDefault(); + moveLeft(); + break; + case "ArrowRight": + case "d": + e.preventDefault(); + moveRight(); + break; + case "ArrowDown": + case "s": + e.preventDefault(); + softDropping = true; + break; + case "ArrowUp": + case "w": + e.preventDefault(); + rotatePiece(); + break; + case " ": + e.preventDefault(); + hardDrop(); + break; + } +}); +document.addEventListener("keyup", (e) => { + if (e.key === "ArrowDown" || e.key === "s") { + softDropping = false; + } +}); +// ── Start ──────────────────────────────────────────────────────────────────── +startGame(); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,626 @@ +"use strict"; +// ── Constants ────────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 30; +const BOARD_WIDTH = COLS * BLOCK_SIZE; +const BOARD_HEIGHT = ROWS * BLOCK_SIZE; +const PREVIEW_SIZE = 4; +const INITIAL_DROP_INTERVAL = 800; // ms +const MIN_DROP_INTERVAL = 80; +const SPEED_DECREASE_PER_LEVEL = 60; // ms faster each level +const LINES_PER_LEVEL = 10; +const LOCK_DELAY = 500; // ms before piece locks after landing +const DAS_DELAY = 170; // delayed auto-shift initial delay +const DAS_REPEAT = 50; // auto-repeat rate +// Scoring (NES-style) +const SCORE_TABLE = { + 1: 100, + 2: 300, + 3: 500, + 4: 800, +}; +// ── Colors ───────────────────────────────────────────────────────────────────── +const PIECE_COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const GHOST_ALPHA = 0.25; +const SHAPES = { + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + O: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +// SRS wall-kick data +const WALL_KICKS = { + "0>1": [[-1, 0], [-1, -1], [0, 2], [-1, 2]], + "1>0": [[1, 0], [1, 1], [0, -2], [1, -2]], + "1>2": [[1, 0], [1, 1], [0, -2], [1, -2]], + "2>1": [[-1, 0], [-1, -1], [0, 2], [-1, 2]], + "2>3": [[1, 0], [1, -1], [0, 2], [1, 2]], + "3>2": [[-1, 0], [-1, 1], [0, -2], [-1, -2]], + "3>0": [[-1, 0], [-1, 1], [0, -2], [-1, -2]], + "0>3": [[1, 0], [1, -1], [0, 2], [1, 2]], +}; +const WALL_KICKS_I = { + "0>1": [[-2, 0], [1, 0], [-2, 1], [1, -2]], + "1>0": [[2, 0], [-1, 0], [2, -1], [-1, 2]], + "1>2": [[-1, 0], [2, 0], [-1, -2], [2, 1]], + "2>1": [[1, 0], [-2, 0], [1, 2], [-2, -1]], + "2>3": [[2, 0], [-1, 0], [2, -1], [-1, 2]], + "3>2": [[-2, 0], [1, 0], [-2, 1], [1, -2]], + "3>0": [[1, 0], [-2, 0], [1, 2], [-2, -1]], + "0>3": [[-1, 0], [2, 0], [-1, -2], [2, 1]], +}; +// ── 7-bag random generator ──────────────────────────────────────────────────── +class BagRandomizer { + constructor() { + this.bag = []; + } + next() { + if (this.bag.length === 0) { + this.bag = ["I", "O", "T", "S", "Z", "J", "L"]; + // Fisher-Yates shuffle + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop(); + } +} +// ── Game ─────────────────────────────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.heldPiece = null; + this.holdUsed = false; + this.score = 0; + this.level = 1; + this.linesCleared = 0; + this.gameOver = false; + this.paused = false; + // Timing + this.lastDrop = 0; + this.dropInterval = INITIAL_DROP_INTERVAL; + this.lockTimer = null; + // DAS state + this.dasDirection = null; + this.dasTimer = null; + this.dasRepeating = false; + // Animation + this.animationId = null; + this.flashingRows = []; + this.flashStart = 0; + this.FLASH_DURATION = 300; + // Keys held down + this.keysDown = new Set(); + this.canvas = document.getElementById("board"); + this.ctx = this.canvas.getContext("2d"); + this.previewCanvas = document.getElementById("preview"); + this.previewCtx = this.previewCanvas.getContext("2d"); + this.holdCanvas = document.getElementById("hold"); + this.holdCtx = this.holdCanvas.getContext("2d"); + this.scoreEl = document.getElementById("score"); + this.levelEl = document.getElementById("level"); + this.linesEl = document.getElementById("lines"); + this.messageEl = document.getElementById("message"); + this.canvas.width = BOARD_WIDTH; + this.canvas.height = BOARD_HEIGHT; + this.previewCanvas.width = BLOCK_SIZE * 5; + this.previewCanvas.height = BLOCK_SIZE * 14; + this.holdCanvas.width = BLOCK_SIZE * 5; + this.holdCanvas.height = BLOCK_SIZE * 4; + this.board = this.createBoard(); + this.bag = new BagRandomizer(); + this.nextQueue = [this.bag.next(), this.bag.next(), this.bag.next()]; + this.current = this.spawnPiece(this.bag.next()); + this.bindKeys(); + this.start(); + } + // ── Board helpers ────────────────────────────────────────────────────────── + createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); + } + getShape(piece) { + return SHAPES[piece.type][piece.rotation]; + } + collides(piece, board = this.board) { + const shape = SHAPES[piece.type][piece.rotation]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = piece.x + c; + const by = piece.y + r; + if (bx < 0 || bx >= COLS || by >= ROWS) + return true; + if (by >= 0 && board[by][bx] !== null) + return true; + } + } + return false; + } + lockPiece() { + const shape = this.getShape(this.current); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = this.current.x + c; + const by = this.current.y + r; + if (by < 0) { + this.triggerGameOver(); + return; + } + this.board[by][bx] = PIECE_COLORS[this.current.type]; + } + } + this.lockTimer = null; + this.clearLines(); + this.holdUsed = false; + this.spawnNext(); + } + clearLines() { + const fullRows = []; + for (let r = 0; r < ROWS; r++) { + if (this.board[r].every((cell) => cell !== null)) { + fullRows.push(r); + } + } + if (fullRows.length === 0) + return; + // Start flash animation + this.flashingRows = fullRows; + this.flashStart = performance.now(); + // Score + const pts = SCORE_TABLE[fullRows.length] || 0; + this.score += pts * this.level; + this.linesCleared += fullRows.length; + this.level = Math.floor(this.linesCleared / LINES_PER_LEVEL) + 1; + this.dropInterval = Math.max(MIN_DROP_INTERVAL, INITIAL_DROP_INTERVAL - (this.level - 1) * SPEED_DECREASE_PER_LEVEL); + // Actually remove the rows after a delay (handled in update via flash) + setTimeout(() => { + for (const row of fullRows) { + this.board.splice(row, 1); + this.board.unshift(Array(COLS).fill(null)); + } + this.flashingRows = []; + }, this.FLASH_DURATION); + } + spawnPiece(type) { + const shape = SHAPES[type][0]; + const piece = { + type, + rotation: 0, + x: Math.floor((COLS - shape[0].length) / 2), + y: type === "I" ? -1 : 0, + }; + return piece; + } + spawnNext() { + const nextType = this.nextQueue.shift(); + this.nextQueue.push(this.bag.next()); + this.current = this.spawnPiece(nextType); + if (this.collides(this.current)) { + this.triggerGameOver(); + } + } + // ── Ghost piece ──────────────────────────────────────────────────────────── + getGhostY() { + let ghost = { ...this.current }; + while (!this.collides({ ...ghost, y: ghost.y + 1 })) { + ghost.y++; + } + return ghost.y; + } + // ── Movement ─────────────────────────────────────────────────────────────── + move(dx, dy) { + const moved = { ...this.current, x: this.current.x + dx, y: this.current.y + dy }; + if (!this.collides(moved)) { + this.current = moved; + // Reset lock timer if we moved horizontally and piece is on ground + if (dx !== 0 && this.lockTimer !== null) { + this.lockTimer = performance.now(); + } + return true; + } + return false; + } + rotate(dir) { + const oldR = this.current.rotation; + const newR = (oldR + dir + 4) % 4; + const rotated = { ...this.current, rotation: newR }; + // Try basic rotation + if (!this.collides(rotated)) { + this.current = rotated; + if (this.lockTimer !== null) + this.lockTimer = performance.now(); + return; + } + // Wall kicks + const kickKey = `${oldR}>${newR}`; + const kicks = this.current.type === "I" ? WALL_KICKS_I[kickKey] : WALL_KICKS[kickKey]; + if (!kicks) + return; + for (const [kx, ky] of kicks) { + const kicked = { ...rotated, x: rotated.x + kx, y: rotated.y - ky }; + if (!this.collides(kicked)) { + this.current = kicked; + if (this.lockTimer !== null) + this.lockTimer = performance.now(); + return; + } + } + } + hardDrop() { + let dropped = 0; + while (!this.collides({ ...this.current, y: this.current.y + 1 })) { + this.current.y++; + dropped++; + } + this.score += dropped * 2; + this.lockPiece(); + } + softDrop() { + if (this.move(0, 1)) { + this.score += 1; + return true; + } + return false; + } + hold() { + if (this.holdUsed) + return; + this.holdUsed = true; + const type = this.current.type; + if (this.heldPiece !== null) { + this.current = this.spawnPiece(this.heldPiece); + } + else { + this.spawnNext(); + } + this.heldPiece = type; + this.lockTimer = null; + } + // ── Input ────────────────────────────────────────────────────────────────── + bindKeys() { + document.addEventListener("keydown", (e) => { + if (this.gameOver) { + if (e.key === "Enter") + this.restart(); + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.paused = !this.paused; + this.messageEl.textContent = this.paused ? "PAUSED" : ""; + return; + } + if (this.paused) + return; + switch (e.key) { + case "ArrowLeft": + e.preventDefault(); + if (!this.keysDown.has("ArrowLeft")) { + this.move(-1, 0); + this.dasDirection = "left"; + this.dasTimer = performance.now(); + this.dasRepeating = false; + } + this.keysDown.add("ArrowLeft"); + break; + case "ArrowRight": + e.preventDefault(); + if (!this.keysDown.has("ArrowRight")) { + this.move(1, 0); + this.dasDirection = "right"; + this.dasTimer = performance.now(); + this.dasRepeating = false; + } + this.keysDown.add("ArrowRight"); + break; + case "ArrowDown": + e.preventDefault(); + this.keysDown.add("ArrowDown"); + this.softDrop(); + break; + case "ArrowUp": + e.preventDefault(); + this.rotate(1); + break; + case "z": + case "Z": + this.rotate(-1); + break; + case "x": + case "X": + this.rotate(1); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + case "c": + case "C": + case "Shift": + this.hold(); + break; + } + }); + document.addEventListener("keyup", (e) => { + this.keysDown.delete(e.key); + if (e.key === "ArrowLeft" && this.dasDirection === "left") { + this.dasDirection = null; + this.dasTimer = null; + } + if (e.key === "ArrowRight" && this.dasDirection === "right") { + this.dasDirection = null; + this.dasTimer = null; + } + }); + } + // ── Game lifecycle ───────────────────────────────────────────────────────── + triggerGameOver() { + this.gameOver = true; + this.messageEl.textContent = "GAME OVER — Press Enter"; + } + restart() { + this.board = this.createBoard(); + this.bag = new BagRandomizer(); + this.nextQueue = [this.bag.next(), this.bag.next(), this.bag.next()]; + this.current = this.spawnPiece(this.bag.next()); + this.heldPiece = null; + this.holdUsed = false; + this.score = 0; + this.level = 1; + this.linesCleared = 0; + this.dropInterval = INITIAL_DROP_INTERVAL; + this.gameOver = false; + this.paused = false; + this.flashingRows = []; + this.lockTimer = null; + this.messageEl.textContent = ""; + this.lastDrop = performance.now(); + } + start() { + this.lastDrop = performance.now(); + const loop = (now) => { + this.update(now); + this.draw(); + this.animationId = requestAnimationFrame(loop); + }; + this.animationId = requestAnimationFrame(loop); + } + // ── Update ───────────────────────────────────────────────────────────────── + update(now) { + if (this.gameOver || this.paused) + return; + // DAS (delayed auto-shift) + if (this.dasDirection && this.dasTimer !== null) { + const elapsed = now - this.dasTimer; + if (!this.dasRepeating && elapsed >= DAS_DELAY) { + this.dasRepeating = true; + this.dasTimer = now; + this.move(this.dasDirection === "left" ? -1 : 1, 0); + } + else if (this.dasRepeating && elapsed >= DAS_REPEAT) { + this.dasTimer = now; + this.move(this.dasDirection === "left" ? -1 : 1, 0); + } + } + // Soft drop repeat + if (this.keysDown.has("ArrowDown")) { + // Override gravity with faster drop + if (now - this.lastDrop > 50) { + this.softDrop(); + this.lastDrop = now; + return; + } + } + // Gravity + if (now - this.lastDrop > this.dropInterval) { + if (!this.move(0, 1)) { + // Piece can't move down — start or check lock timer + if (this.lockTimer === null) { + this.lockTimer = now; + } + else if (now - this.lockTimer >= LOCK_DELAY) { + this.lockPiece(); + } + } + else { + this.lockTimer = null; + } + this.lastDrop = now; + } + // If piece is on ground and lock timer running, check if piece can still drop + if (this.lockTimer !== null) { + if (!this.collides({ ...this.current, y: this.current.y + 1 })) { + // Piece is no longer on ground (moved sideways off a ledge) + this.lockTimer = null; + } + else if (now - this.lockTimer >= LOCK_DELAY) { + this.lockPiece(); + } + } + this.updateUI(); + } + updateUI() { + this.scoreEl.textContent = this.score.toString(); + this.levelEl.textContent = this.level.toString(); + this.linesEl.textContent = this.linesCleared.toString(); + } + // ── Drawing ──────────────────────────────────────────────────────────────── + draw() { + this.drawBoard(); + this.drawPreview(); + this.drawHold(); + } + drawBlock(ctx, x, y, color, alpha = 1, size = BLOCK_SIZE) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size, y * size, size, size); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.3)"; + ctx.fillRect(x * size, y * size, size, size * 0.15); + ctx.fillRect(x * size, y * size, size * 0.15, size); + // Shadow + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(x * size, y * size + size * 0.85, size, size * 0.15); + ctx.fillRect(x * size + size * 0.85, y * size, size * 0.15, size); + // Border + ctx.strokeStyle = "rgba(0,0,0,0.5)"; + ctx.lineWidth = 1; + ctx.strokeRect(x * size + 0.5, y * size + 0.5, size - 1, size - 1); + ctx.globalAlpha = 1; + } + drawBoard() { + const ctx = this.ctx; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, BOARD_WIDTH, BOARD_HEIGHT); + // Grid + ctx.strokeStyle = "rgba(255,255,255,0.05)"; + ctx.lineWidth = 1; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK_SIZE + 0.5, r * BLOCK_SIZE + 0.5, BLOCK_SIZE - 1, BLOCK_SIZE - 1); + } + } + // Locked blocks + const now = performance.now(); + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.board[r][c]) { + if (this.flashingRows.includes(r)) { + // Flash effect + const elapsed = now - this.flashStart; + const flash = Math.sin((elapsed / this.FLASH_DURATION) * Math.PI * 4) > 0; + if (flash) { + this.drawBlock(ctx, c, r, "#fff"); + } + else { + this.drawBlock(ctx, c, r, this.board[r][c]); + } + } + else { + this.drawBlock(ctx, c, r, this.board[r][c]); + } + } + } + } + if (this.gameOver || this.paused) + return; + // Ghost piece + const ghostY = this.getGhostY(); + const shape = this.getShape(this.current); + const color = PIECE_COLORS[this.current.type]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = this.current.x + c; + const by = ghostY + r; + if (by >= 0 && by < ROWS) { + this.drawBlock(ctx, bx, by, color, GHOST_ALPHA); + } + } + } + // Current piece + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = this.current.x + c; + const by = this.current.y + r; + if (by >= 0 && by < ROWS) { + this.drawBlock(ctx, bx, by, color); + } + } + } + } + drawPieceOnCanvas(ctx, type, offsetX, offsetY, blockSize = BLOCK_SIZE) { + const shape = SHAPES[type][0]; + const color = PIECE_COLORS[type]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + this.drawBlock(ctx, offsetX + c, offsetY + r, color, 1, blockSize); + } + } + } + drawPreview() { + const ctx = this.previewCtx; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, this.previewCanvas.width, this.previewCanvas.height); + for (let i = 0; i < this.nextQueue.length; i++) { + const type = this.nextQueue[i]; + const ox = type === "O" ? 1.5 : type === "I" ? 0.5 : 1; + const oy = i * 4 + (type === "I" ? 0.5 : 1); + this.drawPieceOnCanvas(ctx, type, ox, oy); + } + } + drawHold() { + const ctx = this.holdCtx; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, this.holdCanvas.width, this.holdCanvas.height); + if (this.heldPiece) { + const type = this.heldPiece; + const ox = type === "O" ? 1.5 : type === "I" ? 0.5 : 1; + const oy = type === "I" ? 0 : 0.5; + const alpha = this.holdUsed ? 0.4 : 1; + ctx.globalAlpha = alpha; + this.drawPieceOnCanvas(ctx, type, ox, oy); + ctx.globalAlpha = 1; + } + } +} +// ── Bootstrap ────────────────────────────────────────────────────────────────── +document.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;CACF,CAAC;AAEF,qBAAqB;AACrB,MAAM,UAAU,GAAuC;IACrD,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACpC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAClC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAClC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACpC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACjC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACrC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACrC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,509 @@ +"use strict"; +// ============================================================ +// TETRIS – TypeScript, Canvas 2D +// ============================================================ +// ── Constants ───────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 32; // px per cell on main board +const NEXT_BLOCK = 24; // px per cell on next-piece preview +const COLORS = [ + null, + '#00cfcf', // 1 – I (cyan) + '#cfcf00', // 2 – O (yellow) + '#9f00cf', // 3 – T (purple) + '#00cf00', // 4 – S (green) + '#cf0000', // 5 – Z (red) + '#0000cf', // 6 – J (blue) + '#cf6f00', // 7 – L (orange) +]; +const GHOST_ALPHA = 0.25; +// Piece matrices indexed 1-7 to match COLORS +const PIECES = [ + [], // 0 – placeholder + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], // 1 – I + [[2, 2], [2, 2]], // 2 – O + [[0, 3, 0], [3, 3, 3], [0, 0, 0]], // 3 – T + [[0, 4, 4], [4, 4, 0], [0, 0, 0]], // 4 – S + [[5, 5, 0], [0, 5, 5], [0, 0, 0]], // 5 – Z + [[6, 0, 0], [6, 6, 6], [0, 0, 0]], // 6 – J + [[0, 0, 7], [7, 7, 7], [0, 0, 0]], // 7 – L +]; +// Points awarded for 1-4 lines cleared (multiplied by level) +const LINE_POINTS = [0, 100, 300, 500, 800]; +// Drop interval in ms at each level (level 0-based index, capped at 29) +function dropInterval(level) { + const frames = [48, 43, 38, 33, 28, 23, 18, 13, 8, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1]; + const f = frames[Math.min(level, frames.length - 1)]; + return Math.round((f / 60) * 1000); +} +// ── Helpers ────────────────────────────────────────────────── +function createBoard() { + return Array.from({ length: ROWS }, () => new Array(COLS).fill(0)); +} +function rotate(matrix, dir) { + const size = matrix.length; + const cols = matrix[0].length; + const result = Array.from({ length: cols }, () => new Array(size).fill(0)); + for (let r = 0; r < size; r++) { + for (let c = 0; c < cols; c++) { + if (dir === 1) { + result[c][size - 1 - r] = matrix[r][c]; + } + else { + result[cols - 1 - c][r] = matrix[r][c]; + } + } + } + return result; +} +function randomPieceType() { + return Math.floor(Math.random() * 7) + 1; +} +function spawnPiece(type) { + const matrix = PIECES[type].map(row => [...row]); + const x = Math.floor((COLS - matrix[0].length) / 2); + return { matrix, x, y: 0, type }; +} +// ── Collision ──────────────────────────────────────────────── +function collides(board, piece, dx = 0, dy = 0, mat) { + const m = mat !== null && mat !== void 0 ? mat : piece.matrix; + for (let r = 0; r < m.length; r++) { + for (let c = 0; c < m[r].length; c++) { + if (!m[r][c]) + continue; + const nx = piece.x + c + dx; + const ny = piece.y + r + dy; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny < 0) + continue; + if (board[ny][nx]) + return true; + } + } + return false; +} +// Wall-kick offsets (SRS-lite): try these dx offsets in order +const KICKS = [0, -1, 1, -2, 2]; +// ── Rendering helpers ──────────────────────────────────────── +function drawBlock(ctx, x, y, colorIndex, blockSize, alpha = 1) { + const color = COLORS[colorIndex]; + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * blockSize + 1, y * blockSize + 1, blockSize - 2, blockSize - 2); + // Highlight + ctx.fillStyle = 'rgba(255,255,255,0.3)'; + ctx.fillRect(x * blockSize + 1, y * blockSize + 1, blockSize - 2, 4); + ctx.fillRect(x * blockSize + 1, y * blockSize + 1, 4, blockSize - 2); + // Shadow edge + ctx.fillStyle = 'rgba(0,0,0,0.3)'; + ctx.fillRect(x * blockSize + 1, y * blockSize + blockSize - 5, blockSize - 2, 4); + ctx.fillRect(x * blockSize + blockSize - 5, y * blockSize + 1, 4, blockSize - 2); + ctx.globalAlpha = 1; +} +function drawMatrix(ctx, matrix, ox, oy, blockSize, alpha = 1) { + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (matrix[r][c]) { + drawBlock(ctx, ox + c, oy + r, matrix[r][c], blockSize, alpha); + } + } + } +} +// ── Game Class ─────────────────────────────────────────────── +class Tetris { + constructor() { + this.board = createBoard(); + this.score = 0; + this.lines = 0; + this.level = 0; + this.dropCounter = 0; + this.lastTime = 0; + this.animId = null; + this.gameOver = false; + this.paused = false; + // Hold + this.held = null; + this.holdUsed = false; + // DAS (Delayed Auto-Shift) + this.dasLeft = false; + this.dasRight = false; + this.dasDelay = 170; // ms before auto-repeat starts + this.dasRate = 50; // ms between auto-repeats + this.dasLeftTimer = 0; + this.dasRightTimer = 0; + this.dasLeftRepeat = false; + this.dasRightRepeat = false; + this.initDOM(); + this.bindKeys(); + this.showOverlay('TETRIS', 'Press Start or Enter to play'); + } + // ── DOM setup ──────────────────────────────────────────── + initDOM() { + const boardCanvas = document.getElementById('board'); + const nextCanvas = document.getElementById('next'); + const holdCanvas = document.getElementById('hold'); + boardCanvas.width = COLS * BLOCK; + boardCanvas.height = ROWS * BLOCK; + nextCanvas.width = 4 * NEXT_BLOCK; + nextCanvas.height = 4 * NEXT_BLOCK; + holdCanvas.width = 4 * NEXT_BLOCK; + holdCanvas.height = 4 * NEXT_BLOCK; + this.boardCtx = boardCanvas.getContext('2d'); + this.nextCtx = nextCanvas.getContext('2d'); + this.holdCtx = holdCanvas.getContext('2d'); + this.scoreEl = document.getElementById('score'); + this.linesEl = document.getElementById('lines'); + this.levelEl = document.getElementById('level'); + this.overlayEl = document.getElementById('overlay'); + this.overlayTitle = document.getElementById('overlay-title'); + this.overlayMsg = document.getElementById('overlay-msg'); + this.startBtn = document.getElementById('start-btn'); + this.startBtn.addEventListener('click', () => this.startGame()); + } + // ── Key bindings ───────────────────────────────────────── + bindKeys() { + document.addEventListener('keydown', (e) => { + if (e.repeat) + return; + switch (e.code) { + case 'Enter': + if (this.gameOver || !this.animId) { + this.startGame(); + return; + } + break; + case 'Escape': + case 'KeyP': + this.togglePause(); + return; + } + if (this.gameOver || this.paused) + return; + switch (e.code) { + case 'ArrowLeft': + case 'KeyA': + e.preventDefault(); + this.moveLeft(); + this.dasLeft = true; + this.dasLeftTimer = Date.now() + this.dasDelay; + this.dasLeftRepeat = false; + break; + case 'ArrowRight': + case 'KeyD': + e.preventDefault(); + this.moveRight(); + this.dasRight = true; + this.dasRightTimer = Date.now() + this.dasDelay; + this.dasRightRepeat = false; + break; + case 'ArrowDown': + case 'KeyS': + e.preventDefault(); + this.softDrop(); + break; + case 'ArrowUp': + case 'KeyW': + e.preventDefault(); + this.rotatePiece(1); + break; + case 'KeyZ': + e.preventDefault(); + this.rotatePiece(-1); + break; + case 'KeyX': + e.preventDefault(); + this.rotatePiece(1); + break; + case 'Space': + e.preventDefault(); + this.hardDrop(); + break; + case 'KeyC': + case 'ShiftLeft': + case 'ShiftRight': + e.preventDefault(); + this.holdPiece(); + break; + } + }); + document.addEventListener('keyup', (e) => { + if (e.code === 'ArrowLeft' || e.code === 'KeyA') + this.dasLeft = false; + if (e.code === 'ArrowRight' || e.code === 'KeyD') + this.dasRight = false; + }); + } + // ── Game lifecycle ──────────────────────────────────────── + startGame() { + this.board = createBoard(); + this.score = 0; + this.lines = 0; + this.level = 0; + this.held = null; + this.holdUsed = false; + this.gameOver = false; + this.paused = false; + this.dropCounter = 0; + this.dasLeft = false; + this.dasRight = false; + this.next = spawnPiece(randomPieceType()); + this.current = this.nextPiece(); + this.hideOverlay(); + this.updateUI(); + if (this.animId) + cancelAnimationFrame(this.animId); + this.lastTime = performance.now(); + this.animId = requestAnimationFrame(this.loop.bind(this)); + } + nextPiece() { + const p = this.next; + this.next = spawnPiece(randomPieceType()); + return p; + } + togglePause() { + if (this.gameOver) + return; + if (!this.animId && this.paused) { + // resume + this.paused = false; + this.hideOverlay(); + this.lastTime = performance.now(); + this.animId = requestAnimationFrame(this.loop.bind(this)); + } + else if (this.animId && !this.paused) { + // pause + this.paused = true; + cancelAnimationFrame(this.animId); + this.animId = null; + this.showOverlay('PAUSED', 'Press P or Escape to resume'); + } + } + // ── Main loop ───────────────────────────────────────────── + loop(time) { + const delta = time - this.lastTime; + this.lastTime = time; + this.dropCounter += delta; + if (this.dropCounter >= dropInterval(this.level)) { + this.dropCounter = 0; + this.gravity(); + } + // DAS + const now = Date.now(); + if (this.dasLeft && now >= this.dasLeftTimer) { + this.moveLeft(); + this.dasLeftTimer = now + (this.dasLeftRepeat ? this.dasRate : this.dasDelay); + this.dasLeftRepeat = true; + } + if (this.dasRight && now >= this.dasRightTimer) { + this.moveRight(); + this.dasRightTimer = now + (this.dasRightRepeat ? this.dasRate : this.dasDelay); + this.dasRightRepeat = true; + } + this.render(); + this.animId = requestAnimationFrame(this.loop.bind(this)); + } + // ── Physics ─────────────────────────────────────────────── + gravity() { + if (!collides(this.board, this.current, 0, 1)) { + this.current.y++; + } + else { + this.lockPiece(); + } + } + lockPiece() { + const { matrix, x, y } = this.current; + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (!matrix[r][c]) + continue; + const boardY = y + r; + if (boardY < 0) { + this.endGame(); + return; + } + this.board[boardY][x + c] = matrix[r][c]; + } + } + this.clearLines(); + this.holdUsed = false; + this.current = this.nextPiece(); + if (collides(this.board, this.current)) { + this.endGame(); + } + } + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every(cell => cell !== 0)) { + this.board.splice(r, 1); + this.board.unshift(new Array(COLS).fill(0)); + cleared++; + r++; // re-check same index + } + } + if (cleared > 0) { + this.lines += cleared; + this.score += LINE_POINTS[cleared] * (this.level + 1); + this.level = Math.floor(this.lines / 10); + this.updateUI(); + } + } + // ── Moves ───────────────────────────────────────────────── + moveLeft() { + if (!collides(this.board, this.current, -1)) + this.current.x--; + } + moveRight() { + if (!collides(this.board, this.current, 1)) + this.current.x++; + } + softDrop() { + if (!collides(this.board, this.current, 0, 1)) { + this.current.y++; + this.score++; + this.dropCounter = 0; + this.updateUI(); + } + } + hardDrop() { + let dropped = 0; + while (!collides(this.board, this.current, 0, 1)) { + this.current.y++; + dropped++; + } + this.score += dropped * 2; + this.dropCounter = 0; + this.lockPiece(); + this.updateUI(); + } + rotatePiece(dir) { + const rotated = rotate(this.current.matrix, dir); + const original = this.current.matrix; + this.current.matrix = rotated; + for (const kick of KICKS) { + this.current.x += kick; + if (!collides(this.board, this.current)) + return; // success + this.current.x -= kick; + } + this.current.matrix = original; // revert + } + holdPiece() { + if (this.holdUsed) + return; + this.holdUsed = true; + const type = this.current.type; + if (this.held === null) { + this.held = type; + this.current = this.nextPiece(); + } + else { + const prev = this.held; + this.held = type; + this.current = spawnPiece(prev); + } + this.drawHold(); + } + // ── Ghost piece ─────────────────────────────────────────── + ghostY() { + let gy = this.current.y; + while (!collides(this.board, Object.assign(Object.assign({}, this.current), { y: gy + 1 }))) + gy++; + return gy; + } + // ── Render ──────────────────────────────────────────────── + render() { + this.drawBoard(); + this.drawNextPiece(); + } + drawBoard() { + const ctx = this.boardCtx; + const W = COLS * BLOCK; + const H = ROWS * BLOCK; + // Background + ctx.fillStyle = '#111'; + ctx.fillRect(0, 0, W, H); + // Grid lines + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let c = 1; c < COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, H); + ctx.stroke(); + } + for (let r = 1; r < ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(W, r * BLOCK); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.board[r][c]) + drawBlock(ctx, c, r, this.board[r][c], BLOCK); + } + } + // Ghost + const gy = this.ghostY(); + drawMatrix(ctx, this.current.matrix, this.current.x, gy, BLOCK, GHOST_ALPHA); + // Current piece + drawMatrix(ctx, this.current.matrix, this.current.x, this.current.y, BLOCK); + } + drawNextPiece() { + const ctx = this.nextCtx; + const S = 4 * NEXT_BLOCK; + ctx.fillStyle = '#1a1a2e'; + ctx.fillRect(0, 0, S, S); + const m = this.next.matrix; + const ox = Math.floor((4 - m[0].length) / 2); + const oy = Math.floor((4 - m.length) / 2); + drawMatrix(ctx, m, ox, oy, NEXT_BLOCK); + } + drawHold() { + const ctx = this.holdCtx; + const S = 4 * NEXT_BLOCK; + ctx.fillStyle = '#1a1a2e'; + ctx.fillRect(0, 0, S, S); + if (this.held === null) + return; + const m = PIECES[this.held]; + const ox = Math.floor((4 - m[0].length) / 2); + const oy = Math.floor((4 - m.length) / 2); + ctx.globalAlpha = this.holdUsed ? 0.4 : 1; + drawMatrix(ctx, m, ox, oy, NEXT_BLOCK); + ctx.globalAlpha = 1; + } + // ── UI ──────────────────────────────────────────────────── + updateUI() { + this.scoreEl.textContent = String(this.score); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + } + showOverlay(title, msg) { + this.overlayTitle.textContent = title; + this.overlayMsg.textContent = msg; + this.overlayEl.style.display = 'flex'; + this.startBtn.textContent = (title === 'GAME OVER' || title === 'TETRIS') ? 'Start' : 'Resume'; + } + hideOverlay() { + this.overlayEl.style.display = 'none'; + } + endGame() { + this.gameOver = true; + if (this.animId) { + cancelAnimationFrame(this.animId); + this.animId = null; + } + this.showOverlay('GAME OVER', `Score: ${this.score} | Lines: ${this.lines} | Level: ${this.level}`); + this.startBtn.textContent = 'Play Again'; + } +} +// ── Bootstrap ───────────────────────────────────────────────── +window.addEventListener('DOMContentLoaded', () => { + new Tetris(); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,667 @@ +"use strict"; +// ============================================================ +// Tetris — complete browser game +// ============================================================ +// ─── Constants ─────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell on the main board +const MINI = 25; // px per cell in hold / next previews +const PIECE_TYPES = ['I', 'J', 'L', 'O', 'S', 'T', 'Z']; +/** Guideline colours */ +const COLORS = { + I: '#00d4e0', + J: '#3b5bdb', + L: '#f76707', + O: '#f59f00', + S: '#2f9e44', + T: '#ae3ec9', + Z: '#e03131', +}; +/** Spawn shapes — all use the same 0-based top-left anchor */ +const SPAWN_SHAPES = { + I: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + J: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + L: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], + O: [ + [1, 1], + [1, 1], + ], + S: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + T: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + Z: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], +}; +const KICKS_JLSTZ = { + '0->1': [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + '1->0': [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + '1->2': [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + '2->1': [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + '2->3': [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + '3->2': [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + '3->0': [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + '0->3': [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], +}; +const KICKS_I = { + '0->1': [[0, 0], [-2, 0], [1, 0], [-2, 1], [1, -2]], + '1->0': [[0, 0], [2, 0], [-1, 0], [2, -1], [-1, 2]], + '1->2': [[0, 0], [-1, 0], [2, 0], [-1, -2], [2, 1]], + '2->1': [[0, 0], [1, 0], [-2, 0], [1, 2], [-2, -1]], + '2->3': [[0, 0], [2, 0], [-1, 0], [2, -1], [-1, 2]], + '3->2': [[0, 0], [-2, 0], [1, 0], [-2, 1], [1, -2]], + '3->0': [[0, 0], [1, 0], [-2, 0], [1, 2], [-2, -1]], + '0->3': [[0, 0], [-1, 0], [2, 0], [-1, -2], [2, 1]], +}; +// Scoring per line count (multiplied by current level) +const LINE_POINTS = [0, 100, 300, 500, 800]; +const LINES_PER_LEVEL = 10; +// Timing (milliseconds) +const DAS_DELAY = 167; // hold before auto-repeat starts +const DAS_INTERVAL = 33; // interval between auto-repeat moves +const SOFT_DROP_MS = 50; // drop interval while ↓ is held +const LOCK_DELAY = 500; // time on ground before locking +const MAX_LOCK_RESETS = 15; +// ─── Shape rotation helpers ─────────────────────────────────── +/** Rotate a shape matrix 90° clockwise. + * For a square n×n matrix: result[c][n-1-r] = shape[r][c] + */ +function rotateCW(shape) { + const rows = shape.length; + const cols = shape[0].length; + const out = Array.from({ length: cols }, () => new Array(rows).fill(0)); + for (let r = 0; r < rows; r++) + for (let c = 0; c < cols; c++) + out[c][rows - 1 - r] = shape[r][c]; + return out; +} +/** Rotate a shape matrix 90° counter-clockwise. */ +function rotateCCW(shape) { + const rows = shape.length; + const cols = shape[0].length; + const out = Array.from({ length: cols }, () => new Array(rows).fill(0)); + for (let r = 0; r < rows; r++) + for (let c = 0; c < cols; c++) + out[cols - 1 - c][r] = shape[r][c]; + return out; +} +// ─── 7-bag randomiser ───────────────────────────────────────── +class BagRandomizer { + constructor() { + this.bag = []; + } + next() { + if (this.bag.length === 0) { + this.bag = [...PIECE_TYPES]; + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop(); + } +} +// ─── Main game class ────────────────────────────────────────── +class TetrisGame { + // ── Bootstrap ────────────────────────────────────────────── + constructor() { + // Board + this.board = []; + this.active = null; + this.nextType = 'I'; + this.heldType = null; + this.canHold = true; + this.bag = new BagRandomizer(); + // Score + this.score = 0; + this.lines = 0; + this.level = 1; + this.state = 'playing'; + // Gravity / lock timing + this.lastTs = 0; + this.dropAccum = 0; + this.lockAccum = 0; + this.lockResets = 0; + this.onGround = false; + this.animId = 0; + // DAS state + this.keys = new Set(); + this.dasLeft = 0; + this.dasRight = 0; + this.boardCanvas = document.getElementById('board-canvas'); + this.boardCtx = this.boardCanvas.getContext('2d'); + this.nextCanvas = document.getElementById('next-canvas'); + this.nextCtx = this.nextCanvas.getContext('2d'); + this.holdCanvas = document.getElementById('hold-canvas'); + this.holdCtx = this.holdCanvas.getContext('2d'); + this.scoreEl = document.getElementById('score'); + this.linesEl = document.getElementById('lines'); + this.levelEl = document.getElementById('level'); + this.overlayEl = document.getElementById('overlay'); + // Set intrinsic canvas sizes (these are the drawing buffer dimensions) + this.boardCanvas.width = COLS * BLOCK; + this.boardCanvas.height = ROWS * BLOCK; + this.nextCanvas.width = 4 * MINI; + this.nextCanvas.height = 4 * MINI; + this.holdCanvas.width = 4 * MINI; + this.holdCanvas.height = 4 * MINI; + this.setupInput(); + this.initGame(); + this.animId = requestAnimationFrame(ts => this.loop(ts)); + } + // ── Initialisation / restart ─────────────────────────────── + initGame() { + this.board = Array.from({ length: ROWS }, () => new Array(COLS).fill(null)); + this.score = 0; + this.lines = 0; + this.level = 1; + this.heldType = null; + this.canHold = true; + this.bag = new BagRandomizer(); + this.lastTs = 0; + this.dropAccum = 0; + this.lockAccum = 0; + this.lockResets = 0; + this.onGround = false; + this.dasLeft = 0; + this.dasRight = 0; + this.state = 'playing'; + this.nextType = this.bag.next(); + this.spawnNext(); + this.updateUI(); + this.overlayEl.style.display = 'none'; + } + // ── Piece management ─────────────────────────────────────── + spawnNext() { + const type = this.nextType; + this.nextType = this.bag.next(); + const shape = SPAWN_SHAPES[type].map(r => [...r]); + const piece = { + type, + shape, + rotation: 0, + x: Math.floor((COLS - shape[0].length) / 2), + y: -1, // start one row above visible area (bar typically at row 0) + }; + if (!this.isValid(piece, piece.x, piece.y)) { + // Block-out: can't spawn → game over + this.active = piece; + this.triggerGameOver(); + return; + } + this.active = piece; + this.onGround = false; + this.lockAccum = 0; + this.lockResets = 0; + this.canHold = true; + } + // ── Collision detection ──────────────────────────────────── + isValid(piece, tx, ty) { + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + const nx = tx + c; + const ny = ty + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return false; + if (ny >= 0 && this.board[ny][nx] !== null) + return false; + } + } + return true; + } + // ── Movement ─────────────────────────────────────────────── + move(dx, dy) { + if (!this.active) + return false; + const nx = this.active.x + dx; + const ny = this.active.y + dy; + if (!this.isValid(this.active, nx, ny)) + return false; + this.active.x = nx; + this.active.y = ny; + // Reset lock delay (up to max resets) when moving horizontally on the ground + if (dx !== 0 && this.onGround && this.lockResets < MAX_LOCK_RESETS) { + this.lockAccum = 0; + this.lockResets++; + } + return true; + } + tryRotate(dir) { + if (!this.active) + return; + const oldRot = this.active.rotation; + const newRot = ((oldRot + (dir === 1 ? 1 : 3)) % 4); + const newShape = dir === 1 ? rotateCW(this.active.shape) : rotateCCW(this.active.shape); + const kickKey = `${oldRot}->${newRot}`; + const kicks = this.active.type === 'I' ? KICKS_I[kickKey] : + this.active.type === 'O' ? [[0, 0]] : + KICKS_JLSTZ[kickKey]; + const test = Object.assign(Object.assign({}, this.active), { shape: newShape, rotation: newRot }); + for (const [kx, ky] of kicks) { + if (this.isValid(test, this.active.x + kx, this.active.y + ky)) { + this.active.shape = newShape; + this.active.rotation = newRot; + this.active.x += kx; + this.active.y += ky; + // Reset lock delay on successful rotation while on ground + if (this.onGround && this.lockResets < MAX_LOCK_RESETS) { + this.lockAccum = 0; + this.lockResets++; + } + return; + } + } + } + hardDrop() { + if (!this.active) + return; + let dropped = 0; + while (this.move(0, 1)) + dropped++; + // Award 2 pts per row hard-dropped (guideline bonus) + this.score += dropped * 2; + this.updateUI(); + this.lock(); + } + holdPiece() { + if (!this.active || !this.canHold) + return; + const swapType = this.heldType; + this.heldType = this.active.type; + this.canHold = false; + if (swapType === null) { + this.spawnNext(); + } + else { + const shape = SPAWN_SHAPES[swapType].map(r => [...r]); + this.active = { + type: swapType, + shape, + rotation: 0, + x: Math.floor((COLS - shape[0].length) / 2), + y: -1, + }; + if (!this.isValid(this.active, this.active.x, this.active.y)) { + this.triggerGameOver(); + return; + } + this.onGround = false; + this.lockAccum = 0; + this.lockResets = 0; + } + } + // ── Locking & line clearing ──────────────────────────────── + lock() { + if (!this.active) + return; + const { shape, x, y, type } = this.active; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const ny = y + r; + if (ny < 0 || ny >= ROWS) + continue; + this.board[ny][x + c] = COLORS[type]; + } + } + const cleared = this.clearLines(); + if (cleared > 0) { + this.score += LINE_POINTS[cleared] * this.level; + this.lines += cleared; + this.level = Math.floor(this.lines / LINES_PER_LEVEL) + 1; + this.updateUI(); + } + this.dropAccum = 0; + this.spawnNext(); + } + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every(c => c !== null)) { + this.board.splice(r, 1); + this.board.unshift(new Array(COLS).fill(null)); + cleared++; + r++; // re-check the row that just shifted down + } + } + return cleared; + } + // ── Drop speed ───────────────────────────────────────────── + /** Returns milliseconds per one-cell drop for the current level. + * Uses the Tetris guideline formula: + * seconds = (0.8 − (level−1)×0.007)^(level−1) + */ + dropInterval() { + const secs = Math.pow(0.8 - (this.level - 1) * 0.007, this.level - 1); + return Math.max(30, Math.round(secs * 1000)); + } + // ── Ghost piece ──────────────────────────────────────────── + ghostY() { + if (!this.active) + return 0; + let gy = this.active.y; + while (this.isValid(this.active, this.active.x, gy + 1)) + gy++; + return gy; + } + // ── Update loop ──────────────────────────────────────────── + update(dt) { + if (!this.active) + return; + // ── DAS left ── + if (this.keys.has('ArrowLeft')) { + const prev = this.dasLeft; + this.dasLeft += dt; + const pTick = prev < DAS_DELAY ? -1 : Math.floor((prev - DAS_DELAY) / DAS_INTERVAL); + const cTick = this.dasLeft < DAS_DELAY ? -1 : Math.floor((this.dasLeft - DAS_DELAY) / DAS_INTERVAL); + for (let t = pTick + 1; t <= cTick; t++) + this.move(-1, 0); + } + else { + this.dasLeft = 0; + } + // ── DAS right ── + if (this.keys.has('ArrowRight')) { + const prev = this.dasRight; + this.dasRight += dt; + const pTick = prev < DAS_DELAY ? -1 : Math.floor((prev - DAS_DELAY) / DAS_INTERVAL); + const cTick = this.dasRight < DAS_DELAY ? -1 : Math.floor((this.dasRight - DAS_DELAY) / DAS_INTERVAL); + for (let t = pTick + 1; t <= cTick; t++) + this.move(1, 0); + } + else { + this.dasRight = 0; + } + // ── Gravity ── + const softDrop = this.keys.has('ArrowDown'); + const interval = softDrop ? SOFT_DROP_MS : this.dropInterval(); + this.dropAccum += dt; + while (this.dropAccum >= interval) { + this.dropAccum -= interval; + if (!this.move(0, 1)) { + this.dropAccum = 0; + break; + } + } + // ── Lock delay ── + const prevOnGround = this.onGround; + this.onGround = !this.isValid(this.active, this.active.x, this.active.y + 1); + if (!prevOnGround && this.onGround) { + // Just landed — start the lock timer fresh + this.lockAccum = 0; + this.lockResets = 0; + } + if (this.onGround) { + this.lockAccum += dt; + if (this.lockAccum >= LOCK_DELAY) + this.lock(); + } + else { + this.lockAccum = 0; + } + } + // ── Main loop ────────────────────────────────────────────── + loop(ts) { + if (this.lastTs === 0) + this.lastTs = ts; + const dt = Math.min(ts - this.lastTs, 100); // cap to prevent spiral on tab-switch + this.lastTs = ts; + if (this.state === 'playing') + this.update(dt); + this.render(); + this.animId = requestAnimationFrame(t => this.loop(t)); + } + // ── Input ────────────────────────────────────────────────── + setupInput() { + document.addEventListener('keydown', e => { + if (this.keys.has(e.code)) + return; // ignore key repeat + this.keys.add(e.code); + // Always-available controls + if (e.code === 'KeyP' || e.code === 'Escape') { + this.togglePause(); + return; + } + if (e.code === 'KeyR') { + this.restart(); + return; + } + if (this.state !== 'playing') + return; + switch (e.code) { + case 'ArrowLeft': + this.dasLeft = 0; + this.move(-1, 0); + break; + case 'ArrowRight': + this.dasRight = 0; + this.move(1, 0); + break; + case 'ArrowDown': + this.move(0, 1); + this.dropAccum = 0; + break; + case 'ArrowUp': + case 'KeyX': + this.tryRotate(1); // CW + break; + case 'KeyZ': + case 'ControlLeft': + case 'ControlRight': + this.tryRotate(-1); // CCW + break; + case 'Space': + this.hardDrop(); + e.preventDefault(); + break; + case 'ShiftLeft': + case 'ShiftRight': + case 'KeyC': + this.holdPiece(); + break; + } + }); + document.addEventListener('keyup', e => { + this.keys.delete(e.code); + }); + } + // ── State transitions ────────────────────────────────────── + togglePause() { + if (this.state === 'gameover') + return; + if (this.state === 'playing') { + this.state = 'paused'; + this.overlayEl.innerHTML = ` + <div class="overlay-box"> + <h2>PAUSED</h2> + <p>Press <kbd>P</kbd> to resume</p> + <p>Press <kbd>R</kbd> to restart</p> + </div>`; + this.overlayEl.style.display = 'flex'; + } + else { + this.state = 'playing'; + this.overlayEl.style.display = 'none'; + this.lastTs = 0; // reset timestamp to avoid large dt jump + } + } + triggerGameOver() { + this.state = 'gameover'; + this.overlayEl.innerHTML = ` + <div class="overlay-box"> + <h2>GAME OVER</h2> + <p class="final-score">Score: ${this.score.toLocaleString()}</p> + <p>Level ${this.level} &nbsp;·&nbsp; ${this.lines} lines</p> + <p>Press <kbd>R</kbd> to restart</p> + </div>`; + this.overlayEl.style.display = 'flex'; + } + restart() { + this.keys.clear(); + this.initGame(); + } + updateUI() { + this.scoreEl.textContent = this.score.toLocaleString(); + this.linesEl.textContent = this.lines.toString(); + this.levelEl.textContent = this.level.toString(); + } + // ── Rendering ────────────────────────────────────────────── + /** + * Draw a single Tetris block with a simple 3-D bevel effect. + * @param alpha 0–1 global opacity (< 1 used for ghost / dimmed hold) + */ + drawBlock(ctx, px, py, size, color, alpha = 1) { + const gap = 1; // 1-px gap creates implicit grid lines + const ix = px + gap; + const iy = py + gap; + const iw = size - gap * 2; + ctx.save(); + ctx.globalAlpha = alpha; + // Main fill + ctx.fillStyle = color; + ctx.fillRect(ix, iy, iw, iw); + // Top-left highlight + ctx.fillStyle = 'rgba(255,255,255,0.28)'; + ctx.fillRect(ix, iy, iw, 4); + ctx.fillRect(ix, iy, 4, iw); + // Bottom-right shadow + ctx.fillStyle = 'rgba(0,0,0,0.35)'; + ctx.fillRect(ix, iy + iw - 4, iw, 4); + ctx.fillRect(ix + iw - 4, iy, 4, iw); + ctx.restore(); + } + renderBoard() { + const ctx = this.boardCtx; + const W = COLS * BLOCK; + const H = ROWS * BLOCK; + // Background + ctx.fillStyle = '#0d1117'; + ctx.fillRect(0, 0, W, H); + // Subtle grid lines + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let c = 1; c < COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, H); + ctx.stroke(); + } + for (let r = 1; r < ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(W, r * BLOCK); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const cell = this.board[r][c]; + if (cell) + this.drawBlock(ctx, c * BLOCK, r * BLOCK, BLOCK, cell); + } + } + if (!this.active) + return; + // Ghost piece + const gy = this.ghostY(); + if (gy !== this.active.y) { + const gc = COLORS[this.active.type]; + for (let r = 0; r < this.active.shape.length; r++) { + for (let c = 0; c < this.active.shape[r].length; c++) { + if (!this.active.shape[r][c]) + continue; + const px = (this.active.x + c) * BLOCK; + const py = (gy + r) * BLOCK; + if (gy + r < 0) + continue; + // Ghost: transparent fill + solid outline + ctx.save(); + ctx.globalAlpha = 0.18; + ctx.fillStyle = gc; + ctx.fillRect(px + 1, py + 1, BLOCK - 2, BLOCK - 2); + ctx.globalAlpha = 0.55; + ctx.strokeStyle = gc; + ctx.lineWidth = 1.5; + ctx.strokeRect(px + 1.5, py + 1.5, BLOCK - 3, BLOCK - 3); + ctx.restore(); + } + } + } + // Active piece + for (let r = 0; r < this.active.shape.length; r++) { + for (let c = 0; c < this.active.shape[r].length; c++) { + if (!this.active.shape[r][c]) + continue; + const py = (this.active.y + r) * BLOCK; + if (this.active.y + r < 0) + continue; // skip off-screen rows + this.drawBlock(ctx, (this.active.x + c) * BLOCK, py, BLOCK, COLORS[this.active.type]); + } + } + } + /** Render a piece centred inside a mini preview canvas. */ + renderMiniPiece(ctx, type, dimmed = false) { + const W = ctx.canvas.width; + const H = ctx.canvas.height; + ctx.fillStyle = '#0d1117'; + ctx.fillRect(0, 0, W, H); + if (!type) + return; + const shape = SPAWN_SHAPES[type]; + // Bounding box of non-empty cells + let minR = shape.length, maxR = -1, minC = shape[0].length, maxC = -1; + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c]) { + if (r < minR) + minR = r; + if (r > maxR) + maxR = r; + if (c < minC) + minC = c; + if (c > maxC) + maxC = c; + } + const pieceW = (maxC - minC + 1) * MINI; + const pieceH = (maxR - minR + 1) * MINI; + const offX = Math.floor((W - pieceW) / 2); + const offY = Math.floor((H - pieceH) / 2); + for (let r = minR; r <= maxR; r++) + for (let c = minC; c <= maxC; c++) + if (shape[r][c]) + this.drawBlock(ctx, offX + (c - minC) * MINI, offY + (r - minR) * MINI, MINI, COLORS[type], dimmed ? 0.35 : 1); + } + render() { + this.renderBoard(); + this.renderMiniPiece(this.nextCtx, this.nextType); + this.renderMiniPiece(this.holdCtx, this.heldType, !this.canHold); + } +} +// ─── Entry point ────────────────────────────────────────────── +window.addEventListener('DOMContentLoaded', () => { new TetrisGame(); }); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=off_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,542 @@ +"use strict"; +// ─── Constants ─────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 32; // px +const PREVIEW_BLOCK = 24; // px +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const GHOST_ALPHA = 0.25; +// Each piece defined as a set of rotation states (array of [row, col] offsets) +const PIECES = { + I: [ + [[0, 0], [0, 1], [0, 2], [0, 3]], + [[0, 2], [1, 2], [2, 2], [3, 2]], + [[2, 0], [2, 1], [2, 2], [2, 3]], + [[0, 1], [1, 1], [2, 1], [3, 1]], + ], + O: [ + [[0, 1], [0, 2], [1, 1], [1, 2]], + [[0, 1], [0, 2], [1, 1], [1, 2]], + [[0, 1], [0, 2], [1, 1], [1, 2]], + [[0, 1], [0, 2], [1, 1], [1, 2]], + ], + T: [ + [[0, 1], [1, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [1, 2], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 1]], + [[0, 1], [1, 0], [1, 1], [2, 1]], + ], + S: [ + [[0, 1], [0, 2], [1, 0], [1, 1]], + [[0, 1], [1, 1], [1, 2], [2, 2]], + [[1, 1], [1, 2], [2, 0], [2, 1]], + [[0, 0], [1, 0], [1, 1], [2, 1]], + ], + Z: [ + [[0, 0], [0, 1], [1, 1], [1, 2]], + [[0, 2], [1, 1], [1, 2], [2, 1]], + [[1, 0], [1, 1], [2, 1], [2, 2]], + [[0, 1], [1, 0], [1, 1], [2, 0]], + ], + J: [ + [[0, 0], [1, 0], [1, 1], [1, 2]], + [[0, 1], [0, 2], [1, 1], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 2]], + [[0, 1], [1, 1], [2, 0], [2, 1]], + ], + L: [ + [[0, 2], [1, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [2, 1], [2, 2]], + [[1, 0], [1, 1], [1, 2], [2, 0]], + [[0, 0], [0, 1], [1, 1], [2, 1]], + ], +}; +const PIECE_TYPES = Object.keys(PIECES); +// Wall kick data (SRS) for J, L, S, T, Z +const KICKS_JLSTZ = { + "0->1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1->0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1->2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2->1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2->3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3->2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3->0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0->3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// Wall kick data (SRS) for I +const KICKS_I = { + "0->1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1->0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1->2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2->1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2->3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3->2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3->0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0->3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// Scoring per lines cleared +const LINE_SCORES = [0, 100, 300, 500, 800]; +// Speed levels (ms per drop tick) +const LEVEL_SPEEDS = [800, 720, 630, 550, 470, 380, 300, 215, 130, 100, 80, 80, 80, 70, 70, 70, 50, 50, 50, 30]; +// ─── Game State ─────────────────────────────────────────────────────────────── +let board = []; +let current = null; +let next = null; +let score = 0; +let lines = 0; +let level = 0; +let gameOver = false; +let paused = false; +let dropTimer = 0; +let lastTime = 0; +let animFrameId = 0; +let lockDelay = 0; +let lockDelayMax = 500; // ms +let onGround = false; +let lockMoves = 0; +let lockMovesMax = 15; +// ─── Canvas Setup ───────────────────────────────────────────────────────────── +const canvas = document.getElementById("board"); +const ctx = canvas.getContext("2d"); +canvas.width = COLS * BLOCK; +canvas.height = ROWS * BLOCK; +const previewCanvas = document.getElementById("preview"); +const previewCtx = previewCanvas.getContext("2d"); +previewCanvas.width = 6 * PREVIEW_BLOCK; +previewCanvas.height = 4 * PREVIEW_BLOCK; +const scoreEl = document.getElementById("score"); +const linesEl = document.getElementById("lines"); +const levelEl = document.getElementById("level"); +const msgEl = document.getElementById("message"); +// ─── Board Helpers ──────────────────────────────────────────────────────────── +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function getBlocks(piece) { + return PIECES[piece.type][piece.rot].map(([r, c]) => [piece.row + r, piece.col + c]); +} +function isValid(piece) { + for (const [r, c] of getBlocks(piece)) { + if (r < 0 || r >= ROWS || c < 0 || c >= COLS) + return false; + if (r >= 0 && board[r][c] !== null) + return false; + } + return true; +} +function placePiece(piece) { + const color = COLORS[piece.type]; + for (const [r, c] of getBlocks(piece)) { + if (r >= 0) + board[r][c] = color; + } +} +function clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every(cell => cell !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // recheck same row index + } + } + return cleared; +} +// ─── Piece Factory ──────────────────────────────────────────────────────────── +function randomPiece() { + const type = PIECE_TYPES[Math.floor(Math.random() * PIECE_TYPES.length)]; + return { type, rot: 0, row: 0, col: 3 }; +} +function spawnPiece() { + current = next ?? randomPiece(); + next = randomPiece(); + // Center spawn + current.col = Math.floor((COLS - 4) / 2); + current.row = 0; + // Try spawning; if invalid try row -1 + if (!isValid(current)) { + current.row = -1; + if (!isValid(current)) + return false; + } + lockDelay = 0; + lockMoves = 0; + onGround = false; + return true; +} +// ─── Rotation with SRS kicks ────────────────────────────────────────────────── +function tryRotate(dir) { + if (!current) + return false; + const newRot = ((current.rot + dir) + 4) % 4; + const key = `${current.rot}->${newRot}`; + const kicks = current.type === "I" ? KICKS_I : (current.type === "O" ? null : KICKS_JLSTZ); + const testPiece = { ...current, rot: newRot }; + if (kicks) { + for (const [kr, kc] of kicks[key] ?? [[0, 0]]) { + testPiece.row = current.row + kr; + testPiece.col = current.col + kc; + if (isValid(testPiece)) { + current = { ...testPiece }; + resetLockOnMove(); + return true; + } + } + } + else { + // O piece — no kick needed + testPiece.row = current.row; + testPiece.col = current.col; + if (isValid(testPiece)) { + current = { ...testPiece }; + return true; + } + } + return false; +} +function resetLockOnMove() { + if (onGround && lockMoves < lockMovesMax) { + lockDelay = 0; + lockMoves++; + } +} +// ─── Movement ───────────────────────────────────────────────────────────────── +function moveLeft() { + if (!current || gameOver || paused) + return; + const moved = { ...current, col: current.col - 1 }; + if (isValid(moved)) { + current = moved; + resetLockOnMove(); + } +} +function moveRight() { + if (!current || gameOver || paused) + return; + const moved = { ...current, col: current.col + 1 }; + if (isValid(moved)) { + current = moved; + resetLockOnMove(); + } +} +function softDrop() { + if (!current || gameOver || paused) + return; + const moved = { ...current, row: current.row + 1 }; + if (isValid(moved)) { + current = moved; + dropTimer = 0; + score += 1; + updateUI(); + } +} +function hardDrop() { + if (!current || gameOver || paused) + return; + let dropped = 0; + while (true) { + const moved = { ...current, row: current.row + 1 }; + if (!isValid(moved)) + break; + current = moved; + dropped++; + } + score += dropped * 2; + lockPiece(); +} +function ghostRow() { + if (!current) + return 0; + let ghost = { ...current }; + while (true) { + const next = { ...ghost, row: ghost.row + 1 }; + if (!isValid(next)) + break; + ghost = next; + } + return ghost.row; +} +// ─── Piece Locking ──────────────────────────────────────────────────────────── +function lockPiece() { + if (!current) + return; + placePiece(current); + const cleared = clearLines(); + if (cleared > 0) { + score += LINE_SCORES[cleared] * (level + 1); + lines += cleared; + level = Math.min(Math.floor(lines / 10), LEVEL_SPEEDS.length - 1); + updateUI(); + } + if (!spawnPiece()) { + gameOver = true; + msgEl.textContent = "GAME OVER"; + msgEl.style.display = "block"; + } +} +// ─── Update / Game Loop ─────────────────────────────────────────────────────── +function update(timestamp) { + const dt = timestamp - lastTime; + lastTime = timestamp; + if (!gameOver && !paused && current) { + const speed = LEVEL_SPEEDS[Math.min(level, LEVEL_SPEEDS.length - 1)]; + // Check if on ground + const below = { ...current, row: current.row + 1 }; + const nowOnGround = !isValid(below); + if (nowOnGround) { + if (!onGround) { + onGround = true; + lockDelay = 0; + } + lockDelay += dt; + if (lockDelay >= lockDelayMax) { + lockPiece(); + } + } + else { + onGround = false; + lockDelay = 0; + dropTimer += dt; + if (dropTimer >= speed) { + dropTimer = 0; + current = { ...current, row: current.row + 1 }; + } + } + } + draw(); + animFrameId = requestAnimationFrame(update); +} +// ─── Drawing ────────────────────────────────────────────────────────────────── +function drawBlock(context, r, c, color, size, alpha = 1) { + context.globalAlpha = alpha; + context.fillStyle = color; + context.fillRect(c * size + 1, r * size + 1, size - 2, size - 2); + // Highlight + context.fillStyle = "rgba(255,255,255,0.3)"; + context.fillRect(c * size + 1, r * size + 1, size - 2, 4); + context.fillRect(c * size + 1, r * size + 1, 4, size - 2); + // Shadow + context.fillStyle = "rgba(0,0,0,0.3)"; + context.fillRect(c * size + 1, r * size + size - 5, size - 2, 4); + context.fillRect(c * size + size - 5, r * size + 1, 4, size - 2); + context.globalAlpha = 1; +} +function draw() { + // Board background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.05)"; + ctx.lineWidth = 1; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK, r * BLOCK, BLOCK, BLOCK); + } + } + // Placed blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c]) { + drawBlock(ctx, r, c, board[r][c], BLOCK); + } + } + } + // Ghost piece + if (current && !gameOver) { + const gr = ghostRow(); + if (gr !== current.row) { + const ghostBlocks = PIECES[current.type][current.rot]; + const color = COLORS[current.type]; + for (const [br, bc] of ghostBlocks) { + drawBlock(ctx, gr + br, current.col + bc, color, BLOCK, GHOST_ALPHA); + } + } + } + // Current piece + if (current && !gameOver) { + const color = COLORS[current.type]; + for (const [r, c] of getBlocks(current)) { + if (r >= 0) + drawBlock(ctx, r, c, color, BLOCK); + } + } + // Paused overlay + if (paused && !gameOver) { + ctx.fillStyle = "rgba(0,0,0,0.6)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px 'Courier New', monospace"; + ctx.textAlign = "center"; + ctx.fillText("PAUSED", canvas.width / 2, canvas.height / 2); + } + drawPreview(); +} +function drawPreview() { + previewCtx.fillStyle = "#111"; + previewCtx.fillRect(0, 0, previewCanvas.width, previewCanvas.height); + if (!next) + return; + const color = COLORS[next.type]; + const blocks = PIECES[next.type][0]; + // Find bounding box + const minR = Math.min(...blocks.map(([r]) => r)); + const maxR = Math.max(...blocks.map(([r]) => r)); + const minC = Math.min(...blocks.map(([, c]) => c)); + const maxC = Math.max(...blocks.map(([, c]) => c)); + const pieceH = maxR - minR + 1; + const pieceW = maxC - minC + 1; + const offsetR = Math.floor((4 - pieceH) / 2) - minR; + const offsetC = Math.floor((6 - pieceW) / 2) - minC; + for (const [br, bc] of blocks) { + drawBlock(previewCtx, br + offsetR, bc + offsetC, color, PREVIEW_BLOCK); + } +} +// ─── UI Helpers ─────────────────────────────────────────────────────────────── +function updateUI() { + scoreEl.textContent = score.toString(); + linesEl.textContent = lines.toString(); + levelEl.textContent = level.toString(); +} +// ─── Input Handling ─────────────────────────────────────────────────────────── +const keys = {}; +let dasTimer = 0; +let arrTimer = 0; +const DAS = 170; // Delayed Auto Shift ms +const ARR = 50; // Auto Repeat Rate ms +document.addEventListener("keydown", (e) => { + if (gameOver) { + if (e.code === "Enter" || e.code === "Space") { + restartGame(); + } + return; + } + if (e.code === "KeyP" || e.code === "Escape") { + paused = !paused; + msgEl.textContent = paused ? "PAUSED" : ""; + msgEl.style.display = paused ? "block" : "none"; + return; + } + if (paused) + return; + switch (e.code) { + case "ArrowLeft": + case "KeyA": + if (!keys[e.code]) { + moveLeft(); + dasTimer = 0; + } + keys[e.code] = true; + break; + case "ArrowRight": + case "KeyD": + if (!keys[e.code]) { + moveRight(); + dasTimer = 0; + } + keys[e.code] = true; + break; + case "ArrowDown": + case "KeyS": + softDrop(); + keys[e.code] = true; + break; + case "ArrowUp": + case "KeyW": + tryRotate(1); + e.preventDefault(); + break; + case "KeyZ": + tryRotate(-1); + break; + case "KeyX": + tryRotate(1); + break; + case "Space": + hardDrop(); + e.preventDefault(); + break; + case "KeyC": + // hold piece could be added; for now just prevent default + break; + } +}); +document.addEventListener("keyup", (e) => { + keys[e.code] = false; + if (e.code === "ArrowLeft" || e.code === "KeyA" || e.code === "ArrowRight" || e.code === "KeyD") { + dasTimer = 0; + arrTimer = 0; + } +}); +// DAS/ARR loop - run in the main update loop via separate interval +let dasLastTime = 0; +function dasLoop(timestamp) { + const dt = timestamp - dasLastTime; + dasLastTime = timestamp; + if (!paused && !gameOver) { + const leftHeld = keys["ArrowLeft"] || keys["KeyA"]; + const rightHeld = keys["ArrowRight"] || keys["KeyD"]; + const downHeld = keys["ArrowDown"] || keys["KeyS"]; + if (leftHeld || rightHeld) { + dasTimer += dt; + if (dasTimer >= DAS) { + arrTimer += dt; + if (arrTimer >= ARR) { + arrTimer = 0; + if (leftHeld) + moveLeft(); + if (rightHeld) + moveRight(); + } + } + } + if (downHeld) { + softDrop(); + } + } + requestAnimationFrame(dasLoop); +} +// ─── Game Init / Restart ────────────────────────────────────────────────────── +function startGame() { + board = createBoard(); + score = 0; + lines = 0; + level = 0; + gameOver = false; + paused = false; + dropTimer = 0; + lockDelay = 0; + lockMoves = 0; + onGround = false; + next = randomPiece(); + spawnPiece(); + updateUI(); + msgEl.style.display = "none"; +} +function restartGame() { + cancelAnimationFrame(animFrameId); + startGame(); + lastTime = performance.now(); + animFrameId = requestAnimationFrame(update); +} +// ─── Button Controls ────────────────────────────────────────────────────────── +document.getElementById("btn-left")?.addEventListener("click", moveLeft); +document.getElementById("btn-right")?.addEventListener("click", moveRight); +document.getElementById("btn-rotate")?.addEventListener("click", () => tryRotate(1)); +document.getElementById("btn-down")?.addEventListener("click", softDrop); +document.getElementById("btn-drop")?.addEventListener("click", hardDrop); +document.getElementById("btn-restart")?.addEventListener("click", restartGame); +// ─── Boot ───────────────────────────────────────────────────────────────────── +startGame(); +lastTime = performance.now(); +dasLastTime = performance.now(); +animFrameId = requestAnimationFrame(update); +requestAnimationFrame(dasLoop); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/game.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/game.d.ts @@ -0,0 +1,26 @@ +import { TetrominoType, Piece, GameState, GameAction } from './types'; +export declare class TetrisGame { + private state; + constructor(); + private initializeGameState; + private getRandomTetromino; + private createNewPiece; + getState(): GameState; + update(deltaTime: number): void; + handleAction(action: GameAction): void; + private moveLeft; + private moveRight; + private moveDown; + private hardDrop; + private rotate; + private canMove; + private isValidPosition; + private lockPiece; + private clearLines; + private updateLevel; + private spawnNewPiece; + getBoard(): number[][]; + getCurrentPiece(): Piece; + getNextPiece(): TetrominoType; + getGhostPiecePosition(): number; +} diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/game.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/game.js @@ -0,0 +1,226 @@ +import { COLS, ROWS, TetrominoType, TETROMINO_SHAPES, GameAction, } from './types'; +export class TetrisGame { + constructor() { + this.state = this.initializeGameState(); + } + initializeGameState() { + return { + board: Array(ROWS).fill(null).map(() => Array(COLS).fill(0)), + currentPiece: this.createNewPiece(), + nextPiece: this.getRandomTetromino(), + score: 0, + lines: 0, + level: 1, + gameOver: false, + paused: false, + dropCounter: 0, + dropInterval: 1000, + }; + } + getRandomTetromino() { + const types = Object.values(TetrominoType); + return types[Math.floor(Math.random() * types.length)]; + } + createNewPiece() { + return { + type: this.state.nextPiece, + x: Math.floor(COLS / 2) - 1, + y: 0, + rotationIndex: 0, + }; + } + getState() { + return this.state; + } + update(deltaTime) { + if (this.state.gameOver || this.state.paused) { + return; + } + this.state.dropCounter += deltaTime; + if (this.state.dropCounter >= this.state.dropInterval) { + this.moveDown(); + this.state.dropCounter = 0; + } + } + handleAction(action) { + switch (action) { + case GameAction.MOVE_LEFT: + this.moveLeft(); + break; + case GameAction.MOVE_RIGHT: + this.moveRight(); + break; + case GameAction.MOVE_DOWN: + this.moveDown(); + break; + case GameAction.ROTATE: + this.rotate(); + break; + case GameAction.DROP: + this.hardDrop(); + break; + case GameAction.PAUSE: + if (!this.state.paused) { + this.state.paused = true; + } + break; + case GameAction.RESUME: + if (this.state.paused) { + this.state.paused = false; + } + break; + case GameAction.RESET: + this.state = this.initializeGameState(); + break; + } + } + moveLeft() { + if (this.canMove(-1, 0)) { + this.state.currentPiece.x--; + } + } + moveRight() { + if (this.canMove(1, 0)) { + this.state.currentPiece.x++; + } + } + moveDown() { + if (this.canMove(0, 1)) { + this.state.currentPiece.y++; + } + else { + this.lockPiece(); + this.clearLines(); + this.spawnNewPiece(); + } + } + hardDrop() { + while (this.canMove(0, 1)) { + this.state.currentPiece.y++; + } + this.lockPiece(); + this.clearLines(); + this.spawnNewPiece(); + } + rotate() { + const piece = this.state.currentPiece; + const shape = TETROMINO_SHAPES[piece.type]; + const nextRotationIndex = (piece.rotationIndex + 1) % shape.length; + const currentRotation = piece.rotationIndex; + piece.rotationIndex = nextRotationIndex; + if (!this.isValidPosition(piece)) { + piece.rotationIndex = currentRotation; + } + } + canMove(dx, dy) { + const piece = this.state.currentPiece; + return this.isValidPosition({ + ...piece, + x: piece.x + dx, + y: piece.y + dy, + }); + } + isValidPosition(piece) { + const shape = TETROMINO_SHAPES[piece.type][piece.rotationIndex]; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 0) + continue; + const boardX = piece.x + col; + const boardY = piece.y + row; + // Check boundaries + if (boardX < 0 || boardX >= COLS || boardY >= ROWS) { + return false; + } + // Check collision with existing blocks + if (boardY >= 0 && this.state.board[boardY][boardX] !== 0) { + return false; + } + } + } + return true; + } + lockPiece() { + const piece = this.state.currentPiece; + const shape = TETROMINO_SHAPES[piece.type][piece.rotationIndex]; + const colorIndex = Object.values(TetrominoType).indexOf(piece.type) + 1; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 0) + continue; + const boardX = piece.x + col; + const boardY = piece.y + row; + if (boardY >= 0 && boardY < ROWS && boardX >= 0 && boardX < COLS) { + this.state.board[boardY][boardX] = colorIndex; + } + else if (boardY < 0) { + // Game over - piece spawned above the board + this.state.gameOver = true; + } + } + } + } + clearLines() { + let linesCleared = 0; + for (let row = ROWS - 1; row >= 0; row--) { + if (this.state.board[row].every((cell) => cell !== 0)) { + // Clear this row + this.state.board.splice(row, 1); + this.state.board.unshift(Array(COLS).fill(0)); + linesCleared++; + row++; // Check this row again + } + } + if (linesCleared > 0) { + this.state.lines += linesCleared; + const baseScore = [40, 100, 300, 1200]; + const points = baseScore[linesCleared - 1] || 0; + this.state.score += points * (this.state.level); + this.updateLevel(); + } + } + updateLevel() { + const newLevel = Math.floor(this.state.lines / 10) + 1; + if (newLevel !== this.state.level) { + this.state.level = newLevel; + // Increase speed: decrease interval by ~10% per level + this.state.dropInterval = Math.max(100, 1000 - (this.state.level - 1) * 50); + } + } + spawnNewPiece() { + if (this.state.gameOver) { + return; + } + this.state.currentPiece = { + type: this.state.nextPiece, + x: Math.floor(COLS / 2) - 1, + y: 0, + rotationIndex: 0, + }; + this.state.nextPiece = this.getRandomTetromino(); + // Check if the new piece can be placed + if (!this.isValidPosition(this.state.currentPiece)) { + this.state.gameOver = true; + } + } + getBoard() { + return this.state.board; + } + getCurrentPiece() { + return this.state.currentPiece; + } + getNextPiece() { + return this.state.nextPiece; + } + getGhostPiecePosition() { + let ghostY = this.state.currentPiece.y; + const originalY = this.state.currentPiece.y; + while (this.isValidPosition({ + ...this.state.currentPiece, + y: ghostY + 1, + })) { + ghostY++; + } + return ghostY; + } +} diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/index.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/index.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/index.js @@ -0,0 +1,81 @@ +import { TetrisGame } from './game'; +import { Renderer } from './renderer'; +import { UIController } from './ui'; +import { GameAction } from './types'; +class TetrisApplication { + constructor() { + this.lastTime = Date.now(); + this.gameRunning = false; + this.gameLoop = () => { + const currentTime = Date.now(); + const deltaTime = currentTime - this.lastTime; + this.lastTime = currentTime; + if (this.gameRunning) { + this.game.update(deltaTime); + const state = this.game.getState(); + this.ui.updateScore(state.score); + this.ui.updateLevel(state.level); + this.ui.updateLines(state.lines); + this.renderer.renderNextPiece(state.nextPiece); + if (state.gameOver) { + this.gameRunning = false; + this.ui.showGameOverStatus(); + this.ui.disableGameControls(); + } + } + this.render(); + requestAnimationFrame(this.gameLoop); + }; + this.game = new TetrisGame(); + this.renderer = new Renderer('gameCanvas', 'nextPieceCanvas'); + this.ui = new UIController(); + this.setupUI(); + this.render(); + } + setupUI() { + this.ui.onAction((action) => { + this.game.handleAction(action); + // Update UI based on game state + const state = this.game.getState(); + this.ui.updateScore(state.score); + this.ui.updateLevel(state.level); + this.ui.updateLines(state.lines); + if (state.gameOver) { + this.gameRunning = false; + this.ui.showGameOverStatus(); + this.ui.disableGameControls(); + } + else if (state.paused) { + this.gameRunning = false; + this.ui.showPausedStatus(); + } + else if (action === GameAction.RESUME) { + this.gameRunning = true; + this.ui.clearStatus(); + this.ui.enableGameControls(); + } + else if (action === GameAction.RESET) { + this.game = new TetrisGame(); + this.gameRunning = false; + this.ui.clearStatus(); + this.ui.setStartButtonState(false); + } + }); + // Initial render + this.renderer.renderNextPiece(this.game.getNextPiece()); + } + render() { + const state = this.game.getState(); + const ghostY = this.game.getGhostPiecePosition(); + this.renderer.render(this.game.getBoard(), this.game.getCurrentPiece(), ghostY, state.gameOver); + } + start() { + this.lastTime = Date.now(); + requestAnimationFrame(this.gameLoop); + } +} +// Initialize the game when the DOM is ready +document.addEventListener('DOMContentLoaded', () => { + const app = new TetrisApplication(); + app.start(); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/renderer.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/renderer.d.ts @@ -0,0 +1,17 @@ +import { TetrominoType, Piece } from './types'; +export declare class Renderer { + private canvas; + private context; + private nextPieceCanvas; + private nextPieceContext; + constructor(canvasId: string, nextPieceCanvasId: string); + render(board: number[][], currentPiece: Piece, ghostY: number, gameOver: boolean): void; + renderNextPiece(nextPieceType: TetrominoType): void; + private clearCanvas; + private drawBoard; + private drawCurrentPiece; + private drawGhost; + private drawBlock; + private drawGameOver; + private getTetrominoByColorIndex; +} diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/renderer.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/renderer.js @@ -0,0 +1,126 @@ +import { COLS, ROWS, BLOCK_SIZE, TetrominoType, TETROMINO_SHAPES, TETROMINO_COLORS, } from './types'; +export class Renderer { + constructor(canvasId, nextPieceCanvasId) { + this.canvas = document.getElementById(canvasId); + this.context = this.canvas.getContext('2d'); + this.nextPieceCanvas = document.getElementById(nextPieceCanvasId); + this.nextPieceContext = this.nextPieceCanvas.getContext('2d'); + } + render(board, currentPiece, ghostY, gameOver) { + this.clearCanvas(); + this.drawBoard(board); + this.drawGhost(currentPiece, ghostY); + this.drawCurrentPiece(currentPiece); + if (gameOver) { + this.drawGameOver(); + } + } + renderNextPiece(nextPieceType) { + const context = this.nextPieceContext; + context.fillStyle = '#f9f9f9'; + context.fillRect(0, 0, this.nextPieceCanvas.width, this.nextPieceCanvas.height); + const shape = TETROMINO_SHAPES[nextPieceType][0]; + const color = TETROMINO_COLORS[nextPieceType]; + // Calculate position to center the piece + const pieceWidth = shape[0].length * 20; + const pieceHeight = shape.length * 20; + const startX = (this.nextPieceCanvas.width - pieceWidth) / 2; + const startY = (this.nextPieceCanvas.height - pieceHeight) / 2; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 1) { + context.fillStyle = color; + context.fillRect(startX + col * 20 + 1, startY + row * 20 + 1, 18, 18); + context.strokeStyle = '#000'; + context.lineWidth = 1; + context.strokeRect(startX + col * 20 + 1, startY + row * 20 + 1, 18, 18); + } + } + } + } + clearCanvas() { + this.context.fillStyle = '#000'; + this.context.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid + this.context.strokeStyle = 'rgba(255, 255, 255, 0.1)'; + this.context.lineWidth = 0.5; + for (let row = 0; row <= ROWS; row++) { + this.context.beginPath(); + this.context.moveTo(0, row * BLOCK_SIZE); + this.context.lineTo(COLS * BLOCK_SIZE, row * BLOCK_SIZE); + this.context.stroke(); + } + for (let col = 0; col <= COLS; col++) { + this.context.beginPath(); + this.context.moveTo(col * BLOCK_SIZE, 0); + this.context.lineTo(col * BLOCK_SIZE, ROWS * BLOCK_SIZE); + this.context.stroke(); + } + } + drawBoard(board) { + for (let row = 0; row < board.length; row++) { + for (let col = 0; col < board[row].length; col++) { + if (board[row][col] !== 0) { + const tetromino = this.getTetrominoByColorIndex(board[row][col]); + const color = TETROMINO_COLORS[tetromino]; + this.drawBlock(col, row, color, true); + } + } + } + } + drawCurrentPiece(piece) { + const shape = TETROMINO_SHAPES[piece.type][piece.rotationIndex]; + const color = TETROMINO_COLORS[piece.type]; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 1) { + this.drawBlock(piece.x + col, piece.y + row, color, true); + } + } + } + } + drawGhost(piece, ghostY) { + const shape = TETROMINO_SHAPES[piece.type][piece.rotationIndex]; + const color = TETROMINO_COLORS[piece.type]; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 1) { + this.drawBlock(piece.x + col, ghostY + row, color, false); + } + } + } + } + drawBlock(col, row, color, filled = true) { + const x = col * BLOCK_SIZE; + const y = row * BLOCK_SIZE; + if (filled) { + this.context.fillStyle = color; + this.context.fillRect(x + 1, y + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + } + else { + // Ghost piece (transparent outline) + this.context.strokeStyle = color; + this.context.globalAlpha = 0.3; + this.context.lineWidth = 2; + this.context.strokeRect(x + 1, y + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + this.context.globalAlpha = 1; + } + // Block border + this.context.strokeStyle = filled ? 'rgba(0, 0, 0, 0.3)' : color; + this.context.lineWidth = 1; + this.context.strokeRect(x + 1, y + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + } + drawGameOver() { + this.context.fillStyle = 'rgba(0, 0, 0, 0.7)'; + this.context.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.context.fillStyle = '#fff'; + this.context.font = 'bold 30px Arial'; + this.context.textAlign = 'center'; + this.context.textBaseline = 'middle'; + this.context.fillText('GAME OVER', this.canvas.width / 2, this.canvas.height / 2); + } + getTetrominoByColorIndex(index) { + const types = Object.values(TetrominoType); + return types[index - 1] || TetrominoType.I; + } +} diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.js @@ -0,0 +1,595 @@ +"use strict"; +(() => { + // src/types.ts + var COLS = 10; + var ROWS = 20; + var BLOCK_SIZE = 20; + var TetrominoType = /* @__PURE__ */ ((TetrominoType2) => { + TetrominoType2["I"] = "I"; + TetrominoType2["O"] = "O"; + TetrominoType2["T"] = "T"; + TetrominoType2["S"] = "S"; + TetrominoType2["Z"] = "Z"; + TetrominoType2["J"] = "J"; + TetrominoType2["L"] = "L"; + return TetrominoType2; + })(TetrominoType || {}); + var TETROMINO_COLORS = { + ["I" /* I */]: "#00f0f0", + // Cyan + ["O" /* O */]: "#f0f000", + // Yellow + ["T" /* T */]: "#a000f0", + // Purple + ["S" /* S */]: "#00f000", + // Green + ["Z" /* Z */]: "#f00000", + // Red + ["J" /* J */]: "#0000f0", + // Blue + ["L" /* L */]: "#f0a000" + // Orange + }; + var TETROMINO_SHAPES = { + ["I" /* I */]: [ + [[1], [1], [1], [1]], + [[1, 1, 1, 1]] + ], + ["O" /* O */]: [ + [[1, 1], [1, 1]] + ], + ["T" /* T */]: [ + [[0, 1, 0], [1, 1, 1]], + [[1, 0], [1, 1], [1, 0]], + [[1, 1, 1], [0, 1, 0]], + [[0, 1], [1, 1], [0, 1]] + ], + ["S" /* S */]: [ + [[0, 1, 1], [1, 1, 0]], + [[1, 0], [1, 1], [0, 1]] + ], + ["Z" /* Z */]: [ + [[1, 1, 0], [0, 1, 1]], + [[0, 1], [1, 1], [1, 0]] + ], + ["J" /* J */]: [ + [[1, 0, 0], [1, 1, 1]], + [[1, 1], [1, 0], [1, 0]], + [[1, 1, 1], [0, 0, 1]], + [[0, 1], [0, 1], [1, 1]] + ], + ["L" /* L */]: [ + [[0, 0, 1], [1, 1, 1]], + [[1, 0], [1, 0], [1, 1]], + [[1, 1, 1], [1, 0, 0]], + [[1, 1], [0, 1], [0, 1]] + ] + }; + + // src/game.ts + var TetrisGame = class { + constructor() { + this.state = this.initializeGameState(); + } + initializeGameState() { + return { + board: Array(ROWS).fill(null).map(() => Array(COLS).fill(0)), + currentPiece: this.createNewPiece(), + nextPiece: this.getRandomTetromino(), + score: 0, + lines: 0, + level: 1, + gameOver: false, + paused: false, + dropCounter: 0, + dropInterval: 1e3 + }; + } + getRandomTetromino() { + const types = Object.values(TetrominoType); + return types[Math.floor(Math.random() * types.length)]; + } + createNewPiece() { + return { + type: this.state.nextPiece, + x: Math.floor(COLS / 2) - 1, + y: 0, + rotationIndex: 0 + }; + } + getState() { + return this.state; + } + update(deltaTime) { + if (this.state.gameOver || this.state.paused) { + return; + } + this.state.dropCounter += deltaTime; + if (this.state.dropCounter >= this.state.dropInterval) { + this.moveDown(); + this.state.dropCounter = 0; + } + } + handleAction(action) { + switch (action) { + case "MOVE_LEFT" /* MOVE_LEFT */: + this.moveLeft(); + break; + case "MOVE_RIGHT" /* MOVE_RIGHT */: + this.moveRight(); + break; + case "MOVE_DOWN" /* MOVE_DOWN */: + this.moveDown(); + break; + case "ROTATE" /* ROTATE */: + this.rotate(); + break; + case "DROP" /* DROP */: + this.hardDrop(); + break; + case "PAUSE" /* PAUSE */: + if (!this.state.paused) { + this.state.paused = true; + } + break; + case "RESUME" /* RESUME */: + if (this.state.paused) { + this.state.paused = false; + } + break; + case "RESET" /* RESET */: + this.state = this.initializeGameState(); + break; + } + } + moveLeft() { + if (this.canMove(-1, 0)) { + this.state.currentPiece.x--; + } + } + moveRight() { + if (this.canMove(1, 0)) { + this.state.currentPiece.x++; + } + } + moveDown() { + if (this.canMove(0, 1)) { + this.state.currentPiece.y++; + } else { + this.lockPiece(); + this.clearLines(); + this.spawnNewPiece(); + } + } + hardDrop() { + while (this.canMove(0, 1)) { + this.state.currentPiece.y++; + } + this.lockPiece(); + this.clearLines(); + this.spawnNewPiece(); + } + rotate() { + const piece = this.state.currentPiece; + const shape = TETROMINO_SHAPES[piece.type]; + const nextRotationIndex = (piece.rotationIndex + 1) % shape.length; + const currentRotation = piece.rotationIndex; + piece.rotationIndex = nextRotationIndex; + if (!this.isValidPosition(piece)) { + piece.rotationIndex = currentRotation; + } + } + canMove(dx, dy) { + const piece = this.state.currentPiece; + return this.isValidPosition({ + ...piece, + x: piece.x + dx, + y: piece.y + dy + }); + } + isValidPosition(piece) { + const shape = TETROMINO_SHAPES[piece.type][piece.rotationIndex]; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 0) continue; + const boardX = piece.x + col; + const boardY = piece.y + row; + if (boardX < 0 || boardX >= COLS || boardY >= ROWS) { + return false; + } + if (boardY >= 0 && this.state.board[boardY][boardX] !== 0) { + return false; + } + } + } + return true; + } + lockPiece() { + const piece = this.state.currentPiece; + const shape = TETROMINO_SHAPES[piece.type][piece.rotationIndex]; + const colorIndex = Object.values(TetrominoType).indexOf(piece.type) + 1; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 0) continue; + const boardX = piece.x + col; + const boardY = piece.y + row; + if (boardY >= 0 && boardY < ROWS && boardX >= 0 && boardX < COLS) { + this.state.board[boardY][boardX] = colorIndex; + } else if (boardY < 0) { + this.state.gameOver = true; + } + } + } + } + clearLines() { + let linesCleared = 0; + for (let row = ROWS - 1; row >= 0; row--) { + if (this.state.board[row].every((cell) => cell !== 0)) { + this.state.board.splice(row, 1); + this.state.board.unshift(Array(COLS).fill(0)); + linesCleared++; + row++; + } + } + if (linesCleared > 0) { + this.state.lines += linesCleared; + const baseScore = [40, 100, 300, 1200]; + const points = baseScore[linesCleared - 1] || 0; + this.state.score += points * this.state.level; + this.updateLevel(); + } + } + updateLevel() { + const newLevel = Math.floor(this.state.lines / 10) + 1; + if (newLevel !== this.state.level) { + this.state.level = newLevel; + this.state.dropInterval = Math.max(100, 1e3 - (this.state.level - 1) * 50); + } + } + spawnNewPiece() { + if (this.state.gameOver) { + return; + } + this.state.currentPiece = { + type: this.state.nextPiece, + x: Math.floor(COLS / 2) - 1, + y: 0, + rotationIndex: 0 + }; + this.state.nextPiece = this.getRandomTetromino(); + if (!this.isValidPosition(this.state.currentPiece)) { + this.state.gameOver = true; + } + } + getBoard() { + return this.state.board; + } + getCurrentPiece() { + return this.state.currentPiece; + } + getNextPiece() { + return this.state.nextPiece; + } + getGhostPiecePosition() { + let ghostY = this.state.currentPiece.y; + const originalY = this.state.currentPiece.y; + while (this.isValidPosition({ + ...this.state.currentPiece, + y: ghostY + 1 + })) { + ghostY++; + } + return ghostY; + } + }; + + // src/renderer.ts + var Renderer = class { + constructor(canvasId, nextPieceCanvasId) { + this.canvas = document.getElementById(canvasId); + this.context = this.canvas.getContext("2d"); + this.nextPieceCanvas = document.getElementById(nextPieceCanvasId); + this.nextPieceContext = this.nextPieceCanvas.getContext("2d"); + } + render(board, currentPiece, ghostY, gameOver) { + this.clearCanvas(); + this.drawBoard(board); + this.drawGhost(currentPiece, ghostY); + this.drawCurrentPiece(currentPiece); + if (gameOver) { + this.drawGameOver(); + } + } + renderNextPiece(nextPieceType) { + const context = this.nextPieceContext; + context.fillStyle = "#f9f9f9"; + context.fillRect(0, 0, this.nextPieceCanvas.width, this.nextPieceCanvas.height); + const shape = TETROMINO_SHAPES[nextPieceType][0]; + const color = TETROMINO_COLORS[nextPieceType]; + const pieceWidth = shape[0].length * 20; + const pieceHeight = shape.length * 20; + const startX = (this.nextPieceCanvas.width - pieceWidth) / 2; + const startY = (this.nextPieceCanvas.height - pieceHeight) / 2; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 1) { + context.fillStyle = color; + context.fillRect( + startX + col * 20 + 1, + startY + row * 20 + 1, + 18, + 18 + ); + context.strokeStyle = "#000"; + context.lineWidth = 1; + context.strokeRect( + startX + col * 20 + 1, + startY + row * 20 + 1, + 18, + 18 + ); + } + } + } + } + clearCanvas() { + this.context.fillStyle = "#000"; + this.context.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.context.strokeStyle = "rgba(255, 255, 255, 0.1)"; + this.context.lineWidth = 0.5; + for (let row = 0; row <= ROWS; row++) { + this.context.beginPath(); + this.context.moveTo(0, row * BLOCK_SIZE); + this.context.lineTo(COLS * BLOCK_SIZE, row * BLOCK_SIZE); + this.context.stroke(); + } + for (let col = 0; col <= COLS; col++) { + this.context.beginPath(); + this.context.moveTo(col * BLOCK_SIZE, 0); + this.context.lineTo(col * BLOCK_SIZE, ROWS * BLOCK_SIZE); + this.context.stroke(); + } + } + drawBoard(board) { + for (let row = 0; row < board.length; row++) { + for (let col = 0; col < board[row].length; col++) { + if (board[row][col] !== 0) { + const tetromino = this.getTetrominoByColorIndex(board[row][col]); + const color = TETROMINO_COLORS[tetromino]; + this.drawBlock(col, row, color, true); + } + } + } + } + drawCurrentPiece(piece) { + const shape = TETROMINO_SHAPES[piece.type][piece.rotationIndex]; + const color = TETROMINO_COLORS[piece.type]; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 1) { + this.drawBlock(piece.x + col, piece.y + row, color, true); + } + } + } + } + drawGhost(piece, ghostY) { + const shape = TETROMINO_SHAPES[piece.type][piece.rotationIndex]; + const color = TETROMINO_COLORS[piece.type]; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 1) { + this.drawBlock(piece.x + col, ghostY + row, color, false); + } + } + } + } + drawBlock(col, row, color, filled = true) { + const x = col * BLOCK_SIZE; + const y = row * BLOCK_SIZE; + if (filled) { + this.context.fillStyle = color; + this.context.fillRect(x + 1, y + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + } else { + this.context.strokeStyle = color; + this.context.globalAlpha = 0.3; + this.context.lineWidth = 2; + this.context.strokeRect(x + 1, y + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + this.context.globalAlpha = 1; + } + this.context.strokeStyle = filled ? "rgba(0, 0, 0, 0.3)" : color; + this.context.lineWidth = 1; + this.context.strokeRect(x + 1, y + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + } + drawGameOver() { + this.context.fillStyle = "rgba(0, 0, 0, 0.7)"; + this.context.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.context.fillStyle = "#fff"; + this.context.font = "bold 30px Arial"; + this.context.textAlign = "center"; + this.context.textBaseline = "middle"; + this.context.fillText("GAME OVER", this.canvas.width / 2, this.canvas.height / 2); + } + getTetrominoByColorIndex(index) { + const types = Object.values(TetrominoType); + return types[index - 1] || "I" /* I */; + } + }; + + // src/ui.ts + var UIController = class { + constructor() { + this.onActionCallback = null; + this.scoreElement = document.getElementById("score"); + this.levelElement = document.getElementById("level"); + this.linesElement = document.getElementById("lines"); + this.statusElement = document.getElementById("status"); + this.startBtn = document.getElementById("startBtn"); + this.pauseBtn = document.getElementById("pauseBtn"); + this.resetBtn = document.getElementById("resetBtn"); + this.setupEventListeners(); + } + setupEventListeners() { + this.startBtn.addEventListener("click", () => { + this.onActionCallback?.("RESUME" /* RESUME */); + this.setStartButtonState(false); + }); + this.pauseBtn.addEventListener("click", () => { + this.onActionCallback?.("PAUSE" /* PAUSE */); + this.setStartButtonState(true); + }); + this.resetBtn.addEventListener("click", () => { + this.onActionCallback?.("RESET" /* RESET */); + this.clearStatus(); + this.setStartButtonState(false); + }); + document.addEventListener("keydown", (e) => this.handleKeyDown(e)); + } + handleKeyDown(event) { + switch (event.key) { + case "ArrowLeft": + event.preventDefault(); + this.onActionCallback?.("MOVE_LEFT" /* MOVE_LEFT */); + break; + case "ArrowRight": + event.preventDefault(); + this.onActionCallback?.("MOVE_RIGHT" /* MOVE_RIGHT */); + break; + case "ArrowDown": + event.preventDefault(); + this.onActionCallback?.("MOVE_DOWN" /* MOVE_DOWN */); + break; + case "z": + case "Z": + case "ArrowUp": + event.preventDefault(); + this.onActionCallback?.("ROTATE" /* ROTATE */); + break; + case " ": + event.preventDefault(); + this.onActionCallback?.("DROP" /* DROP */); + break; + } + } + onAction(callback) { + this.onActionCallback = callback; + } + updateScore(score) { + this.scoreElement.textContent = score.toString(); + } + updateLevel(level) { + this.levelElement.textContent = level.toString(); + } + updateLines(lines) { + this.linesElement.textContent = lines.toString(); + } + showPausedStatus() { + this.statusElement.textContent = "\u23F8 PAUSED"; + this.statusElement.classList.remove("game-over"); + this.statusElement.classList.add("active", "paused"); + } + showGameOverStatus() { + this.statusElement.textContent = "\u{1F480} GAME OVER"; + this.statusElement.classList.remove("paused"); + this.statusElement.classList.add("active", "game-over"); + } + clearStatus() { + this.statusElement.classList.remove("active", "paused", "game-over"); + this.statusElement.textContent = ""; + } + setStartButtonState(show) { + if (show) { + this.startBtn.textContent = "Resume"; + this.startBtn.style.display = "block"; + this.pauseBtn.style.display = "none"; + } else { + this.startBtn.textContent = "Start Game"; + this.startBtn.style.display = "none"; + this.pauseBtn.style.display = "block"; + } + } + disableGameControls() { + this.pauseBtn.disabled = true; + } + enableGameControls() { + this.pauseBtn.disabled = false; + } + }; + + // src/index.ts + var TetrisApplication = class { + constructor() { + this.lastTime = Date.now(); + this.gameRunning = false; + this.gameLoop = () => { + const currentTime = Date.now(); + const deltaTime = currentTime - this.lastTime; + this.lastTime = currentTime; + if (this.gameRunning) { + this.game.update(deltaTime); + const state = this.game.getState(); + this.ui.updateScore(state.score); + this.ui.updateLevel(state.level); + this.ui.updateLines(state.lines); + this.renderer.renderNextPiece(state.nextPiece); + if (state.gameOver) { + this.gameRunning = false; + this.ui.showGameOverStatus(); + this.ui.disableGameControls(); + } + } + this.render(); + requestAnimationFrame(this.gameLoop); + }; + this.game = new TetrisGame(); + this.renderer = new Renderer("gameCanvas", "nextPieceCanvas"); + this.ui = new UIController(); + this.setupUI(); + this.render(); + } + setupUI() { + this.ui.onAction((action) => { + this.game.handleAction(action); + const state = this.game.getState(); + this.ui.updateScore(state.score); + this.ui.updateLevel(state.level); + this.ui.updateLines(state.lines); + if (state.gameOver) { + this.gameRunning = false; + this.ui.showGameOverStatus(); + this.ui.disableGameControls(); + } else if (state.paused) { + this.gameRunning = false; + this.ui.showPausedStatus(); + } else if (action === "RESUME" /* RESUME */) { + this.gameRunning = true; + this.ui.clearStatus(); + this.ui.enableGameControls(); + } else if (action === "RESET" /* RESET */) { + this.game = new TetrisGame(); + this.gameRunning = false; + this.ui.clearStatus(); + this.ui.setStartButtonState(false); + } + }); + this.renderer.renderNextPiece(this.game.getNextPiece()); + } + render() { + const state = this.game.getState(); + const ghostY = this.game.getGhostPiecePosition(); + this.renderer.render( + this.game.getBoard(), + this.game.getCurrentPiece(), + ghostY, + state.gameOver + ); + } + start() { + this.lastTime = Date.now(); + requestAnimationFrame(this.gameLoop); + } + }; + document.addEventListener("DOMContentLoaded", () => { + const app = new TetrisApplication(); + app.start(); + }); +})(); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/types.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/types.d.ts @@ -0,0 +1,42 @@ +export declare const COLS = 10; +export declare const ROWS = 20; +export declare const BLOCK_SIZE = 20; +export declare enum TetrominoType { + I = "I", + O = "O", + T = "T", + S = "S", + Z = "Z", + J = "J", + L = "L" +} +export declare const TETROMINO_COLORS: Record<TetrominoType, string>; +export declare const TETROMINO_SHAPES: Record<TetrominoType, number[][][]>; +export interface Piece { + type: TetrominoType; + x: number; + y: number; + rotationIndex: number; +} +export interface GameState { + board: number[][]; + currentPiece: Piece; + nextPiece: TetrominoType; + score: number; + lines: number; + level: number; + gameOver: boolean; + paused: boolean; + dropCounter: number; + dropInterval: number; +} +export declare enum GameAction { + MOVE_LEFT = "MOVE_LEFT", + MOVE_RIGHT = "MOVE_RIGHT", + MOVE_DOWN = "MOVE_DOWN", + ROTATE = "ROTATE", + DROP = "DROP", + PAUSE = "PAUSE", + RESUME = "RESUME", + RESET = "RESET" +} diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/types.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/types.js @@ -0,0 +1,72 @@ +// Game constants +export const COLS = 10; +export const ROWS = 20; +export const BLOCK_SIZE = 20; +// Tetromino types +export var TetrominoType; +(function (TetrominoType) { + TetrominoType["I"] = "I"; + TetrominoType["O"] = "O"; + TetrominoType["T"] = "T"; + TetrominoType["S"] = "S"; + TetrominoType["Z"] = "Z"; + TetrominoType["J"] = "J"; + TetrominoType["L"] = "L"; +})(TetrominoType || (TetrominoType = {})); +// Colors for each tetromino type +export const TETROMINO_COLORS = { + [TetrominoType.I]: '#00f0f0', // Cyan + [TetrominoType.O]: '#f0f000', // Yellow + [TetrominoType.T]: '#a000f0', // Purple + [TetrominoType.S]: '#00f000', // Green + [TetrominoType.Z]: '#f00000', // Red + [TetrominoType.J]: '#0000f0', // Blue + [TetrominoType.L]: '#f0a000', // Orange +}; +// Tetromino shapes (rotations) +export const TETROMINO_SHAPES = { + [TetrominoType.I]: [ + [[1], [1], [1], [1]], + [[1, 1, 1, 1]], + ], + [TetrominoType.O]: [ + [[1, 1], [1, 1]], + ], + [TetrominoType.T]: [ + [[0, 1, 0], [1, 1, 1]], + [[1, 0], [1, 1], [1, 0]], + [[1, 1, 1], [0, 1, 0]], + [[0, 1], [1, 1], [0, 1]], + ], + [TetrominoType.S]: [ + [[0, 1, 1], [1, 1, 0]], + [[1, 0], [1, 1], [0, 1]], + ], + [TetrominoType.Z]: [ + [[1, 1, 0], [0, 1, 1]], + [[0, 1], [1, 1], [1, 0]], + ], + [TetrominoType.J]: [ + [[1, 0, 0], [1, 1, 1]], + [[1, 1], [1, 0], [1, 0]], + [[1, 1, 1], [0, 0, 1]], + [[0, 1], [0, 1], [1, 1]], + ], + [TetrominoType.L]: [ + [[0, 0, 1], [1, 1, 1]], + [[1, 0], [1, 0], [1, 1]], + [[1, 1, 1], [1, 0, 0]], + [[1, 1], [0, 1], [0, 1]], + ], +}; +export var GameAction; +(function (GameAction) { + GameAction["MOVE_LEFT"] = "MOVE_LEFT"; + GameAction["MOVE_RIGHT"] = "MOVE_RIGHT"; + GameAction["MOVE_DOWN"] = "MOVE_DOWN"; + GameAction["ROTATE"] = "ROTATE"; + GameAction["DROP"] = "DROP"; + GameAction["PAUSE"] = "PAUSE"; + GameAction["RESUME"] = "RESUME"; + GameAction["RESET"] = "RESET"; +})(GameAction || (GameAction = {})); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/ui.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/ui.d.ts @@ -0,0 +1,24 @@ +import { GameAction } from './types'; +export declare class UIController { + private scoreElement; + private levelElement; + private linesElement; + private statusElement; + private startBtn; + private pauseBtn; + private resetBtn; + private onActionCallback; + constructor(); + private setupEventListeners; + private handleKeyDown; + onAction(callback: (action: GameAction) => void): void; + updateScore(score: number): void; + updateLevel(level: number): void; + updateLines(lines: number): void; + showPausedStatus(): void; + showGameOverStatus(): void; + clearStatus(): void; + setStartButtonState(show: boolean): void; + disableGameControls(): void; + enableGameControls(): void; +} diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/ui.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/tetris-game/dist/ui.js @@ -0,0 +1,102 @@ +import { GameAction } from './types'; +export class UIController { + constructor() { + this.onActionCallback = null; + this.scoreElement = document.getElementById('score'); + this.levelElement = document.getElementById('level'); + this.linesElement = document.getElementById('lines'); + this.statusElement = document.getElementById('status'); + this.startBtn = document.getElementById('startBtn'); + this.pauseBtn = document.getElementById('pauseBtn'); + this.resetBtn = document.getElementById('resetBtn'); + this.setupEventListeners(); + } + setupEventListeners() { + // Button listeners + this.startBtn.addEventListener('click', () => { + this.onActionCallback?.(GameAction.RESUME); + this.setStartButtonState(false); + }); + this.pauseBtn.addEventListener('click', () => { + this.onActionCallback?.(GameAction.PAUSE); + this.setStartButtonState(true); + }); + this.resetBtn.addEventListener('click', () => { + this.onActionCallback?.(GameAction.RESET); + this.clearStatus(); + this.setStartButtonState(false); + }); + // Keyboard listeners + document.addEventListener('keydown', (e) => this.handleKeyDown(e)); + } + handleKeyDown(event) { + switch (event.key) { + case 'ArrowLeft': + event.preventDefault(); + this.onActionCallback?.(GameAction.MOVE_LEFT); + break; + case 'ArrowRight': + event.preventDefault(); + this.onActionCallback?.(GameAction.MOVE_RIGHT); + break; + case 'ArrowDown': + event.preventDefault(); + this.onActionCallback?.(GameAction.MOVE_DOWN); + break; + case 'z': + case 'Z': + case 'ArrowUp': + event.preventDefault(); + this.onActionCallback?.(GameAction.ROTATE); + break; + case ' ': + event.preventDefault(); + this.onActionCallback?.(GameAction.DROP); + break; + } + } + onAction(callback) { + this.onActionCallback = callback; + } + updateScore(score) { + this.scoreElement.textContent = score.toString(); + } + updateLevel(level) { + this.levelElement.textContent = level.toString(); + } + updateLines(lines) { + this.linesElement.textContent = lines.toString(); + } + showPausedStatus() { + this.statusElement.textContent = '⏸ PAUSED'; + this.statusElement.classList.remove('game-over'); + this.statusElement.classList.add('active', 'paused'); + } + showGameOverStatus() { + this.statusElement.textContent = '💀 GAME OVER'; + this.statusElement.classList.remove('paused'); + this.statusElement.classList.add('active', 'game-over'); + } + clearStatus() { + this.statusElement.classList.remove('active', 'paused', 'game-over'); + this.statusElement.textContent = ''; + } + setStartButtonState(show) { + if (show) { + this.startBtn.textContent = 'Resume'; + this.startBtn.style.display = 'block'; + this.pauseBtn.style.display = 'none'; + } + else { + this.startBtn.textContent = 'Start Game'; + this.startBtn.style.display = 'none'; + this.pauseBtn.style.display = 'block'; + } + } + disableGameControls() { + this.pauseBtn.disabled = true; + } + enableGameControls() { + this.pauseBtn.disabled = false; + } +} diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,411 @@ +"use strict"; +// ─── Types & Constants ─────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 32; // pixel size of one cell +const COLORS = [ + "#000000", // 0 – empty + "#00f0f0", // 1 – I (cyan) + "#0000f0", // 2 – J (blue) + "#f0a000", // 3 – L (orange) + "#f0f000", // 4 – O (yellow) + "#00f000", // 5 – S (green) + "#a000f0", // 6 – T (purple) + "#f00000", // 7 – Z (red) +]; +// SRS-style piece definitions (each shape is an array of rows) +const SHAPES = [ + // I + [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + // J + [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + // L + [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], + // O + [ + [1, 1], + [1, 1], + ], + // S + [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + // T + [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + // Z + [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], +]; +// Points for clearing 1-4 lines (index 0 unused) +const LINE_POINTS = [0, 100, 300, 500, 800]; +// ─── Canvas Setup ──────────────────────────────────────────────────── +const canvas = document.getElementById("game-canvas"); +const ctx = canvas.getContext("2d"); +canvas.width = COLS * BLOCK; +canvas.height = ROWS * BLOCK; +const nextCanvas = document.getElementById("next-canvas"); +const nextCtx = nextCanvas.getContext("2d"); +nextCanvas.width = 4 * BLOCK; +nextCanvas.height = 4 * BLOCK; +const scoreEl = document.getElementById("score"); +const levelEl = document.getElementById("level"); +const linesEl = document.getElementById("lines"); +const gameOverEl = document.getElementById("game-over"); +// ─── Game State ────────────────────────────────────────────────────── +let grid; +let current; +let next; +let score; +let lines; +let level; +let gameOver; +let dropInterval; +let lastDrop; +let animationId; +let lockDelay; +let lockTimer; +let softDropping; +function createGrid() { + return Array.from({ length: ROWS }, () => new Array(COLS).fill(0)); +} +function randomPiece() { + const idx = Math.floor(Math.random() * SHAPES.length); + const shape = SHAPES[idx].map((row) => [...row]); + const colorIdx = idx + 1; + return { + shape, + color: colorIdx, + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + }; +} +function init() { + grid = createGrid(); + score = 0; + lines = 0; + level = 1; + gameOver = false; + dropInterval = 1000; + lastDrop = 0; + lockDelay = 500; + lockTimer = 0; + softDropping = false; + current = randomPiece(); + next = randomPiece(); + gameOverEl.style.display = "none"; + updateHUD(); +} +// ─── Collision Detection ───────────────────────────────────────────── +function collides(piece, dx, dy, shape) { + const s = shape || piece.shape; + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const nx = piece.x + c + dx; + const ny = piece.y + r + dy; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny < 0) + continue; + if (grid[ny][nx]) + return true; + } + } + return false; +} +// ─── Piece Locking & Line Clearing ────────────────────────────────── +function lock(piece) { + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + const y = piece.y + r; + const x = piece.x + c; + if (y < 0) { + triggerGameOver(); + return; + } + grid[y][x] = piece.color; + } + } + clearLines(); +} +function clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (grid[r].every((cell) => cell !== 0)) { + grid.splice(r, 1); + grid.unshift(new Array(COLS).fill(0)); + cleared++; + r++; // recheck same row index after splice + } + } + if (cleared > 0) { + lines += cleared; + score += LINE_POINTS[cleared] * level; + // Level up every 10 lines + const newLevel = Math.floor(lines / 10) + 1; + if (newLevel !== level) { + level = newLevel; + dropInterval = Math.max(100, 1000 - (level - 1) * 80); + } + updateHUD(); + } +} +function triggerGameOver() { + gameOver = true; + gameOverEl.style.display = "flex"; +} +// ─── Rotation (SRS-like wall kicks) ───────────────────────────────── +function rotateMatrix(matrix) { + const n = matrix.length; + const rotated = Array.from({ length: n }, () => new Array(n).fill(0)); + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + rotated[c][n - 1 - r] = matrix[r][c]; + } + } + return rotated; +} +function tryRotate(piece) { + const rotated = rotateMatrix(piece.shape); + // Wall-kick offsets to try + const kicks = [0, -1, 1, -2, 2]; + for (const dx of kicks) { + if (!collides(piece, dx, 0, rotated)) { + piece.shape = rotated; + piece.x += dx; + return; + } + } +} +// ─── Movement ──────────────────────────────────────────────────────── +function moveLeft() { + if (!collides(current, -1, 0)) + current.x--; +} +function moveRight() { + if (!collides(current, 1, 0)) + current.x++; +} +function moveDown() { + if (!collides(current, 0, 1)) { + current.y++; + return true; + } + return false; +} +function hardDrop() { + while (!collides(current, 0, 1)) { + current.y++; + score += 2; + } + lock(current); + spawn(); + updateHUD(); +} +function spawn() { + current = next; + next = randomPiece(); + lockTimer = 0; + if (collides(current, 0, 0)) { + triggerGameOver(); + } +} +// ─── Ghost Piece (drop shadow) ────────────────────────────────────── +function ghostY() { + let gy = 0; + while (!collides(current, 0, gy + 1)) { + gy++; + } + return current.y + gy; +} +// ─── Drawing ───────────────────────────────────────────────────────── +function drawBlock(context, x, y, color, alpha = 1) { + context.globalAlpha = alpha; + context.fillStyle = color; + context.fillRect(x * BLOCK, y * BLOCK, BLOCK, BLOCK); + // Highlight + context.fillStyle = "rgba(255,255,255,0.25)"; + context.fillRect(x * BLOCK, y * BLOCK, BLOCK, 3); + context.fillRect(x * BLOCK, y * BLOCK, 3, BLOCK); + // Shadow + context.fillStyle = "rgba(0,0,0,0.25)"; + context.fillRect(x * BLOCK + BLOCK - 3, y * BLOCK, 3, BLOCK); + context.fillRect(x * BLOCK, y * BLOCK + BLOCK - 3, BLOCK, 3); + // Border + context.globalAlpha = alpha; + context.strokeStyle = "#111"; + context.lineWidth = 1; + context.strokeRect(x * BLOCK, y * BLOCK, BLOCK, BLOCK); + context.globalAlpha = 1; +} +function drawGrid() { + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Grid lines + ctx.strokeStyle = "#1a1a1a"; + ctx.lineWidth = 0.5; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK, r * BLOCK, BLOCK, BLOCK); + } + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c]) { + drawBlock(ctx, c, r, COLORS[grid[r][c]]); + } + } + } +} +function drawPiece(piece, alpha = 1, overrideY) { + const py = overrideY !== undefined ? overrideY : piece.y; + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (piece.shape[r][c]) { + drawBlock(ctx, piece.x + c, py + r, COLORS[piece.color], alpha); + } + } + } +} +function drawGhost() { + const gy = ghostY(); + if (gy !== current.y) { + drawPiece(current, 0.25, gy); + } +} +function drawNext() { + nextCtx.fillStyle = "#1a1a1a"; + nextCtx.fillRect(0, 0, nextCanvas.width, nextCanvas.height); + const offsetX = (4 - next.shape[0].length) / 2; + const offsetY = (4 - next.shape.length) / 2; + for (let r = 0; r < next.shape.length; r++) { + for (let c = 0; c < next.shape[r].length; c++) { + if (next.shape[r][c]) { + nextCtx.globalAlpha = 1; + nextCtx.fillStyle = COLORS[next.color]; + const bx = (offsetX + c) * BLOCK; + const by = (offsetY + r) * BLOCK; + nextCtx.fillRect(bx, by, BLOCK, BLOCK); + nextCtx.strokeStyle = "#111"; + nextCtx.lineWidth = 1; + nextCtx.strokeRect(bx, by, BLOCK, BLOCK); + // Highlight + nextCtx.fillStyle = "rgba(255,255,255,0.25)"; + nextCtx.fillRect(bx, by, BLOCK, 3); + nextCtx.fillRect(bx, by, 3, BLOCK); + // Shadow + nextCtx.fillStyle = "rgba(0,0,0,0.25)"; + nextCtx.fillRect(bx + BLOCK - 3, by, 3, BLOCK); + nextCtx.fillRect(bx, by + BLOCK - 3, BLOCK, 3); + } + } + } +} +function updateHUD() { + scoreEl.textContent = score.toString(); + levelEl.textContent = level.toString(); + linesEl.textContent = lines.toString(); +} +// ─── Game Loop ─────────────────────────────────────────────────────── +function gameLoop(timestamp) { + if (gameOver) + return; + const effectiveInterval = softDropping ? dropInterval / 10 : dropInterval; + if (timestamp - lastDrop > effectiveInterval) { + if (!moveDown()) { + // Piece can't move down – start or continue lock timer + lockTimer += timestamp - lastDrop; + if (lockTimer >= lockDelay) { + lock(current); + if (!gameOver) + spawn(); + lockTimer = 0; + } + } + else { + lockTimer = 0; + if (softDropping) + score += 1; + } + lastDrop = timestamp; + updateHUD(); + } + // Draw + drawGrid(); + drawGhost(); + drawPiece(current); + drawNext(); + animationId = requestAnimationFrame(gameLoop); +} +// ─── Input Handling ────────────────────────────────────────────────── +document.addEventListener("keydown", (e) => { + if (gameOver) { + if (e.key === "Enter" || e.key === "r" || e.key === "R") { + init(); + animationId = requestAnimationFrame(gameLoop); + } + return; + } + switch (e.key) { + case "ArrowLeft": + case "a": + e.preventDefault(); + moveLeft(); + break; + case "ArrowRight": + case "d": + e.preventDefault(); + moveRight(); + break; + case "ArrowDown": + case "s": + e.preventDefault(); + softDropping = true; + break; + case "ArrowUp": + case "w": + e.preventDefault(); + tryRotate(current); + break; + case " ": + e.preventDefault(); + hardDrop(); + break; + } +}); +document.addEventListener("keyup", (e) => { + if (e.key === "ArrowDown" || e.key === "s") { + softDropping = false; + } +}); +// ─── Start ─────────────────────────────────────────────────────────── +init(); +animationId = requestAnimationFrame(gameLoop); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,353 @@ +"use strict"; +// ── Types ────────────────────────────────────────────────────────────────────── +// ── Constants ────────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 32; +const PREVIEW_BLOCK = 20; +const TETROMINOES = [ + { shape: [[1, 1, 1, 1]], color: "#00f0f0" }, // I + { shape: [[1, 0, 0], [1, 1, 1]], color: "#0000f0" }, // J + { shape: [[0, 0, 1], [1, 1, 1]], color: "#f0a000" }, // L + { shape: [[1, 1], [1, 1]], color: "#f0f000" }, // O + { shape: [[0, 1, 1], [1, 1, 0]], color: "#00f000" }, // S + { shape: [[0, 1, 0], [1, 1, 1]], color: "#a000f0" }, // T + { shape: [[1, 1, 0], [0, 1, 1]], color: "#f00000" }, // Z +]; +const POINTS_PER_LINE = [0, 100, 300, 500, 800]; +const LINES_PER_LEVEL = 10; +const BASE_SPEED = 800; // ms per drop at level 1 +const SPEED_FACTOR = 0.85; // multiplier per level +const MIN_SPEED = 50; +// ── Canvas setup ─────────────────────────────────────────────────────────────── +const canvas = document.getElementById("game-canvas"); +const ctx = canvas.getContext("2d"); +canvas.width = COLS * BLOCK_SIZE; +canvas.height = ROWS * BLOCK_SIZE; +const previewCanvas = document.getElementById("preview-canvas"); +const previewCtx = previewCanvas.getContext("2d"); +previewCanvas.width = 6 * PREVIEW_BLOCK; +previewCanvas.height = 4 * PREVIEW_BLOCK; +const scoreEl = document.getElementById("score"); +const levelEl = document.getElementById("level"); +const linesEl = document.getElementById("lines"); +const gameOverEl = document.getElementById("game-over"); +// ── Game state ───────────────────────────────────────────────────────────────── +let grid; +let current; +let next; +let score; +let level; +let totalLines; +let dropInterval; +let lastDrop; +let gameOver; +let paused; +let rafId; +// ── Helpers ──────────────────────────────────────────────────────────────────── +function createEmptyGrid() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function randomTetromino() { + const t = TETROMINOES[Math.floor(Math.random() * TETROMINOES.length)]; + return { + shape: t.shape.map((r) => [...r]), + color: t.color, + row: 0, + col: Math.floor((COLS - t.shape[0].length) / 2), + }; +} +function rotateMatrix(matrix) { + const rows = matrix.length; + const cols = matrix[0].length; + const rotated = Array.from({ length: cols }, () => Array(rows).fill(0)); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + rotated[c][rows - 1 - r] = matrix[r][c]; + } + } + return rotated; +} +function collides(piece, grid) { + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + const newR = piece.row + r; + const newC = piece.col + c; + if (newR < 0 || newR >= ROWS || newC < 0 || newC >= COLS) + return true; + if (grid[newR][newC]) + return true; + } + } + return false; +} +function lockPiece() { + for (let r = 0; r < current.shape.length; r++) { + for (let c = 0; c < current.shape[r].length; c++) { + if (!current.shape[r][c]) + continue; + const gr = current.row + r; + const gc = current.col + c; + if (gr < 0) { + triggerGameOver(); + return; + } + grid[gr][gc] = current.color; + } + } + clearLines(); + spawnPiece(); +} +function clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (grid[r].every((c) => c !== null)) { + grid.splice(r, 1); + grid.unshift(Array(COLS).fill(null)); + cleared++; + r++; // recheck same index + } + } + if (cleared > 0) { + score += POINTS_PER_LINE[cleared] * level; + totalLines += cleared; + const newLevel = Math.floor(totalLines / LINES_PER_LEVEL) + 1; + if (newLevel !== level) { + level = newLevel; + dropInterval = Math.max(MIN_SPEED, BASE_SPEED * Math.pow(SPEED_FACTOR, level - 1)); + } + updateHUD(); + } +} +function spawnPiece() { + current = next; + next = randomTetromino(); + if (collides(current, grid)) { + triggerGameOver(); + } +} +function triggerGameOver() { + gameOver = true; + gameOverEl.style.display = "block"; + cancelAnimationFrame(rafId); +} +function updateHUD() { + scoreEl.textContent = String(score); + levelEl.textContent = String(level); + linesEl.textContent = String(totalLines); +} +// ── Drawing ──────────────────────────────────────────────────────────────────── +function drawBlock(context, x, y, size, color) { + context.fillStyle = color; + context.fillRect(x, y, size, size); + // highlight + context.fillStyle = "rgba(255,255,255,0.3)"; + context.fillRect(x, y, size, 3); + context.fillRect(x, y, 3, size); + // shadow + context.fillStyle = "rgba(0,0,0,0.3)"; + context.fillRect(x + size - 3, y, 3, size); + context.fillRect(x, y + size - 3, size, 3); + // border + context.strokeStyle = "#000"; + context.lineWidth = 1; + context.strokeRect(x, y, size, size); +} +function drawGrid() { + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(canvas.width, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, canvas.height); + ctx.stroke(); + } + // locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c]) { + drawBlock(ctx, c * BLOCK_SIZE, r * BLOCK_SIZE, BLOCK_SIZE, grid[r][c]); + } + } + } +} +function drawGhost() { + const ghost = { ...current, shape: current.shape.map((r) => [...r]) }; + while (!collides({ ...ghost, row: ghost.row + 1 }, grid)) { + ghost.row++; + } + for (let r = 0; r < ghost.shape.length; r++) { + for (let c = 0; c < ghost.shape[r].length; c++) { + if (!ghost.shape[r][c]) + continue; + const x = (ghost.col + c) * BLOCK_SIZE; + const y = (ghost.row + r) * BLOCK_SIZE; + ctx.strokeStyle = current.color; + ctx.lineWidth = 2; + ctx.strokeRect(x + 2, y + 2, BLOCK_SIZE - 4, BLOCK_SIZE - 4); + } + } +} +function drawPiece(piece) { + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + drawBlock(ctx, (piece.col + c) * BLOCK_SIZE, (piece.row + r) * BLOCK_SIZE, BLOCK_SIZE, piece.color); + } + } +} +function drawPreview() { + previewCtx.fillStyle = "#111"; + previewCtx.fillRect(0, 0, previewCanvas.width, previewCanvas.height); + const shape = next.shape; + const offX = Math.floor((6 - shape[0].length) / 2); + const offY = Math.floor((4 - shape.length) / 2); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + drawBlock(previewCtx, (offX + c) * PREVIEW_BLOCK, (offY + r) * PREVIEW_BLOCK, PREVIEW_BLOCK, next.color); + } + } +} +function render() { + drawGrid(); + if (!gameOver) { + drawGhost(); + drawPiece(current); + } + drawPreview(); +} +// ── Input ────────────────────────────────────────────────────────────────────── +function moveLeft() { + current.col--; + if (collides(current, grid)) + current.col++; +} +function moveRight() { + current.col++; + if (collides(current, grid)) + current.col--; +} +function moveDown() { + current.row++; + if (collides(current, grid)) { + current.row--; + lockPiece(); + return false; + } + return true; +} +function hardDrop() { + let rows = 0; + while (!collides({ ...current, row: current.row + 1 }, grid)) { + current.row++; + rows++; + } + score += rows * 2; + updateHUD(); + lockPiece(); +} +function rotatePiece() { + const original = current.shape; + current.shape = rotateMatrix(current.shape); + // wall-kick offsets to try + const kicks = [0, -1, 1, -2, 2]; + let kicked = false; + for (const offset of kicks) { + current.col += offset; + if (!collides(current, grid)) { + kicked = true; + break; + } + current.col -= offset; + } + if (!kicked) { + current.shape = original; // revert + } +} +document.addEventListener("keydown", (e) => { + if (gameOver) { + if (e.key === "Enter") + initGame(); + return; + } + if (e.key === "p" || e.key === "P") { + paused = !paused; + if (!paused) { + lastDrop = performance.now(); + rafId = requestAnimationFrame(gameLoop); + } + return; + } + if (paused) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + moveLeft(); + break; + case "ArrowRight": + case "d": + moveRight(); + break; + case "ArrowDown": + case "s": + moveDown(); + score += 1; + updateHUD(); + break; + case "ArrowUp": + case "w": + rotatePiece(); + break; + case " ": + hardDrop(); + break; + } + e.preventDefault(); + render(); +}); +// ── Game loop ────────────────────────────────────────────────────────────────── +function gameLoop(timestamp) { + if (gameOver || paused) + return; + if (timestamp - lastDrop > dropInterval) { + moveDown(); + lastDrop = timestamp; + } + render(); + rafId = requestAnimationFrame(gameLoop); +} +function initGame() { + grid = createEmptyGrid(); + score = 0; + level = 1; + totalLines = 0; + dropInterval = BASE_SPEED; + lastDrop = performance.now(); + gameOver = false; + paused = false; + gameOverEl.style.display = "none"; + next = randomTetromino(); + current = randomTetromino(); + updateHUD(); + render(); + cancelAnimationFrame(rafId); + rafId = requestAnimationFrame(gameLoop); +} +// ── Start ────────────────────────────────────────────────────────────────────── +initGame(); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":";AAAA,kFAAkF;AAkBlF,kFAAkF;AAElF,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,UAAU,GAAG,EAAE,CAAC;AACtB,MAAM,aAAa,GAAG,EAAE,CAAC;AAEzB,MAAM,WAAW,GAAmB;IAClC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAA0B,KAAK,EAAE,SAAS,EAAE,EAAE,IAAI;IACzE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAkB,KAAK,EAAE,SAAS,EAAE,EAAE,IAAI;IACzE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAkB,KAAK,EAAE,SAAS,EAAE,EAAE,IAAI;IACzE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAyB,KAAK,EAAE,SAAS,EAAE,EAAE,IAAI;IAC1E,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAkB,KAAK,EAAE,SAAS,EAAE,EAAE,IAAI;IACzE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAkB,KAAK,EAAE,SAAS,EAAE,EAAE,IAAI;IACzE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAkB,KAAK,EAAE,SAAS,EAAE,EAAE,IAAI;CAC1E,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAChD,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,UAAU,GAAG,GAAG,CAAC,CAAO,yBAAyB;AACvD,MAAM,YAAY,GAAG,IAAI,CAAC,CAAI,uBAAuB;AACrD,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,kFAAkF;AAElF,MAAM,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAsB,CAAC;AAC3E,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;AACrC,MAAM,CAAC,KAAK,GAAG,IAAI,GAAG,UAAU,CAAC;AACjC,MAAM,CAAC,MAAM,GAAG,IAAI,GAAG,UAAU,CAAC;AAElC,MAAM,aAAa,GAAG,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAsB,CAAC;AACrF,MAAM,UAAU,GAAG,aAAa,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;AACnD,aAAa,CAAC,KAAK,GAAG,CAAC,GAAG,aAAa,CAAC;AACxC,aAAa,CAAC,MAAM,GAAG,CAAC,GAAG,aAAa,CAAC;AAEzC,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC;AAClD,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC;AAClD,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC;AAClD,MAAM,UAAU,GAAG,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAE,CAAC;AAEzD,kFAAkF;AAElF,IAAI,IAAU,CAAC;AACf,IAAI,OAAc,CAAC;AACnB,IAAI,IAAW,CAAC;AAChB,IAAI,KAAa,CAAC;AAClB,IAAI,KAAa,CAAC;AAClB,IAAI,UAAkB,CAAC;AACvB,IAAI,YAAoB,CAAC;AACzB,IAAI,QAAgB,CAAC;AACrB,IAAI,QAAiB,CAAC;AACtB,IAAI,MAAe,CAAC;AACpB,IAAI,KAAa,CAAC;AAElB,kFAAkF;AAElF,SAAS,eAAe;IACtB,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAW,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,eAAe;IACtB,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IACtE,OAAO;QACL,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACjC,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,GAAG,EAAE,CAAC;QACN,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;KAChD,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,MAAa;IACjC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC9B,MAAM,OAAO,GAAU,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,QAAQ,CAAC,KAAY,EAAE,IAAU;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAAE,SAAS;YACjC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;YAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;YAC3B,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,IAAI,IAAI;gBAAE,OAAO,IAAI,CAAC;YACtE,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;gBAAE,OAAO,IAAI,CAAC;QACpC,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,SAAS;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACjD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAAE,SAAS;YACnC,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;YAC3B,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;YAC3B,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;gBACX,eAAe,EAAE,CAAC;gBAClB,OAAO;YACT,CAAC;YACD,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,UAAU,EAAE,CAAC;IACb,UAAU,EAAE,CAAC;AACf,CAAC;AAED,SAAS,UAAU;IACjB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAClB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YACrC,OAAO,EAAE,CAAC;YACV,CAAC,EAAE,CAAC,CAAC,qBAAqB;QAC5B,CAAC;IACH,CAAC;IACD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,KAAK,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC;QAC1C,UAAU,IAAI,OAAO,CAAC;QACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QAC9D,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;YACvB,KAAK,GAAG,QAAQ,CAAC;YACjB,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;QACrF,CAAC;QACD,SAAS,EAAE,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,UAAU;IACjB,OAAO,GAAG,IAAI,CAAC;IACf,IAAI,GAAG,eAAe,EAAE,CAAC;IACzB,IAAI,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;QAC5B,eAAe,EAAE,CAAC;IACpB,CAAC;AACH,CAAC;AAED,SAAS,eAAe;IACtB,QAAQ,GAAG,IAAI,CAAC;IAChB,UAAU,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;IACnC,oBAAoB,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACpC,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACpC,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;AAC3C,CAAC;AAED,kFAAkF;AAElF,SAAS,SAAS,CAChB,OAAiC,EACjC,CAAS,EACT,CAAS,EACT,IAAY,EACZ,KAAa;IAEb,OAAO,CAAC,SAAS,GAAG,KAAK,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAEnC,YAAY;IACZ,OAAO,CAAC,SAAS,GAAG,uBAAuB,CAAC;IAC5C,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;IAEhC,SAAS;IACT,OAAO,CAAC,SAAS,GAAG,iBAAiB,CAAC;IACtC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3C,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAE3C,SAAS;IACT,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC;IAC7B,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;IACtB,OAAO,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,QAAQ;IACf,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC;IACvB,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAEhD,aAAa;IACb,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC;IACzB,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,GAAG,CAAC,SAAS,EAAE,CAAC;QAChB,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC;QAC9B,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC;QACzC,GAAG,CAAC,MAAM,EAAE,CAAC;IACf,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,GAAG,CAAC,SAAS,EAAE,CAAC;QAChB,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC;QAC9B,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1C,GAAG,CAAC,MAAM,EAAE,CAAC;IACf,CAAC;IAED,eAAe;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACf,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC;YAC1E,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,SAAS;IAChB,MAAM,KAAK,GAAU,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,OAAO,CAAC,QAAQ,CAAC,EAAE,GAAG,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC;QACzD,KAAK,CAAC,GAAG,EAAE,CAAC;IACd,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAAE,SAAS;YACjC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC;YACvC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC;YACvC,GAAG,CAAC,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC;YAChC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;YAClB,GAAG,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,KAAY;IAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAAE,SAAS;YACjC,SAAS,CACP,GAAG,EACH,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,UAAU,EAC5B,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,UAAU,EAC5B,UAAU,EACV,KAAK,CAAC,KAAK,CACZ,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,WAAW;IAClB,UAAU,CAAC,SAAS,GAAG,MAAM,CAAC;IAC9B,UAAU,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAErE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAEhD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAAE,SAAS;YAC3B,SAAS,CACP,UAAU,EACV,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,aAAa,EAC1B,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,aAAa,EAC1B,aAAa,EACb,IAAI,CAAC,KAAK,CACX,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,MAAM;IACb,QAAQ,EAAE,CAAC;IACX,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,SAAS,EAAE,CAAC;QACZ,SAAS,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IACD,WAAW,EAAE,CAAC;AAChB,CAAC;AAED,kFAAkF;AAElF,SAAS,QAAQ;IACf,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,IAAI,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;QAAE,OAAO,CAAC,GAAG,EAAE,CAAC;AAC7C,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,IAAI,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;QAAE,OAAO,CAAC,GAAG,EAAE,CAAC;AAC7C,CAAC;AAED,SAAS,QAAQ;IACf,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,IAAI,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,SAAS,EAAE,CAAC;QACZ,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,QAAQ;IACf,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,OAAO,CAAC,QAAQ,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC;QAC7D,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,IAAI,EAAE,CAAC;IACT,CAAC;IACD,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC;IAClB,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC;AACd,CAAC;AAED,SAAS,WAAW;IAClB,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC;IAC/B,OAAO,CAAC,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAE5C,2BAA2B;IAC3B,MAAM,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAChC,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,IAAI,MAAM,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;YAC7B,MAAM,GAAG,IAAI,CAAC;YACd,MAAM;QACR,CAAC;QACD,OAAO,CAAC,GAAG,IAAI,MAAM,CAAC;IACxB,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,CAAC,SAAS;IACrC,CAAC;AACH,CAAC;AAED,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAgB,EAAE,EAAE;IACxD,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO;YAAE,QAAQ,EAAE,CAAC;QAClC,OAAO;IACT,CAAC;IACD,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;QACnC,MAAM,GAAG,CAAC,MAAM,CAAC;QACjB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;YAC7B,KAAK,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO;IACT,CAAC;IACD,IAAI,MAAM;QAAE,OAAO;IAEnB,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC;QACd,KAAK,WAAW,CAAC;QACjB,KAAK,GAAG;YACN,QAAQ,EAAE,CAAC;YACX,MAAM;QACR,KAAK,YAAY,CAAC;QAClB,KAAK,GAAG;YACN,SAAS,EAAE,CAAC;YACZ,MAAM;QACR,KAAK,WAAW,CAAC;QACjB,KAAK,GAAG;YACN,QAAQ,EAAE,CAAC;YACX,KAAK,IAAI,CAAC,CAAC;YACX,SAAS,EAAE,CAAC;YACZ,MAAM;QACR,KAAK,SAAS,CAAC;QACf,KAAK,GAAG;YACN,WAAW,EAAE,CAAC;YACd,MAAM;QACR,KAAK,GAAG;YACN,QAAQ,EAAE,CAAC;YACX,MAAM;IACV,CAAC;IACD,CAAC,CAAC,cAAc,EAAE,CAAC;IACnB,MAAM,EAAE,CAAC;AACX,CAAC,CAAC,CAAC;AAEH,kFAAkF;AAElF,SAAS,QAAQ,CAAC,SAAiB;IACjC,IAAI,QAAQ,IAAI,MAAM;QAAE,OAAO;IAE/B,IAAI,SAAS,GAAG,QAAQ,GAAG,YAAY,EAAE,CAAC;QACxC,QAAQ,EAAE,CAAC;QACX,QAAQ,GAAG,SAAS,CAAC;IACvB,CAAC;IAED,MAAM,EAAE,CAAC;IACT,KAAK,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,QAAQ;IACf,IAAI,GAAG,eAAe,EAAE,CAAC;IACzB,KAAK,GAAG,CAAC,CAAC;IACV,KAAK,GAAG,CAAC,CAAC;IACV,UAAU,GAAG,CAAC,CAAC;IACf,YAAY,GAAG,UAAU,CAAC;IAC1B,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAC7B,QAAQ,GAAG,KAAK,CAAC;IACjB,MAAM,GAAG,KAAK,CAAC;IACf,UAAU,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;IAElC,IAAI,GAAG,eAAe,EAAE,CAAC;IACzB,OAAO,GAAG,eAAe,EAAE,CAAC;IAE5B,SAAS,EAAE,CAAC;IACZ,MAAM,EAAE,CAAC;IACT,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAC5B,KAAK,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,kFAAkF;AAElF,QAAQ,EAAE,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,491 @@ +"use strict"; +// ─── Types & Constants ─────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const CELL = 32; // px per cell +const PREVIEW_CELLS = 4; +const COLORS = { + 0: "#111", // empty + 1: "#00f0f0", // I – cyan + 2: "#0000f0", // J – blue + 3: "#f0a000", // L – orange + 4: "#f0f000", // O – yellow + 5: "#00f000", // S – green + 6: "#a000f0", // T – purple + 7: "#f00000", // Z – red + 8: "#333", // ghost +}; +// Standard 7 tetrominoes (each in their spawn orientation) +const SHAPES = [ + [[1, 1, 1, 1]], // I + [[1, 0, 0], [1, 1, 1]], // J + [[0, 0, 1], [1, 1, 1]], // L + [[1, 1], [1, 1]], // O + [[0, 1, 1], [1, 1, 0]], // S + [[0, 1, 0], [1, 1, 1]], // T + [[1, 1, 0], [0, 1, 1]], // Z +]; +// SRS wall-kick data (non-I pieces) +const KICKS_NORMAL = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// SRS wall-kick data (I piece) +const KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// ─── Utility helpers ───────────────────────────────────────────────── +function createGrid(rows, cols) { + return Array.from({ length: rows }, () => new Array(cols).fill(0)); +} +function rotateCW(shape) { + const h = shape.length; + const w = shape[0].length; + const out = Array.from({ length: w }, () => new Array(h).fill(0)); + for (let r = 0; r < h; r++) + for (let c = 0; c < w; c++) + out[c][h - 1 - r] = shape[r][c]; + return out; +} +function rotateCCW(shape) { + return rotateCW(rotateCW(rotateCW(shape))); +} +// ─── Game class ────────────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.bag = []; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.dropInterval = 1000; // ms + this.lastDrop = 0; + this.lockDelay = 500; // ms + this.lockTimer = 0; + this.lockMoves = 0; + this.isLocking = false; + this.animId = 0; + this.highScore = 0; + // Scoring (original BPS scoring) + this.linePoints = [0, 100, 300, 500, 800]; + // DAS (Delayed Auto-Shift) + this.dasDelay = 170; // ms before auto-repeat starts + this.dasRate = 50; // ms per repeat + this.activeKeys = new Map(); + const mainCanvas = document.getElementById("game-canvas"); + const previewCanvas = document.getElementById("preview-canvas"); + mainCanvas.width = COLS * CELL; + mainCanvas.height = ROWS * CELL; + previewCanvas.width = PREVIEW_CELLS * CELL; + previewCanvas.height = PREVIEW_CELLS * CELL; + this.mainCtx = mainCanvas.getContext("2d"); + this.previewCtx = previewCanvas.getContext("2d"); + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.highScoreEl = document.getElementById("high-score"); + this.overlayEl = document.getElementById("overlay"); + this.overlayTextEl = document.getElementById("overlay-text"); + this.grid = createGrid(ROWS, COLS); + // Load high score + const saved = localStorage.getItem("tetris-high-score"); + if (saved) + this.highScore = parseInt(saved, 10); + this.initInput(); + this.spawnNext(); + this.spawnPiece(); + this.updateUI(); + this.overlayEl.style.display = "none"; + this.lastDrop = performance.now(); + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + // ── Bag randomizer (7-bag) ─────────────────────────────────── + refillBag() { + this.bag = [0, 1, 2, 3, 4, 5, 6]; + // Fisher-Yates shuffle + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + nextFromBag() { + if (this.bag.length === 0) + this.refillBag(); + return this.bag.pop(); + } + // ── Spawning ───────────────────────────────────────────────── + spawnNext() { + const idx = this.nextFromBag(); + this.next = { shape: SHAPES[idx], color: idx + 1 }; + } + spawnPiece() { + const { shape, color } = this.next; + this.current = { + shape, + color, + row: 0, + col: Math.floor((COLS - shape[0].length) / 2), + }; + this.currentRotation = 0; + this.isLocking = false; + this.lockMoves = 0; + this.spawnNext(); + if (!this.isValid(this.current.shape, this.current.row, this.current.col)) { + this.endGame(); + } + } + // ── Collision detection ────────────────────────────────────── + isValid(shape, row, col) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nr = row + r; + const nc = col + c; + if (nc < 0 || nc >= COLS || nr >= ROWS) + return false; + if (nr < 0) + continue; // above top is OK + if (this.grid[nr][nc]) + return false; + } + } + return true; + } + // ── Movement ───────────────────────────────────────────────── + move(dr, dc) { + const nr = this.current.row + dr; + const nc = this.current.col + dc; + if (this.isValid(this.current.shape, nr, nc)) { + this.current.row = nr; + this.current.col = nc; + if (this.isLocking && dr === 0) { + this.lockTimer = performance.now(); + this.lockMoves++; + if (this.lockMoves > 15) + this.lock(); + } + return true; + } + return false; + } + // ── Rotation (SRS) ────────────────────────────────────────── + rotate(dir) { + const oldRot = this.currentRotation; + const newRot = (oldRot + dir + 4) % 4; + const newShape = dir === 1 ? rotateCW(this.current.shape) : rotateCCW(this.current.shape); + const isI = this.current.color === 1; + const kickTable = isI ? KICKS_I : KICKS_NORMAL; + const key = `${oldRot}>${newRot}`; + const kicks = kickTable[key] || [[0, 0]]; + for (const [dx, dy] of kicks) { + const nc = this.current.col + dx; + const nr = this.current.row - dy; + if (this.isValid(newShape, nr, nc)) { + this.current.shape = newShape; + this.current.row = nr; + this.current.col = nc; + this.currentRotation = newRot; + if (this.isLocking) { + this.lockTimer = performance.now(); + this.lockMoves++; + if (this.lockMoves > 15) + this.lock(); + } + return; + } + } + } + // ── Hard drop ──────────────────────────────────────────────── + hardDrop() { + let dropped = 0; + while (this.move(1, 0)) + dropped++; + this.score += dropped * 2; + this.lock(); + } + // ── Soft drop ──────────────────────────────────────────────── + softDrop() { + if (this.move(1, 0)) { + this.score += 1; + return true; + } + return false; + } + // ── Ghost piece (shadow) ───────────────────────────────────── + ghostRow() { + let r = this.current.row; + while (this.isValid(this.current.shape, r + 1, this.current.col)) + r++; + return r; + } + // ── Lock piece onto grid ───────────────────────────────────── + lock() { + const { shape, color, row, col } = this.current; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const gr = row + r; + const gc = col + c; + if (gr < 0) { + this.endGame(); + return; + } + this.grid[gr][gc] = color; + } + } + this.clearLines(); + this.spawnPiece(); + this.lastDrop = performance.now(); + } + // ── Line clearing ──────────────────────────────────────────── + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.grid[r].every((c) => c !== 0)) { + this.grid.splice(r, 1); + this.grid.unshift(new Array(COLS).fill(0)); + cleared++; + r++; // re-check same row index + } + } + if (cleared > 0) { + this.lines += cleared; + this.score += this.linePoints[cleared] * this.level; + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel > this.level) { + this.level = newLevel; + this.dropInterval = Math.max(50, 1000 - (this.level - 1) * 75); + } + } + } + // ── Game over ──────────────────────────────────────────────── + endGame() { + this.gameOver = true; + cancelAnimationFrame(this.animId); + if (this.score > this.highScore) { + this.highScore = this.score; + localStorage.setItem("tetris-high-score", String(this.highScore)); + } + this.updateUI(); + this.overlayTextEl.textContent = "GAME OVER — Press R to restart"; + this.overlayEl.style.display = "flex"; + } + // ── Restart ────────────────────────────────────────────────── + restart() { + this.grid = createGrid(ROWS, COLS); + this.bag = []; + this.score = 0; + this.lines = 0; + this.level = 1; + this.dropInterval = 1000; + this.gameOver = false; + this.paused = false; + this.spawnNext(); + this.spawnPiece(); + this.updateUI(); + this.overlayEl.style.display = "none"; + this.lastDrop = performance.now(); + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + // ── Pause / Resume ────────────────────────────────────────── + togglePause() { + if (this.gameOver) + return; + this.paused = !this.paused; + if (this.paused) { + cancelAnimationFrame(this.animId); + this.overlayTextEl.textContent = "PAUSED — Press P to resume"; + this.overlayEl.style.display = "flex"; + } + else { + this.overlayEl.style.display = "none"; + this.lastDrop = performance.now(); + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + } + // ── Input ──────────────────────────────────────────────────── + initInput() { + document.addEventListener("keydown", (e) => { + if (e.repeat) + return; + if (e.key === "r" || e.key === "R") { + this.restart(); + return; + } + if (e.key === "p" || e.key === "P") { + this.togglePause(); + return; + } + if (this.gameOver || this.paused) + return; + switch (e.key) { + case "ArrowLeft": + this.move(0, -1); + this.activeKeys.set("ArrowLeft", { start: performance.now(), lastRepeat: performance.now() }); + break; + case "ArrowRight": + this.move(0, 1); + this.activeKeys.set("ArrowRight", { start: performance.now(), lastRepeat: performance.now() }); + break; + case "ArrowDown": + this.softDrop(); + this.activeKeys.set("ArrowDown", { start: performance.now(), lastRepeat: performance.now() }); + break; + case "ArrowUp": + case "x": + case "X": + this.rotate(1); + break; + case "z": + case "Z": + case "Control": + this.rotate(-1); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + } + }); + document.addEventListener("keyup", (e) => { + this.activeKeys.delete(e.key); + }); + } + // Process DAS + processDAS(now) { + for (const [key, state] of this.activeKeys) { + const held = now - state.start; + if (held < this.dasDelay) + continue; + const sinceLast = now - state.lastRepeat; + if (sinceLast >= this.dasRate) { + switch (key) { + case "ArrowLeft": + this.move(0, -1); + break; + case "ArrowRight": + this.move(0, 1); + break; + case "ArrowDown": + this.softDrop(); + break; + } + state.lastRepeat = now; + } + } + } + // ── Main loop ──────────────────────────────────────────────── + loop(now) { + if (this.gameOver || this.paused) + return; + // DAS + this.processDAS(now); + // Gravity + const elapsed = now - this.lastDrop; + if (elapsed >= this.dropInterval) { + if (!this.move(1, 0)) { + // Can't move down – start or continue lock delay + if (!this.isLocking) { + this.isLocking = true; + this.lockTimer = now; + } + } + else { + this.isLocking = false; + } + this.lastDrop = now; + } + // Lock delay + if (this.isLocking && now - this.lockTimer >= this.lockDelay) { + this.lock(); + } + this.draw(); + this.updateUI(); + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + // ── Drawing ────────────────────────────────────────────────── + drawCell(ctx, x, y, colorIdx, alpha = 1) { + const color = COLORS[colorIdx] || COLORS[0]; + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * CELL, y * CELL, CELL, CELL); + if (colorIdx !== 0) { + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.18)"; + ctx.fillRect(x * CELL, y * CELL, CELL, 3); + ctx.fillRect(x * CELL, y * CELL, 3, CELL); + // Shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x * CELL + CELL - 3, y * CELL, 3, CELL); + ctx.fillRect(x * CELL, y * CELL + CELL - 3, CELL, 3); + } + // Grid line + ctx.globalAlpha = 0.08; + ctx.strokeStyle = "#fff"; + ctx.strokeRect(x * CELL, y * CELL, CELL, CELL); + ctx.globalAlpha = 1; + } + draw() { + const ctx = this.mainCtx; + ctx.clearRect(0, 0, COLS * CELL, ROWS * CELL); + // Grid + for (let r = 0; r < ROWS; r++) + for (let c = 0; c < COLS; c++) + this.drawCell(ctx, c, r, this.grid[r][c]); + // Ghost + const gr = this.ghostRow(); + const { shape, color, col } = this.current; + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c]) + this.drawCell(ctx, col + c, gr + r, color, 0.25); + // Current piece + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c]) + this.drawCell(ctx, col + c, this.current.row + r, color); + // Preview + this.drawPreview(); + } + drawPreview() { + const ctx = this.previewCtx; + ctx.clearRect(0, 0, PREVIEW_CELLS * CELL, PREVIEW_CELLS * CELL); + ctx.fillStyle = COLORS[0]; + ctx.fillRect(0, 0, PREVIEW_CELLS * CELL, PREVIEW_CELLS * CELL); + const { shape, color } = this.next; + const offX = Math.floor((PREVIEW_CELLS - shape[0].length) / 2); + const offY = Math.floor((PREVIEW_CELLS - shape.length) / 2); + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c]) + this.drawCell(ctx, offX + c, offY + r, color); + } + // ── UI update ──────────────────────────────────────────────── + updateUI() { + this.scoreEl.textContent = String(this.score); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + this.highScoreEl.textContent = String(this.highScore); + } +} +// ─── Bootstrap ────────────────────────────────────────────────────── +window.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":";AAAA,wEAAwE;AAExE,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC,cAAc;AAC/B,MAAM,aAAa,GAAG,CAAC,CAAC;AAYxB,MAAM,MAAM,GAA2B;IACrC,CAAC,EAAE,MAAM,EAAO,QAAQ;IACxB,CAAC,EAAE,SAAS,EAAI,YAAY;IAC5B,CAAC,EAAE,SAAS,EAAI,YAAY;IAC5B,CAAC,EAAE,SAAS,EAAI,cAAc;IAC9B,CAAC,EAAE,SAAS,EAAI,cAAc;IAC9B,CAAC,EAAE,SAAS,EAAI,aAAa;IAC7B,CAAC,EAAE,SAAS,EAAI,cAAc;IAC9B,CAAC,EAAE,SAAS,EAAI,WAAW;IAC3B,CAAC,EAAE,MAAM,EAAO,QAAQ;CACzB,CAAC;AAEF,2DAA2D;AAC3D,MAAM,MAAM,GAAY;IACtB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAA0B,IAAI;IACzC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAoB,IAAI;IACzC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAoB,IAAI;IACzC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAwB,IAAI;IACzC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAoB,IAAI;IACzC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAoB,IAAI;IACzC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAoB,IAAI;CAC1C,CAAC;AAEF,oCAAoC;AACpC,MAAM,YAAY,GAAsC;IACtD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACvC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACvC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACxC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IAC1C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IAC1C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;CACzC,CAAC;AAEF,+BAA+B;AAC/B,MAAM,OAAO,GAAsC;IACjD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;CAC1C,CAAC;AAEF,wEAAwE;AAExE,SAAS,UAAU,CAAC,IAAY,EAAE,IAAY;IAC5C,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,QAAQ,CAAC,KAAY;IAC5B,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IACvB,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC1B,MAAM,GAAG,GAAU,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;QACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;YACxB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,SAAS,CAAC,KAAY;IAC7B,OAAO,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,wEAAwE;AAExE,MAAM,UAAU;IAwCd;QAnCA,QAAG,GAAa,EAAE,CAAC;QACnB,UAAK,GAAG,CAAC,CAAC;QACV,UAAK,GAAG,CAAC,CAAC;QACV,UAAK,GAAG,CAAC,CAAC;QACV,aAAQ,GAAG,KAAK,CAAC;QACjB,WAAM,GAAG,KAAK,CAAC;QACf,iBAAY,GAAG,IAAI,CAAC,CAAC,KAAK;QAC1B,aAAQ,GAAG,CAAC,CAAC;QACb,cAAS,GAAG,GAAG,CAAC,CAAC,KAAK;QACtB,cAAS,GAAG,CAAC,CAAC;QACd,cAAS,GAAG,CAAC,CAAC;QACd,cAAS,GAAG,KAAK,CAAC;QAClB,WAAM,GAAG,CAAC,CAAC;QACX,cAAS,GAAG,CAAC,CAAC;QAcd,iCAAiC;QACjC,eAAU,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAErC,2BAA2B;QAC3B,aAAQ,GAAG,GAAG,CAAC,CAAE,+BAA+B;QAChD,YAAO,GAAG,EAAE,CAAC,CAAI,gBAAgB;QACjC,eAAU,GAAuD,IAAI,GAAG,EAAE,CAAC;QAGzE,MAAM,UAAU,GAAG,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAsB,CAAC;QAC/E,MAAM,aAAa,GAAG,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAsB,CAAC;QAErF,UAAU,CAAC,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC;QAC/B,UAAU,CAAC,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;QAChC,aAAa,CAAC,KAAK,GAAG,aAAa,GAAG,IAAI,CAAC;QAC3C,aAAa,CAAC,MAAM,GAAG,aAAa,GAAG,IAAI,CAAC;QAE5C,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;QAC5C,IAAI,CAAC,UAAU,GAAG,aAAa,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;QAElD,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC;QACjD,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC;QACjD,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC;QACjD,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAE,CAAC;QAC1D,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAE,CAAC;QACrD,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC,cAAc,CAAC,cAAc,CAAE,CAAC;QAE9D,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAEnC,kBAAkB;QAClB,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QACxD,IAAI,KAAK;YAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAEhD,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QACtC,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAClC,IAAI,CAAC,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,gEAAgE;IAChE,SAAS;QACP,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACjC,uBAAuB;QACvB,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC9C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED,WAAW;QACT,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5C,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAG,CAAC;IACzB,CAAC;IAED,gEAAgE;IAChE,SAAS;QACP,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC;IACrD,CAAC;IAED,UAAU;QACR,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG;YACb,KAAK;YACL,KAAK;YACL,GAAG,EAAE,CAAC;YACN,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;SAC9C,CAAC;QACF,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,SAAS,EAAE,CAAC;QAEjB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1E,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,OAAO,CAAC,KAAY,EAAE,GAAW,EAAE,GAAW;QAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACzC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAAE,SAAS;gBAC3B,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;gBACnB,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;gBACnB,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI;oBAAE,OAAO,KAAK,CAAC;gBACrD,IAAI,EAAE,GAAG,CAAC;oBAAE,SAAS,CAAC,kBAAkB;gBACxC,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;oBAAE,OAAO,KAAK,CAAC;YACtC,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,gEAAgE;IAChE,IAAI,CAAC,EAAU,EAAE,EAAU;QACzB,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;QACjC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;QACjC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;YAC7C,IAAI,CAAC,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;YACtB,IAAI,CAAC,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;YACtB,IAAI,IAAI,CAAC,SAAS,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;gBAC/B,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;gBACnC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACjB,IAAI,IAAI,CAAC,SAAS,GAAG,EAAE;oBAAE,IAAI,CAAC,IAAI,EAAE,CAAC;YACvC,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,+DAA+D;IAC/D,MAAM,CAAC,GAAW;QAChB,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC;QACpC,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAE1F,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,CAAC,CAAC;QACrC,MAAM,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC;QAC/C,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAEzC,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;YACjC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;YACjC,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;gBACnC,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC;gBAC9B,IAAI,CAAC,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;gBACtB,IAAI,CAAC,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;gBACtB,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC;gBAC9B,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;oBACnB,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;oBACnC,IAAI,CAAC,SAAS,EAAE,CAAC;oBACjB,IAAI,IAAI,CAAC,SAAS,GAAG,EAAE;wBAAE,IAAI,CAAC,IAAI,EAAE,CAAC;gBACvC,CAAC;gBACD,OAAO;YACT,CAAC;QACH,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,QAAQ;QACN,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;QAClC,IAAI,CAAC,KAAK,IAAI,OAAO,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAED,gEAAgE;IAChE,QAAQ;QACN,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,gEAAgE;IAChE,QAAQ;QACN,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;QACzB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,CAAC,EAAE,CAAC;QACtE,OAAO,CAAC,CAAC;IACX,CAAC;IAED,gEAAgE;IAChE,IAAI;QACF,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAChD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACzC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAAE,SAAS;gBAC3B,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;gBACnB,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;gBACnB,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;oBAAC,IAAI,CAAC,OAAO,EAAE,CAAC;oBAAC,OAAO;gBAAC,CAAC;gBACvC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC;YAC5B,CAAC;QACH,CAAC;QACD,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IACpC,CAAC;IAED,gEAAgE;IAChE,UAAU;QACR,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBACvC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACvB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC3C,OAAO,EAAE,CAAC;gBACV,CAAC,EAAE,CAAC,CAAC,0BAA0B;YACjC,CAAC;QACH,CAAC;QACD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC;YACtB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;YACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;YACjD,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC1B,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;gBACtB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACjE,CAAC;QACH,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,OAAO;QACL,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC;YAC5B,YAAY,CAAC,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;QACpE,CAAC;QACD,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,aAAa,CAAC,WAAW,GAAG,gCAAgC,CAAC;QAClE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;IACxC,CAAC;IAED,gEAAgE;IAChE,OAAO;QACL,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QACd,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QACtC,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAClC,IAAI,CAAC,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,+DAA+D;IAC/D,WAAW;QACT,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,CAAC,aAAa,CAAC,WAAW,GAAG,4BAA4B,CAAC;YAC9D,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;YACtC,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;YAClC,IAAI,CAAC,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,SAAS;QACP,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;YACzC,IAAI,CAAC,CAAC,MAAM;gBAAE,OAAO;YAErB,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;gBAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAAC,OAAO;YAAC,CAAC;YAC/D,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;gBAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBAAC,OAAO;YAAC,CAAC;YACnE,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM;gBAAE,OAAO;YAEzC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC;gBACd,KAAK,WAAW;oBACd,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;oBACjB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,WAAW,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;oBAC9F,MAAM;gBACR,KAAK,YAAY;oBACf,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;oBAChB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,WAAW,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;oBAC/F,MAAM;gBACR,KAAK,WAAW;oBACd,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAChB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,WAAW,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;oBAC9F,MAAM;gBACR,KAAK,SAAS,CAAC;gBACf,KAAK,GAAG,CAAC;gBACT,KAAK,GAAG;oBACN,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;oBACf,MAAM;gBACR,KAAK,GAAG,CAAC;gBACT,KAAK,GAAG,CAAC;gBACT,KAAK,SAAS;oBACZ,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;oBAChB,MAAM;gBACR,KAAK,GAAG;oBACN,CAAC,CAAC,cAAc,EAAE,CAAC;oBACnB,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAChB,MAAM;YACV,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;YACvC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,cAAc;IACd,UAAU,CAAC,GAAW;QACpB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC3C,MAAM,IAAI,GAAG,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC;YAC/B,IAAI,IAAI,GAAG,IAAI,CAAC,QAAQ;gBAAE,SAAS;YACnC,MAAM,SAAS,GAAG,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC;YACzC,IAAI,SAAS,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC9B,QAAQ,GAAG,EAAE,CAAC;oBACZ,KAAK,WAAW;wBAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;wBAAC,MAAM;oBAC3C,KAAK,YAAY;wBAAE,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;wBAAC,MAAM;oBAC1C,KAAK,WAAW;wBAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;wBAAC,MAAM;gBAC5C,CAAC;gBACD,KAAK,CAAC,UAAU,GAAG,GAAG,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,IAAI,CAAC,GAAW;QACd,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QAEzC,MAAM;QACN,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAErB,UAAU;QACV,MAAM,OAAO,GAAG,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC;QACpC,IAAI,OAAO,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACrB,iDAAiD;gBACjD,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;oBACpB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;oBACtB,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;gBACvB,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACzB,CAAC;YACD,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC;QACtB,CAAC;QAED,aAAa;QACb,IAAI,IAAI,CAAC,SAAS,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC7D,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,CAAC;QAED,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,gEAAgE;IAChE,QAAQ,CAAC,GAA6B,EAAE,CAAS,EAAE,CAAS,EAAE,QAAgB,EAAE,KAAK,GAAG,CAAC;QACvF,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;QAC5C,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC;QACxB,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC;QACtB,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAE7C,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;YACnB,YAAY;YACZ,GAAG,CAAC,SAAS,GAAG,wBAAwB,CAAC;YACzC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC1C,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;YAC1C,SAAS;YACT,GAAG,CAAC,SAAS,GAAG,kBAAkB,CAAC;YACnC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;YACrD,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACvD,CAAC;QAED,YAAY;QACZ,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC;QACvB,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC;QACzB,GAAG,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC/C,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC;IACtB,CAAC;IAED,IAAI;QACF,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC;QACzB,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC;QAE9C,OAAO;QACP,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE;YAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE;gBAC3B,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE9C,QAAQ;QACR,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC3B,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;YACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE;gBACtC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBACb,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAEvD,gBAAgB;QAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;YACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE;gBACtC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBACb,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QAE/D,UAAU;QACV,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED,WAAW;QACT,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC;QAC5B,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,GAAG,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC,CAAC;QAChE,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1B,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,GAAG,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC,CAAC;QAE/D,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,aAAa,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAE5D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;YACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE;gBACtC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBACb,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IACtD,CAAC;IAED,gEAAgE;IAChE,QAAQ;QACN,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,CAAC,WAAW,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxD,CAAC;CACF;AAED,uEAAuE;AACvE,MAAM,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAC/C,IAAI,UAAU,EAAE,CAAC;AACnB,CAAC,CAAC,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,567 @@ +"use strict"; +// ============================================================ +// TETRIS — Full TypeScript implementation +// Controls: ← → move | ↑ / Z / X rotate | ↓ soft-drop +// Space hard-drop | C hold | P pause | Enter start +// ============================================================ +// ── Constants ──────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const CELL = 30; // px per cell on the main board +const PREVIEW_CELL = 24; // px per cell in hold / next panels +// Points awarded per number of lines cleared (multiplied by level) +const LINE_POINTS = [0, 100, 300, 500, 800]; +// Drop interval (ms) per level (level index 0 = level 1) +function dropInterval(level) { + return Math.max(50, 1000 - (level - 1) * 90); +} +// DAS / ARR settings (ms) +const DAS = 150; // delay before auto-repeat starts +const ARR = 50; // auto-repeat rate once started +// ── Piece definitions ──────────────────────────────────────── +// Standard Tetris Guide colours +const PIECE_DEFS = [ + { color: "#00cfcf", shape: [[1, 1, 1, 1]] }, // I + { color: "#cfcf00", shape: [[1, 1], [1, 1]] }, // O + { color: "#9f00cf", shape: [[0, 1, 0], [1, 1, 1]] }, // T + { color: "#00cf00", shape: [[0, 1, 1], [1, 1, 0]] }, // S + { color: "#cf2000", shape: [[1, 1, 0], [0, 1, 1]] }, // Z + { color: "#2050cf", shape: [[1, 0, 0], [1, 1, 1]] }, // J + { color: "#cf7f00", shape: [[0, 0, 1], [1, 1, 1]] }, // L +]; +// ── Helpers ────────────────────────────────────────────────── +/** Rotate shape 90 ° clockwise */ +function rotateCW(shape) { + const R = shape.length, C = shape[0].length; + const out = Array.from({ length: C }, () => Array(R).fill(0)); + for (let r = 0; r < R; r++) + for (let c = 0; c < C; c++) + out[c][R - 1 - r] = shape[r][c]; + return out; +} +/** Rotate shape 90 ° counter-clockwise */ +function rotateCCW(shape) { + return rotateCW(rotateCW(rotateCW(shape))); +} +function emptyBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +/** 7-bag random piece generator */ +function makeBag() { + const bag = [...PIECE_DEFS]; + for (let i = bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [bag[i], bag[j]] = [bag[j], bag[i]]; + } + return bag; +} +function spawnPiece(def) { + const x = Math.floor((COLS - def.shape[0].length) / 2); + return { def, shape: def.shape, x, y: 0 }; +} +// ── Collision / placement ──────────────────────────────────── +function isValid(board, shape, px, py) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = px + c, ny = py + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return false; + if (ny >= 0 && board[ny][nx] !== null) + return false; + } + } + return true; +} +/** Lock piece into board, return new board */ +function lockPiece(board, piece) { + const b = board.map(row => [...row]); + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + const ny = piece.y + r, nx = piece.x + c; + if (ny >= 0) + b[ny][nx] = piece.def.color; + } + } + return b; +} +/** Clear full lines, return { board, count } */ +function clearLines(board) { + const kept = board.filter(row => row.some(c => c === null)); + const count = ROWS - kept.length; + const empty = Array.from({ length: count }, () => Array(COLS).fill(null)); + return { board: [...empty, ...kept], count }; +} +/** Ghost piece: drop until collision */ +function ghostY(board, piece) { + let gy = piece.y; + while (isValid(board, piece.shape, piece.x, gy + 1)) + gy++; + return gy; +} +// ── Wall-kick offsets (SRS-lite) ───────────────────────────── +// Tries these (dx, dy) offsets when rotation collides +const KICKS = [ + [0, 0], [-1, 0], [1, 0], [-2, 0], [2, 0], [0, -1], [0, -2] +]; +function tryRotate(board, piece, newShape) { + for (const [dx, dy] of KICKS) { + if (isValid(board, newShape, piece.x + dx, piece.y + dy)) { + return Object.assign(Object.assign({}, piece), { shape: newShape, x: piece.x + dx, y: piece.y + dy }); + } + } + return null; +} +// ── Rendering helpers ───────────────────────────────────────── +function drawCell(ctx, x, y, size, color, alpha = 1) { + const s = size; + const pad = 1; + ctx.save(); + ctx.globalAlpha = alpha; + // Main fill + ctx.fillStyle = color; + ctx.fillRect(x * s + pad, y * s + pad, s - pad * 2, s - pad * 2); + // Highlight (top-left edge) + ctx.fillStyle = "rgba(255,255,255,0.30)"; + ctx.fillRect(x * s + pad, y * s + pad, s - pad * 2, 4); + ctx.fillRect(x * s + pad, y * s + pad, 4, s - pad * 2); + // Shadow (bottom-right edge) + ctx.fillStyle = "rgba(0,0,0,0.35)"; + ctx.fillRect(x * s + pad, y * s + s - pad - 4, s - pad * 2, 4); + ctx.fillRect(x * s + s - pad - 4, y * s + pad, 4, s - pad * 2); + ctx.restore(); +} +function drawGrid(ctx, w, h, cell) { + ctx.save(); + ctx.strokeStyle = "rgba(255,255,255,0.05)"; + ctx.lineWidth = 1; + for (let c = 0; c <= w; c++) { + ctx.beginPath(); + ctx.moveTo(c * cell, 0); + ctx.lineTo(c * cell, h * cell); + ctx.stroke(); + } + for (let r = 0; r <= h; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * cell); + ctx.lineTo(w * cell, r * cell); + ctx.stroke(); + } + ctx.restore(); +} +function drawShape(ctx, shape, color, cellSize, offsetX = 0, offsetY = 0, alpha = 1) { + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c]) + drawCell(ctx, offsetX + c, offsetY + r, cellSize, color, alpha); +} +/** Center a shape in a canvas of (canvasW x canvasH) grid cells */ +function centeredOffsets(shape, canvasW, canvasH) { + const ox = Math.floor((canvasW - shape[0].length) / 2); + const oy = Math.floor((canvasH - shape.length) / 2); + return [ox, oy]; +} +// ── Main game class ────────────────────────────────────────── +class TetrisGame { + constructor() { + // Game state + this.state = "idle"; + this.board = emptyBoard(); + this.current = null; + this.held = null; + this.canHold = true; + this.bag = []; + this.nextDef = null; + this.score = 0; + this.level = 1; + this.lines = 0; + // Timing + this.lastTime = 0; + this.dropAcc = 0; // accumulated drop time + this.lockDelay = 0; // ms since piece landed (lock delay) + this.lockMoves = 0; // how many moves/rotations since landing + this.isGrounded = false; + // Input + this.keysDown = new Set(); + this.dasTimer = {}; + this.arrTimer = {}; + // Flash rows on line clear + this.flashRows = []; + this.flashTimer = 0; + this.FLASH_DURATION = 120; // ms + // Combo + this.combo = -1; + // ── Main loop ──────────────────────────────────────────────── + this.loop = (now) => { + const dt = Math.min(now - this.lastTime, 100); // cap at 100ms + this.lastTime = now; + this.update(dt); + this.render(); + requestAnimationFrame(this.loop); + }; + const getCanvas = (id) => document.getElementById(id).getContext("2d"); + this.mainCtx = getCanvas("game-canvas"); + this.holdCtx = getCanvas("hold-canvas"); + this.nextCtx = getCanvas("next-canvas"); + this.scoreEl = document.getElementById("score"); + this.levelEl = document.getElementById("level"); + this.linesEl = document.getElementById("lines"); + this.overlay = document.getElementById("overlay"); + this.overlayTitle = document.getElementById("overlay-title"); + this.overlayMsg = document.getElementById("overlay-msg"); + this.bindInput(); + this.showOverlay("TETRIS", "Press Enter to start"); + requestAnimationFrame(this.loop); + } + // ── Input ────────────────────────────────────────────────── + bindInput() { + window.addEventListener("keydown", e => { + if (this.keysDown.has(e.code)) + return; // ignore repeats here + this.keysDown.add(e.code); + this.onKeyDown(e.code); + }); + window.addEventListener("keyup", e => { + this.keysDown.delete(e.code); + delete this.dasTimer[e.code]; + delete this.arrTimer[e.code]; + }); + } + onKeyDown(code) { + if (code === "Enter") { + if (this.state === "idle" || this.state === "over") + this.startGame(); + else if (this.state === "playing" || this.state === "paused") + this.togglePause(); + return; + } + if (code === "KeyP") { + if (this.state === "playing" || this.state === "paused") + this.togglePause(); + return; + } + if (this.state !== "playing") + return; + switch (code) { + case "ArrowLeft": + this.moveH(-1); + break; + case "ArrowRight": + this.moveH(1); + break; + case "ArrowDown": + this.softDrop(); + break; + case "ArrowUp": + case "KeyX": + this.rotatePiece(true); + break; + case "KeyZ": + this.rotatePiece(false); + break; + case "Space": + this.hardDrop(); + break; + case "KeyC": + case "ShiftLeft": + case "ShiftRight": + this.holdPiece(); + break; + } + } + handleDAS(dt) { + if (this.state !== "playing") + return; + const autoRepeatKey = (code, action) => { + if (!this.keysDown.has(code)) + return; + if (this.dasTimer[code] === undefined) + this.dasTimer[code] = 0; + this.dasTimer[code] += dt; + if (this.dasTimer[code] >= DAS) { + if (this.arrTimer[code] === undefined) + this.arrTimer[code] = 0; + this.arrTimer[code] += dt; + while (this.arrTimer[code] >= ARR) { + action(); + this.arrTimer[code] -= ARR; + } + } + }; + autoRepeatKey("ArrowLeft", () => this.moveH(-1)); + autoRepeatKey("ArrowRight", () => this.moveH(1)); + autoRepeatKey("ArrowDown", () => this.softDrop()); + } + // ── Game control ──────────────────────────────────────────── + startGame() { + this.board = emptyBoard(); + this.held = null; + this.canHold = true; + this.score = 0; + this.level = 1; + this.lines = 0; + this.combo = -1; + this.bag = []; + this.flashRows = []; + this.flashTimer = 0; + this.updateUI(); + this.nextDef = this.pullFromBag(); + this.spawnNext(); + this.state = "playing"; + this.hideOverlay(); + } + togglePause() { + if (this.state === "playing") { + this.state = "paused"; + this.showOverlay("PAUSED", "Press Enter or P to resume"); + } + else if (this.state === "paused") { + this.state = "playing"; + this.hideOverlay(); + this.lastTime = performance.now(); // reset timing to avoid jump + } + } + gameOver() { + this.state = "over"; + this.showOverlay("GAME OVER", `Score: ${this.score}<br>Press Enter to restart`); + } + // ── Bag & spawn ───────────────────────────────────────────── + pullFromBag() { + if (this.bag.length === 0) + this.bag = makeBag(); + return this.bag.shift(); + } + spawnNext() { + const def = this.nextDef; + this.nextDef = this.pullFromBag(); + this.current = spawnPiece(def); + this.canHold = true; + this.isGrounded = false; + this.lockDelay = 0; + this.lockMoves = 0; + this.dropAcc = 0; + // Immediate game-over check + if (!isValid(this.board, this.current.shape, this.current.x, this.current.y)) { + this.gameOver(); + } + } + // ── Movements ─────────────────────────────────────────────── + moveH(dx) { + if (!this.current) + return; + const nx = this.current.x + dx; + if (isValid(this.board, this.current.shape, nx, this.current.y)) { + this.current.x = nx; + this.onPieceMove(); + } + } + softDrop() { + if (!this.current) + return; + const ny = this.current.y + 1; + if (isValid(this.board, this.current.shape, this.current.x, ny)) { + this.current.y = ny; + this.score += 1; + this.dropAcc = 0; + this.isGrounded = false; + this.scoreEl.textContent = String(this.score); + } + } + hardDrop() { + if (!this.current) + return; + const gy = ghostY(this.board, this.current); + this.score += (gy - this.current.y) * 2; + this.current.y = gy; + this.scoreEl.textContent = String(this.score); + this.lock(); + } + rotatePiece(cw) { + if (!this.current) + return; + const newShape = cw ? rotateCW(this.current.shape) : rotateCCW(this.current.shape); + const rotated = tryRotate(this.board, this.current, newShape); + if (rotated) { + this.current = rotated; + this.onPieceMove(); + } + } + holdPiece() { + if (!this.current || !this.canHold) + return; + const heldDef = this.current.def; + if (this.held) { + this.current = spawnPiece(this.held); + } + else { + this.spawnNext(); + } + this.held = heldDef; + this.canHold = false; + this.isGrounded = false; + this.lockDelay = 0; + this.lockMoves = 0; + this.dropAcc = 0; + } + /** Called whenever piece moves or rotates; resets lock-delay if grounded */ + onPieceMove() { + if (!this.current) + return; + const grounded = !isValid(this.board, this.current.shape, this.current.x, this.current.y + 1); + if (grounded && this.isGrounded && this.lockMoves < 15) { + this.lockDelay = 0; // reset lock delay on valid move/rotate + this.lockMoves++; + } + this.isGrounded = grounded; + } + // ── Locking ───────────────────────────────────────────────── + lock() { + if (!this.current) + return; + const locked = lockPiece(this.board, this.current); + const cleared = clearLines(locked); + this.current = null; + if (cleared.count > 0) { + // Find which rows were cleared (in the locked board, before removal) + this.flashRows = []; + for (let r = ROWS - 1; r >= 0 && this.flashRows.length < cleared.count; r--) { + if (locked[r].every(c => c !== null)) + this.flashRows.push(r); + } + // Keep the LOCKED (un-cleared) board so flash rows are visible + this.board = locked; + this.flashTimer = this.FLASH_DURATION; + this.combo++; + const pts = (LINE_POINTS[cleared.count] + (this.combo > 0 ? 50 * this.combo : 0)) * this.level; + this.score += pts; + this.lines += cleared.count; + this.level = Math.floor(this.lines / 10) + 1; + this.updateUI(); + // After flash, apply the cleared board and spawn next piece + setTimeout(() => { + this.flashRows = []; + this.flashTimer = 0; + this.board = cleared.board; + this.spawnNext(); + }, this.FLASH_DURATION); + } + else { + this.board = locked; + this.combo = -1; + this.updateUI(); + this.spawnNext(); + } + } + // ── Update ─────────────────────────────────────────────────── + update(dt) { + // Decrement flash timer regardless of piece state + if (this.flashTimer > 0) + this.flashTimer = Math.max(0, this.flashTimer - dt); + if (this.state !== "playing" || !this.current) + return; + this.handleDAS(dt); + const grounded = !isValid(this.board, this.current.shape, this.current.x, this.current.y + 1); + if (grounded) { + if (!this.isGrounded) { + this.isGrounded = true; + this.lockDelay = 0; + this.lockMoves = 0; + } + this.lockDelay += dt; + if (this.lockDelay >= 500) { + this.lock(); + return; + } + } + else { + this.isGrounded = false; + this.dropAcc += dt; + const interval = dropInterval(this.level); + while (this.dropAcc >= interval) { + this.current.y++; + this.dropAcc -= interval; + // Recheck grounded after drop step + if (!isValid(this.board, this.current.shape, this.current.x, this.current.y + 1)) { + this.isGrounded = true; + this.lockDelay = 0; + this.lockMoves = 0; + this.dropAcc = 0; + break; + } + } + } + } + // ── Render ─────────────────────────────────────────────────── + render() { + // Main board + const ctx = this.mainCtx; + ctx.clearRect(0, 0, COLS * CELL, ROWS * CELL); + // Background + ctx.fillStyle = "#111827"; + ctx.fillRect(0, 0, COLS * CELL, ROWS * CELL); + drawGrid(ctx, COLS, ROWS, CELL); + // Placed cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const color = this.board[r][c]; + if (color) { + const flashing = this.flashRows.includes(r); + const alpha = flashing + ? 0.4 + 0.6 * Math.abs(Math.sin((this.flashTimer / this.FLASH_DURATION) * Math.PI)) + : 1; + drawCell(ctx, c, r, CELL, color, alpha); + } + } + } + // Ghost piece + if (this.current && this.state === "playing") { + const gy = ghostY(this.board, this.current); + if (gy !== this.current.y) { + drawShape(ctx, this.current.shape, this.current.def.color, CELL, this.current.x, gy, 0.22); + } + } + // Current piece + if (this.current && this.state === "playing") { + drawShape(ctx, this.current.shape, this.current.def.color, CELL, this.current.x, this.current.y); + } + // Hold preview + const hCtx = this.holdCtx; + hCtx.clearRect(0, 0, 5 * PREVIEW_CELL, 5 * PREVIEW_CELL); + hCtx.fillStyle = "#0d1117"; + hCtx.fillRect(0, 0, 5 * PREVIEW_CELL, 5 * PREVIEW_CELL); + if (this.held) { + const [ox, oy] = centeredOffsets(this.held.shape, 5, 5); + drawShape(hCtx, this.held.shape, this.held.color, PREVIEW_CELL, ox, oy, this.canHold ? 1 : 0.4); + } + // Next preview + const nCtx = this.nextCtx; + nCtx.clearRect(0, 0, 5 * PREVIEW_CELL, 5 * PREVIEW_CELL); + nCtx.fillStyle = "#0d1117"; + nCtx.fillRect(0, 0, 5 * PREVIEW_CELL, 5 * PREVIEW_CELL); + if (this.nextDef) { + const [ox, oy] = centeredOffsets(this.nextDef.shape, 5, 5); + drawShape(nCtx, this.nextDef.shape, this.nextDef.color, PREVIEW_CELL, ox, oy); + } + } + // ── UI helpers ─────────────────────────────────────────────── + updateUI() { + this.scoreEl.textContent = String(this.score); + this.levelEl.textContent = String(this.level); + this.linesEl.textContent = String(this.lines); + } + showOverlay(title, msg) { + this.overlayTitle.textContent = title; + this.overlayMsg.innerHTML = msg; + this.overlay.style.display = "flex"; + } + hideOverlay() { + this.overlay.style.display = "none"; + } +} +// ── Bootstrap ──────────────────────────────────────────────── +window.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,563 @@ +"use strict"; +// ───────────────────────────────────────────────────────────────────────────── +// Constants +// ───────────────────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell on the main board +const MINI = 26; // px per cell in preview panels +/** Cell colour by piece index (0 = empty). */ +const COLORS = [ + '#0d0d1a', // 0 empty / background + '#00d8d8', // 1 I – cyan + '#d8d800', // 2 O – yellow + '#a000d8', // 3 T – purple + '#00c000', // 4 S – green + '#d81800', // 5 Z – red + '#0055e0', // 6 J – blue + '#e08000', // 7 L – orange +]; +/** + * Canonical spawn matrices for each tetromino. + * Values equal the COLORS index so they carry colour information. + */ +const SHAPES = [ + // 0: I 4×4 + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + // 1: O 2×2 + [[2, 2], [2, 2]], + // 2: T 3×3 + [[0, 3, 0], [3, 3, 3], [0, 0, 0]], + // 3: S 3×3 + [[0, 4, 4], [4, 4, 0], [0, 0, 0]], + // 4: Z 3×3 + [[5, 5, 0], [0, 5, 5], [0, 0, 0]], + // 5: J 3×3 + [[6, 0, 0], [6, 6, 6], [0, 0, 0]], + // 6: L 3×3 + [[0, 0, 7], [7, 7, 7], [0, 0, 0]], +]; +const KICK_JLSTZ = { + '0>1': [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + '1>0': [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + '1>2': [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + '2>1': [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + '2>3': [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + '3>2': [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + '3>0': [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + '0>3': [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], +}; +const KICK_I = { + '0>1': [[0, 0], [-2, 0], [1, 0], [-2, 1], [1, -2]], + '1>0': [[0, 0], [2, 0], [-1, 0], [2, -1], [-1, 2]], + '1>2': [[0, 0], [-1, 0], [2, 0], [-1, -2], [2, 1]], + '2>1': [[0, 0], [1, 0], [-2, 0], [1, 2], [-2, -1]], + '2>3': [[0, 0], [2, 0], [-1, 0], [2, -1], [-1, 2]], + '3>2': [[0, 0], [-2, 0], [1, 0], [-2, 1], [1, -2]], + '3>0': [[0, 0], [1, 0], [-2, 0], [1, 2], [-2, -1]], + '0>3': [[0, 0], [-1, 0], [2, 0], [-1, -2], [2, 1]], +}; +/** Score awarded per number of lines cleared simultaneously (×level). */ +const LINE_PTS = [0, 100, 300, 500, 800]; +/** Drop interval (ms per row) for a given level (1-based). */ +function levelSpeed(lvl) { + const table = [800, 717, 633, 550, 467, 383, 300, 217, 133, 100, + 83, 83, 83, 67, 67, 67, 50, 50, 50, 33]; + return table[Math.min(lvl - 1, table.length - 1)]; +} +// ───────────────────────────────────────────────────────────────────────────── +// Matrix helpers +// ───────────────────────────────────────────────────────────────────────────── +/** Rotate a 2-D matrix 90° clockwise. */ +function rotCW(m) { + const R = m.length, C = m[0].length; + const out = Array.from({ length: C }, () => Array(R).fill(0)); + for (let r = 0; r < R; r++) + for (let c = 0; c < C; c++) + out[c][R - 1 - r] = m[r][c]; + return out; +} +/** Rotate a 2-D matrix 90° counter-clockwise. */ +function rotCCW(m) { + const R = m.length, C = m[0].length; + const out = Array.from({ length: C }, () => Array(R).fill(0)); + for (let r = 0; r < R; r++) + for (let c = 0; c < C; c++) + out[C - 1 - c][r] = m[r][c]; + return out; +} +// ───────────────────────────────────────────────────────────────────────────── +// Game class +// ───────────────────────────────────────────────────────────────────────────── +class Game { + // ── Constructor ─────────────────────────────────────────────────────────── + constructor() { + // ── Board state ──────────────────────────────────────────────────────────── + this.board = []; + this.current = null; // set in startGame() + this.next = null; + this.held = null; + this.canHold = true; + // ── Stats ────────────────────────────────────────────────────────────────── + this.score = 0; + this.level = 1; + this.lines = 0; + this.hiScore = parseInt(localStorage.getItem('tetris-hi') ?? '0', 10); + // ── 7-bag randomiser ────────────────────────────────────────────────────── + this.bag = []; + // ── Timing ──────────────────────────────────────────────────────────────── + this.dropTimer = 0; + this.prevTs = 0; + this.rafId = 0; + // ── State ───────────────────────────────────────────────────────────────── + this.state = 'idle'; + // Main board canvas + const bc = document.getElementById('board'); + bc.width = COLS * BLOCK; + bc.height = ROWS * BLOCK; + this.boardCtx = bc.getContext('2d'); + // Preview canvases + this.nextCanvas = document.getElementById('next-canvas'); + this.nextCtx = this.nextCanvas.getContext('2d'); + this.holdCanvas = document.getElementById('hold-canvas'); + this.holdCtx = this.holdCanvas.getContext('2d'); + // HUD elements + this.scoreEl = document.getElementById('score'); + this.levelEl = document.getElementById('level'); + this.linesEl = document.getElementById('lines'); + this.hiEl = document.getElementById('hi'); + this.overlay = document.getElementById('overlay'); + this.oTitle = document.getElementById('o-title'); + this.oMsg = document.getElementById('o-msg'); + this.board = this.emptyBoard(); + this.hiEl.textContent = this.hiScore.toLocaleString(); + this.bindKeys(); + this.render(); + this.showOverlay('TETRIS', 'Press Enter or R to start'); + } + // ── Helpers ─────────────────────────────────────────────────────────────── + emptyBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(0)); + } + shuffleBag() { + this.bag = [0, 1, 2, 3, 4, 5, 6]; + for (let i = 6; i > 0; i--) { + const j = (Math.random() * (i + 1)) | 0; + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + drawFromBag() { + if (!this.bag.length) + this.shuffleBag(); + return this.bag.pop(); + } + makePiece(type) { + const t = type ?? this.drawFromBag(); + const shape = SHAPES[t].map(row => [...row]); + return { + shape, + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + rot: 0, + type: t, + }; + } + // ── Collision ───────────────────────────────────────────────────────────── + /** Returns true if the given piece (+ optional offset / alternate shape) fits. */ + fits(p, dx = 0, dy = 0, shape = p.shape) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = p.x + c + dx; + const ny = p.y + r + dy; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return false; + if (ny >= 0 && this.board[ny][nx]) + return false; + } + } + return true; + } + /** Returns the lowest y the current piece can reach via straight drop. */ + ghostRow() { + let dy = 0; + while (this.fits(this.current, 0, dy + 1)) + dy++; + return this.current.y + dy; + } + // ── Actions ─────────────────────────────────────────────────────────────── + rotate(cw) { + if (this.current.type === 1) + return; // O piece is symmetric + const ns = cw ? rotCW(this.current.shape) : rotCCW(this.current.shape); + const nr = ((this.current.rot + (cw ? 1 : 3)) % 4); + const key = `${this.current.rot}>${nr}`; + const kicks = this.current.type === 0 ? KICK_I[key] : KICK_JLSTZ[key]; + for (const [kx, ky] of kicks) { + if (this.fits(this.current, kx, ky, ns)) { + this.current.shape = ns; + this.current.rot = nr; + this.current.x += kx; + this.current.y += ky; + return; + } + } + } + moveH(dx) { + if (this.fits(this.current, dx, 0)) + this.current.x += dx; + } + softDrop() { + if (this.fits(this.current, 0, 1)) { + this.current.y++; + this.score++; + this.dropTimer = 0; + } + } + hardDrop() { + const dy = this.ghostRow() - this.current.y; + this.current.y += dy; + this.score += dy * 2; + this.dropTimer = 0; + this.lock(); + } + holdPiece() { + if (!this.canHold) + return; + const savedType = this.current.type; + if (this.held) { + this.current = this.makePiece(this.held.type); + } + else { + this.current = this.next; + this.next = this.makePiece(); + } + this.held = this.makePiece(savedType); + this.canHold = false; + this.dropTimer = 0; + } + /** Lock the current piece onto the board, clear lines, spawn next. */ + lock() { + for (let r = 0; r < this.current.shape.length; r++) { + for (let c = 0; c < this.current.shape[r].length; c++) { + if (!this.current.shape[r][c]) + continue; + const ny = this.current.y + r; + if (ny < 0) { + this.triggerGameOver(); + return; + } + this.board[ny][this.current.x + c] = this.current.shape[r][c]; + } + } + // Clear complete lines + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every(v => v !== 0)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(0)); + r++; + cleared++; + } + } + if (cleared) { + this.score += LINE_PTS[cleared] * this.level; + this.lines += cleared; + this.level = Math.floor(this.lines / 10) + 1; + } + this.updateHUD(); + // Advance pieces + this.current = this.next; + this.next = this.makePiece(); + this.canHold = true; + this.dropTimer = 0; + if (!this.fits(this.current)) + this.triggerGameOver(); + } + triggerGameOver() { + this.state = 'over'; + cancelAnimationFrame(this.rafId); + if (this.score > this.hiScore) { + this.hiScore = this.score; + localStorage.setItem('tetris-hi', String(this.hiScore)); + this.hiEl.textContent = this.hiScore.toLocaleString(); + } + this.render(); + this.showOverlay('GAME OVER', `Score: ${this.score.toLocaleString()}\n\nPress R to restart`); + } + // ── Game lifecycle ──────────────────────────────────────────────────────── + startGame() { + cancelAnimationFrame(this.rafId); + this.board = this.emptyBoard(); + this.score = 0; + this.level = 1; + this.lines = 0; + this.held = null; + this.canHold = true; + this.bag = []; + this.dropTimer = 0; + this.prevTs = 0; + this.state = 'playing'; + this.current = this.makePiece(); + this.next = this.makePiece(); + this.updateHUD(); + this.hideOverlay(); + this.rafId = requestAnimationFrame(ts => this.loop(ts)); + } + togglePause() { + if (this.state === 'playing') { + this.state = 'paused'; + cancelAnimationFrame(this.rafId); + this.showOverlay('PAUSED', 'Press P or Esc to resume'); + } + else if (this.state === 'paused') { + this.state = 'playing'; + this.prevTs = 0; + this.hideOverlay(); + this.rafId = requestAnimationFrame(ts => this.loop(ts)); + } + } + // ── Input ───────────────────────────────────────────────────────────────── + bindKeys() { + const DAS = 140; // delayed auto-shift (ms) + const ARR = 45; // auto-repeat rate (ms) + const held = {}; + const timers = {}; + const startRepeat = (id, fn) => { + timers[id] = window.setTimeout(() => { + timers[`${id}i`] = window.setInterval(fn, ARR); + }, DAS); + }; + const stopRepeat = (id) => { + clearTimeout(timers[id]); + clearInterval(timers[`${id}i`]); + }; + document.addEventListener('keydown', e => { + // Prevent browser scrolling + if (['ArrowLeft', 'ArrowRight', 'ArrowDown', 'ArrowUp', 'Space'].includes(e.key)) { + e.preventDefault(); + } + const code = e.code; + if (held[code]) + return; + held[code] = true; + // Start / restart from overlay + if (this.state === 'idle' || this.state === 'over') { + if (code === 'Enter' || code === 'KeyR') + this.startGame(); + return; + } + // Pause toggle (works regardless of paused/playing) + if (code === 'KeyP' || code === 'Escape') { + this.togglePause(); + return; + } + if (this.state !== 'playing') + return; + switch (code) { + case 'ArrowLeft': + this.moveH(-1); + startRepeat('L', () => this.moveH(-1)); + break; + case 'ArrowRight': + this.moveH(1); + startRepeat('R', () => this.moveH(1)); + break; + case 'ArrowDown': + this.softDrop(); + startRepeat('D', () => this.softDrop()); + break; + case 'ArrowUp': + this.rotate(true); + break; + case 'KeyZ': + this.rotate(false); + break; + case 'KeyX': + this.rotate(true); + break; + case 'Space': + this.hardDrop(); + break; + case 'ShiftLeft': + case 'ShiftRight': + case 'KeyC': + this.holdPiece(); + break; + } + }); + document.addEventListener('keyup', e => { + held[e.code] = false; + if (e.code === 'ArrowLeft') + stopRepeat('L'); + if (e.code === 'ArrowRight') + stopRepeat('R'); + if (e.code === 'ArrowDown') + stopRepeat('D'); + }); + } + // ── HUD ─────────────────────────────────────────────────────────────────── + updateHUD() { + this.scoreEl.textContent = this.score.toLocaleString(); + this.levelEl.textContent = String(this.level); + this.linesEl.textContent = String(this.lines); + } + showOverlay(title, msg) { + this.oTitle.textContent = title; + this.oMsg.textContent = msg; + this.overlay.style.display = 'flex'; + } + hideOverlay() { + this.overlay.style.display = 'none'; + } + // ── Game loop ───────────────────────────────────────────────────────────── + loop(ts) { + if (this.state !== 'playing') + return; + if (!this.prevTs) + this.prevTs = ts; + const dt = ts - this.prevTs; + this.prevTs = ts; + this.dropTimer += dt; + if (this.dropTimer >= levelSpeed(this.level)) { + this.dropTimer -= levelSpeed(this.level); + if (this.fits(this.current, 0, 1)) { + this.current.y++; + } + else { + this.lock(); + if (this.state !== 'playing') { + this.render(); + return; + } + } + } + this.render(); + this.rafId = requestAnimationFrame(ts => this.loop(ts)); + } + // ── Rendering ───────────────────────────────────────────────────────────── + render() { + this.drawBoard(); + this.drawPanel(this.nextCtx, this.nextCanvas, this.next ?? null); + this.drawPanel(this.holdCtx, this.holdCanvas, this.held, !this.canHold); + } + drawBoard() { + const ctx = this.boardCtx; + const W = COLS * BLOCK; + const H = ROWS * BLOCK; + // Background + ctx.fillStyle = '#0d0d1a'; + ctx.fillRect(0, 0, W, H); + // Subtle grid + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(W, r * BLOCK); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, H); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < ROWS; r++) + for (let c = 0; c < COLS; c++) + if (this.board[r][c]) + this.drawCell(ctx, c, r, this.board[r][c], BLOCK); + if (this.state !== 'playing') + return; + // Ghost piece + const gy = this.ghostRow(); + if (gy > this.current.y) { + for (let r = 0; r < this.current.shape.length; r++) + for (let c = 0; c < this.current.shape[r].length; c++) + if (this.current.shape[r][c] && gy + r >= 0) + this.drawGhost(ctx, this.current.x + c, gy + r, this.current.shape[r][c], BLOCK); + } + // Current piece + for (let r = 0; r < this.current.shape.length; r++) + for (let c = 0; c < this.current.shape[r].length; c++) + if (this.current.shape[r][c] && this.current.y + r >= 0) + this.drawCell(ctx, this.current.x + c, this.current.y + r, this.current.shape[r][c], BLOCK); + } + /** Draw a filled, shaded tetromino cell. */ + drawCell(ctx, col, row, colorIdx, bs) { + const x = col * bs + 1; + const y = row * bs + 1; + const s = bs - 2; + ctx.fillStyle = COLORS[colorIdx]; + ctx.fillRect(x, y, s, s); + // Inner shine gradient + const g = ctx.createLinearGradient(x, y, x, y + s); + g.addColorStop(0, 'rgba(255,255,255,0.28)'); + g.addColorStop(0.45, 'rgba(255,255,255,0.06)'); + g.addColorStop(1, 'rgba(0,0,0,0.22)'); + ctx.fillStyle = g; + ctx.fillRect(x, y, s, s); + // Crisp top-left bevel + ctx.fillStyle = 'rgba(255,255,255,0.18)'; + ctx.fillRect(x, y, s, 2); + ctx.fillRect(x, y, 2, s); + // Bottom-right shadow + ctx.fillStyle = 'rgba(0,0,0,0.30)'; + ctx.fillRect(x, y + s - 2, s, 2); + ctx.fillRect(x + s - 2, y, 2, s); + } + /** Draw an outline-only ghost cell. */ + drawGhost(ctx, col, row, colorIdx, bs) { + const x = col * bs + 2; + const y = row * bs + 2; + const s = bs - 4; + ctx.strokeStyle = COLORS[colorIdx]; + ctx.globalAlpha = 0.4; + ctx.lineWidth = 1.5; + ctx.strokeRect(x, y, s, s); + ctx.globalAlpha = 1; + } + /** Render a mini piece preview into a side panel canvas. */ + drawPanel(ctx, canvas, piece, dimmed = false) { + const W = canvas.width; + const H = canvas.height; + ctx.fillStyle = '#0d0d1a'; + ctx.fillRect(0, 0, W, H); + if (!piece) + return; + const shape = piece.shape; + const rows = shape.length; + const cols = shape[0].length; + const ox = ((W - cols * MINI) / 2) | 0; + const oy = ((H - rows * MINI) / 2) | 0; + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (!shape[r][c]) + continue; + const px = ox + c * MINI + 1; + const py = oy + r * MINI + 1; + const s = MINI - 2; + ctx.fillStyle = dimmed ? '#2e2e4a' : COLORS[shape[r][c]]; + ctx.fillRect(px, py, s, s); + if (!dimmed) { + const g = ctx.createLinearGradient(px, py, px, py + s); + g.addColorStop(0, 'rgba(255,255,255,0.28)'); + g.addColorStop(0.45, 'rgba(255,255,255,0.06)'); + g.addColorStop(1, 'rgba(0,0,0,0.22)'); + ctx.fillStyle = g; + ctx.fillRect(px, py, s, s); + ctx.fillStyle = 'rgba(255,255,255,0.18)'; + ctx.fillRect(px, py, s, 2); + ctx.fillRect(px, py, 2, s); + } + } + } + } +} +// ───────────────────────────────────────────────────────────────────────────── +// Bootstrap +// ───────────────────────────────────────────────────────────────────────────── +window.addEventListener('DOMContentLoaded', () => { new Game(); }); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts @@ -0,0 +1,56 @@ +type Piece = number[][]; +type Board = number[][]; +declare enum PieceType { + I = 0, + O = 1, + T = 2, + S = 3, + Z = 4, + J = 5, + L = 6 +} +interface GameState { + board: Board; + currentPiece: Piece; + currentType: PieceType; + nextPiece: Piece; + nextType: PieceType; + posX: number; + posY: number; + score: number; + level: number; + linesCleared: number; + gameOver: boolean; + paused: boolean; +} +declare const COLORS: string[]; +declare const PIECE_SHAPES: Piece[]; +declare class TetrisGame { + private canvas; + private ctx; + private gameState; + private gameLoopId; + private dropSpeed; + private lastDropTime; + constructor(canvasId: string); + private createEmptyBoard; + private setupEventListeners; + private handleKeyPress; + private movePiece; + private rotatePiece; + private rotatePieceClockwise; + private isValidPosition; + private lockPiece; + private clearLines; + private spawnNewPiece; + private copyPiece; + private draw; + private drawCell; + private updateUI; + private drawNextPiece; + private gameLoop; + start(): void; + stop(): void; + private resetGame; +} +//# sourceMappingURL=game.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"game.d.ts","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"AAEA,KAAK,KAAK,GAAG,MAAM,EAAE,EAAE,CAAC;AACxB,KAAK,KAAK,GAAG,MAAM,EAAE,EAAE,CAAC;AAExB,aAAK,SAAS;IACZ,CAAC,IAAI;IACL,CAAC,IAAI;IACL,CAAC,IAAI;IACL,CAAC,IAAI;IACL,CAAC,IAAI;IACL,CAAC,IAAI;IACL,CAAC,IAAI;CACN;AAED,UAAU,SAAS;IACjB,KAAK,EAAE,KAAK,CAAC;IACb,YAAY,EAAE,KAAK,CAAC;IACpB,WAAW,EAAE,SAAS,CAAC;IACvB,SAAS,EAAE,KAAK,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,QAAA,MAAM,MAAM,UAQX,CAAC;AAEF,QAAA,MAAM,YAAY,EAAE,KAAK,EAexB,CAAC;AAEF,cAAM,UAAU;IACd,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,GAAG,CAA2B;IACtC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,YAAY,CAAa;gBAErB,QAAQ,EAAE,MAAM;IA6B5B,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,cAAc;IAkCtB,OAAO,CAAC,SAAS;IAkBjB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,oBAAoB;IAgB5B,OAAO,CAAC,eAAe;IAsBvB,OAAO,CAAC,SAAS;IA4BjB,OAAO,CAAC,UAAU;IA6BlB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,IAAI;IAuEZ,OAAO,CAAC,QAAQ;IAUhB,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,QAAQ;IAeT,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,IAAI;IAInB,OAAO,CAAC,SAAS;CAmBlB"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js @@ -0,0 +1,375 @@ +"use strict"; +// Tetris Game in TypeScript +var PieceType; +(function (PieceType) { + PieceType[PieceType["I"] = 0] = "I"; + PieceType[PieceType["O"] = 1] = "O"; + PieceType[PieceType["T"] = 2] = "T"; + PieceType[PieceType["S"] = 3] = "S"; + PieceType[PieceType["Z"] = 4] = "Z"; + PieceType[PieceType["J"] = 5] = "J"; + PieceType[PieceType["L"] = 6] = "L"; +})(PieceType || (PieceType = {})); +const COLORS = [ + '#00F0F0', // I - Cyan + '#FFFF00', // O - Yellow + '#A000F0', // T - Purple + '#00F000', // S - Green + '#F00000', // Z - Red + '#0000F0', // J - Blue + '#F0A000' // L - Orange +]; +const PIECE_SHAPES = [ + // I + [[1, 1, 1, 1]], + // O + [[1, 1], [1, 1]], + // T + [[0, 1, 0], [1, 1, 1]], + // S + [[0, 1, 1], [1, 1, 0]], + // Z + [[1, 1, 0], [0, 1, 1]], + // J + [[1, 0, 0], [1, 1, 1]], + // L + [[0, 0, 1], [1, 1, 1]] +]; +class TetrisGame { + constructor(canvasId) { + this.gameLoopId = 0; + this.dropSpeed = 1000; // milliseconds + this.lastDropTime = 0; + this.canvas = document.getElementById(canvasId); + const ctx = this.canvas.getContext('2d'); + if (!ctx) + throw new Error('Could not get canvas context'); + this.ctx = ctx; + // Set canvas size + this.canvas.width = 300; + this.canvas.height = 600; + this.gameState = { + board: this.createEmptyBoard(10, 20), + currentPiece: PIECE_SHAPES[PieceType.I], + currentType: PieceType.I, + nextPiece: PIECE_SHAPES[PieceType.O], + nextType: PieceType.O, + posX: 3, + posY: 0, + score: 0, + level: 1, + linesCleared: 0, + gameOver: false, + paused: false + }; + this.setupEventListeners(); + this.draw(); + } + createEmptyBoard(width, height) { + return Array(height).fill(null).map(() => Array(width).fill(0)); + } + setupEventListeners() { + document.addEventListener('keydown', (e) => this.handleKeyPress(e)); + } + handleKeyPress(e) { + if (this.gameState.gameOver) { + if (e.key === 'r' || e.key === 'R') { + this.resetGame(); + } + return; + } + switch (e.key) { + case 'ArrowLeft': + e.preventDefault(); + this.movePiece(-1, 0); + break; + case 'ArrowRight': + e.preventDefault(); + this.movePiece(1, 0); + break; + case 'ArrowDown': + e.preventDefault(); + this.movePiece(0, 1); + break; + case ' ': + case 'ArrowUp': + e.preventDefault(); + this.rotatePiece(); + break; + case 'p': + case 'P': + e.preventDefault(); + this.gameState.paused = !this.gameState.paused; + break; + } + } + movePiece(dx, dy) { + const newX = this.gameState.posX + dx; + const newY = this.gameState.posY + dy; + if (this.isValidPosition(this.gameState.currentPiece, newX, newY)) { + this.gameState.posX = newX; + this.gameState.posY = newY; + if (dy > 0) { + this.lastDropTime = Date.now(); + } + } + else if (dy > 0) { + // Can't move down, lock the piece + this.lockPiece(); + } + this.draw(); + } + rotatePiece() { + const rotated = this.rotatePieceClockwise(this.gameState.currentPiece); + if (this.isValidPosition(rotated, this.gameState.posX, this.gameState.posY)) { + this.gameState.currentPiece = rotated; + } + this.draw(); + } + rotatePieceClockwise(piece) { + const rows = piece.length; + const cols = piece[0].length; + const rotated = []; + for (let col = 0; col < cols; col++) { + const newRow = []; + for (let row = rows - 1; row >= 0; row--) { + newRow.push(piece[row][col]); + } + rotated.push(newRow); + } + return rotated; + } + isValidPosition(piece, x, y) { + for (let row = 0; row < piece.length; row++) { + for (let col = 0; col < piece[row].length; col++) { + if (piece[row][col] === 0) + continue; + const newX = x + col; + const newY = y + row; + // Check boundaries + if (newX < 0 || newX >= 10 || newY >= 20) { + return false; + } + // Check collision with board + if (newY >= 0 && this.gameState.board[newY][newX] !== 0) { + return false; + } + } + } + return true; + } + lockPiece() { + // Place piece on board + for (let row = 0; row < this.gameState.currentPiece.length; row++) { + for (let col = 0; col < this.gameState.currentPiece[row].length; col++) { + if (this.gameState.currentPiece[row][col] === 0) + continue; + const boardY = this.gameState.posY + row; + const boardX = this.gameState.posX + col; + if (boardY >= 0) { + this.gameState.board[boardY][boardX] = this.gameState.currentType + 1; + } + } + } + // Check for game over + if (this.gameState.posY <= 0) { + this.gameState.gameOver = true; + return; + } + // Clear lines and add score + this.clearLines(); + // Spawn new piece + this.spawnNewPiece(); + } + clearLines() { + const board = this.gameState.board; + let linesCleared = 0; + for (let row = board.length - 1; row >= 0; row--) { + if (board[row].every(cell => cell !== 0)) { + board.splice(row, 1); + board.unshift(Array(10).fill(0)); + linesCleared++; + row++; // Check this row again + } + } + if (linesCleared > 0) { + this.gameState.linesCleared += linesCleared; + // Scoring: Standard Tetris scoring + const points = [40, 100, 300, 1200]; + this.gameState.score += (points[linesCleared - 1] || 0) * (this.gameState.level); + // Increase level every 10 lines + const newLevel = Math.floor(this.gameState.linesCleared / 10) + 1; + if (newLevel > this.gameState.level) { + this.gameState.level = newLevel; + this.dropSpeed = Math.max(100, 1000 - (this.gameState.level - 1) * 100); + } + } + } + spawnNewPiece() { + this.gameState.currentPiece = this.gameState.nextPiece; + this.gameState.currentType = this.gameState.nextType; + const randomType = Math.floor(Math.random() * 7); + this.gameState.nextPiece = this.copyPiece(PIECE_SHAPES[randomType]); + this.gameState.nextType = randomType; + this.gameState.posX = 3; + this.gameState.posY = 0; + } + copyPiece(piece) { + return piece.map(row => [...row]); + } + draw() { + const cellSize = 30; + // Clear canvas + this.ctx.fillStyle = '#000'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid + this.ctx.strokeStyle = '#333'; + this.ctx.lineWidth = 0.5; + for (let i = 0; i <= 10; i++) { + this.ctx.beginPath(); + this.ctx.moveTo(i * cellSize, 0); + this.ctx.lineTo(i * cellSize, 20 * cellSize); + this.ctx.stroke(); + } + for (let i = 0; i <= 20; i++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, i * cellSize); + this.ctx.lineTo(10 * cellSize, i * cellSize); + this.ctx.stroke(); + } + // Draw board + for (let row = 0; row < this.gameState.board.length; row++) { + for (let col = 0; col < this.gameState.board[row].length; col++) { + const cellValue = this.gameState.board[row][col]; + if (cellValue > 0) { + this.drawCell(col, row, COLORS[cellValue - 1], cellSize); + } + } + } + // Draw current piece + for (let row = 0; row < this.gameState.currentPiece.length; row++) { + for (let col = 0; col < this.gameState.currentPiece[row].length; col++) { + if (this.gameState.currentPiece[row][col] === 0) + continue; + const x = this.gameState.posX + col; + const y = this.gameState.posY + row; + if (y >= 0) { + this.drawCell(x, y, COLORS[this.gameState.currentType], cellSize); + } + } + } + // Draw pause overlay + if (this.gameState.paused) { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = '#FFF'; + this.ctx.font = 'bold 24px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('PAUSED', this.canvas.width / 2, this.canvas.height / 2); + } + // Draw game over overlay + if (this.gameState.gameOver) { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.8)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = '#FF0000'; + this.ctx.font = 'bold 28px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('GAME OVER', this.canvas.width / 2, this.canvas.height / 2 - 30); + this.ctx.fillStyle = '#FFF'; + this.ctx.font = '16px Arial'; + this.ctx.fillText('Press R to restart', this.canvas.width / 2, this.canvas.height / 2 + 30); + } + } + drawCell(col, row, color, cellSize) { + this.ctx.fillStyle = color; + this.ctx.fillRect(col * cellSize + 1, row * cellSize + 1, cellSize - 2, cellSize - 2); + // Draw border + this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)'; + this.ctx.lineWidth = 1; + this.ctx.strokeRect(col * cellSize + 1, row * cellSize + 1, cellSize - 2, cellSize - 2); + } + updateUI() { + const scoreEl = document.getElementById('score'); + const levelEl = document.getElementById('level'); + const linesEl = document.getElementById('lines'); + const nextPieceCanvas = document.getElementById('next-piece'); + if (scoreEl) + scoreEl.textContent = this.gameState.score.toString(); + if (levelEl) + levelEl.textContent = this.gameState.level.toString(); + if (linesEl) + linesEl.textContent = this.gameState.linesCleared.toString(); + if (nextPieceCanvas) { + this.drawNextPiece(nextPieceCanvas); + } + } + drawNextPiece(canvas) { + const ctx = canvas.getContext('2d'); + if (!ctx) + return; + ctx.fillStyle = '#000'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + const cellSize = canvas.width / 5; + const piece = this.gameState.nextPiece; + const color = COLORS[this.gameState.nextType]; + for (let row = 0; row < piece.length; row++) { + for (let col = 0; col < piece[row].length; col++) { + if (piece[row][col] === 0) + continue; + const x = col * cellSize + cellSize * 0.5; + const y = row * cellSize + cellSize * 0.5; + ctx.fillStyle = color; + ctx.fillRect(x + 1, y + 1, cellSize - 2, cellSize - 2); + ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)'; + ctx.lineWidth = 1; + ctx.strokeRect(x + 1, y + 1, cellSize - 2, cellSize - 2); + } + } + } + gameLoop() { + const now = Date.now(); + if (!this.gameState.paused && !this.gameState.gameOver) { + if (now - this.lastDropTime >= this.dropSpeed) { + this.movePiece(0, 1); + this.lastDropTime = now; + } + } + this.updateUI(); + this.draw(); + this.gameLoopId = requestAnimationFrame(() => this.gameLoop()); + } + start() { + this.lastDropTime = Date.now(); + this.gameLoop(); + } + stop() { + cancelAnimationFrame(this.gameLoopId); + } + resetGame() { + this.gameState = { + board: this.createEmptyBoard(10, 20), + currentPiece: PIECE_SHAPES[PieceType.I], + currentType: PieceType.I, + nextPiece: PIECE_SHAPES[PieceType.O], + nextType: PieceType.O, + posX: 3, + posY: 0, + score: 0, + level: 1, + linesCleared: 0, + gameOver: false, + paused: false + }; + this.dropSpeed = 1000; + this.lastDropTime = Date.now(); + this.draw(); + } +} +// Initialize game when DOM is ready +document.addEventListener('DOMContentLoaded', () => { + const game = new TetrisGame('gameCanvas'); + game.start(); + // Store reference for debugging/control + window.game = game; +}); +//# sourceMappingURL=game.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js.map @@ -0,0 +1 @@ +{"version":3,"file":"game.js","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,429 @@ +"use strict"; +// Game constants +const BOARD_WIDTH = 10; +const BOARD_HEIGHT = 20; +const BLOCK_SIZE = 30; +const INITIAL_DROP_SPEED = 800; // milliseconds +const MIN_DROP_SPEED = 100; +const SPEED_INCREASE_RATE = 0.95; +const TETROMINOES = { + I: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + O: [ + [1, 1, 0, 0], + [1, 1, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + T: [ + [0, 1, 0, 0], + [1, 1, 1, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + S: [ + [0, 1, 1, 0], + [1, 1, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + Z: [ + [1, 1, 0, 0], + [0, 1, 1, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + J: [ + [1, 0, 0, 0], + [1, 1, 1, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + L: [ + [0, 0, 1, 0], + [1, 1, 1, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], +}; +const TETROMINO_COLORS = { + I: '#00F0F0', + O: '#F0F000', + T: '#D000F0', + S: '#00F000', + Z: '#F00000', + J: '#0000F0', + L: '#F0A000', +}; +class TetrisGame { + constructor(canvasId) { + this.currentPiece = null; + this.nextPiece = null; + this.score = 0; + this.lines = 0; + this.level = 1; + this.dropSpeed = INITIAL_DROP_SPEED; + this.lastDropTime = 0; + this.gameOver = false; + this.gamePaused = false; + this.keys = {}; + this.gameLoop = () => { + this.update(); + this.draw(); + requestAnimationFrame(this.gameLoop); + }; + this.canvas = document.getElementById(canvasId); + if (!this.canvas) { + throw new Error(`Canvas with id "${canvasId}" not found`); + } + this.ctx = this.canvas.getContext('2d'); + // Set canvas size + this.canvas.width = BOARD_WIDTH * BLOCK_SIZE; + this.canvas.height = BOARD_HEIGHT * BLOCK_SIZE; + // Initialize empty board + this.board = Array(BOARD_HEIGHT) + .fill(null) + .map(() => Array(BOARD_WIDTH).fill(0)); + // Setup event listeners + this.setupEventListeners(); + // Generate initial pieces + this.nextPiece = this.generateRandomPiece(); + this.spawnPiece(); + // Start game loop + this.gameLoop(); + } + setupEventListeners() { + window.addEventListener('keydown', (e) => { + this.keys[e.key.toLowerCase()] = true; + if (e.key === ' ') { + e.preventDefault(); + this.dropPiece(); + } + if (e.key === 'p' || e.key === 'P') { + this.togglePause(); + } + }); + window.addEventListener('keyup', (e) => { + this.keys[e.key.toLowerCase()] = false; + }); + } + generateRandomPiece() { + const types = Object.keys(TETROMINOES); + const type = types[Math.floor(Math.random() * types.length)]; + return { + shape: JSON.parse(JSON.stringify(TETROMINOES[type])), // Deep copy + x: Math.floor(BOARD_WIDTH / 2) - 2, + y: 0, + type, + color: TETROMINO_COLORS[type], + }; + } + spawnPiece() { + this.currentPiece = this.nextPiece; + this.nextPiece = this.generateRandomPiece(); + if (!this.canMovePiece(0, 0)) { + this.gameOver = true; + } + } + canMovePiece(dx, dy) { + if (!this.currentPiece) + return false; + const newX = this.currentPiece.x + dx; + const newY = this.currentPiece.y + dy; + for (let row = 0; row < 4; row++) { + for (let col = 0; col < 4; col++) { + if (this.currentPiece.shape[row][col] === 0) + continue; + const boardX = newX + col; + const boardY = newY + row; + // Check boundaries + if (boardX < 0 || + boardX >= BOARD_WIDTH || + boardY >= BOARD_HEIGHT) { + return false; + } + // Check collision with placed blocks + if (boardY >= 0 && + this.board[boardY][boardX] !== 0) { + return false; + } + } + } + return true; + } + movePiece(dx, dy) { + if (this.canMovePiece(dx, dy) && this.currentPiece) { + this.currentPiece.x += dx; + this.currentPiece.y += dy; + } + } + rotatePiece() { + if (!this.currentPiece) + return; + const originalShape = this.currentPiece.shape; + this.currentPiece.shape = this.rotateShape(this.currentPiece.shape); + // Check if rotation is valid + if (!this.canMovePiece(0, 0)) { + // Try wall kick (move left/right to fit) + if (this.canMovePiece(-1, 0)) { + this.currentPiece.x -= 1; + } + else if (this.canMovePiece(1, 0)) { + this.currentPiece.x += 1; + } + else if (this.canMovePiece(-2, 0)) { + this.currentPiece.x -= 2; + } + else if (this.canMovePiece(2, 0)) { + this.currentPiece.x += 2; + } + else { + // Revert rotation + this.currentPiece.shape = originalShape; + } + } + } + rotateShape(shape) { + const n = shape.length; + const rotated = Array(n) + .fill(null) + .map(() => Array(n).fill(0)); + for (let row = 0; row < n; row++) { + for (let col = 0; col < n; col++) { + rotated[col][n - 1 - row] = shape[row][col]; + } + } + return rotated; + } + placePiece() { + if (!this.currentPiece) + return; + for (let row = 0; row < 4; row++) { + for (let col = 0; col < 4; col++) { + if (this.currentPiece.shape[row][col] === 0) + continue; + const boardY = this.currentPiece.y + row; + const boardX = this.currentPiece.x + col; + if (boardY >= 0) { + this.board[boardY][boardX] = 1; // Mark as occupied + } + } + } + this.clearLines(); + this.spawnPiece(); + } + clearLines() { + let linesCleared = 0; + for (let row = BOARD_HEIGHT - 1; row >= 0; row--) { + if (this.board[row].every((cell) => cell !== 0)) { + // Remove completed line + this.board.splice(row, 1); + // Add empty line at top + this.board.unshift(Array(BOARD_WIDTH).fill(0)); + linesCleared++; + row++; // Check this row again + } + } + if (linesCleared > 0) { + this.lines += linesCleared; + // Scoring: 100 for 1 line, 300 for 2, 500 for 3, 800 for 4 + const scoreBonus = [0, 100, 300, 500, 800]; + this.score += scoreBonus[Math.min(linesCleared, 4)] * this.level; + // Increase level every 10 lines + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel > this.level) { + this.level = newLevel; + this.dropSpeed = Math.max(MIN_DROP_SPEED, INITIAL_DROP_SPEED * Math.pow(SPEED_INCREASE_RATE, this.level - 1)); + } + } + } + dropPiece() { + while (this.canMovePiece(0, 1)) { + this.currentPiece.y += 1; + } + this.placePiece(); + } + togglePause() { + this.gamePaused = !this.gamePaused; + } + update() { + if (this.gameOver || this.gamePaused) + return; + const now = Date.now(); + // Handle player input + if (this.keys['arrowleft']) { + this.movePiece(-1, 0); + delete this.keys['arrowleft']; + } + if (this.keys['arrowright']) { + this.movePiece(1, 0); + delete this.keys['arrowright']; + } + if (this.keys['arrowdown']) { + this.movePiece(0, 1); + } + if (this.keys['arrowup'] || this.keys['z'] || this.keys['x']) { + this.rotatePiece(); + delete this.keys['arrowup']; + delete this.keys['z']; + delete this.keys['x']; + } + // Auto drop piece + if (now - this.lastDropTime > this.dropSpeed) { + if (this.canMovePiece(0, 1)) { + this.currentPiece.y += 1; + } + else { + this.placePiece(); + } + this.lastDropTime = now; + } + } + draw() { + // Clear canvas + this.ctx.fillStyle = '#000'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid + this.ctx.strokeStyle = '#222'; + this.ctx.lineWidth = 0.5; + for (let row = 0; row <= BOARD_HEIGHT; row++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, row * BLOCK_SIZE); + this.ctx.lineTo(this.canvas.width, row * BLOCK_SIZE); + this.ctx.stroke(); + } + for (let col = 0; col <= BOARD_WIDTH; col++) { + this.ctx.beginPath(); + this.ctx.moveTo(col * BLOCK_SIZE, 0); + this.ctx.lineTo(col * BLOCK_SIZE, this.canvas.height); + this.ctx.stroke(); + } + // Draw placed blocks + for (let row = 0; row < BOARD_HEIGHT; row++) { + for (let col = 0; col < BOARD_WIDTH; col++) { + if (this.board[row][col] !== 0) { + this.drawBlock(col, row, '#888'); + } + } + } + // Draw current piece + if (this.currentPiece && !this.gameOver) { + for (let row = 0; row < 4; row++) { + for (let col = 0; col < 4; col++) { + if (this.currentPiece.shape[row][col] === 0) + continue; + const x = this.currentPiece.x + col; + const y = this.currentPiece.y + row; + if (y >= 0) { + this.drawBlock(x, y, this.currentPiece.color); + } + } + } + } + // Draw game over overlay + if (this.gameOver) { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = '#fff'; + this.ctx.font = 'bold 40px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('GAME OVER', this.canvas.width / 2, this.canvas.height / 2 - 30); + this.ctx.font = '20px Arial'; + this.ctx.fillText('Press R to Restart', this.canvas.width / 2, this.canvas.height / 2 + 20); + } + // Draw pause overlay + if (this.gamePaused && !this.gameOver) { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = '#fff'; + this.ctx.font = 'bold 40px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('PAUSED', this.canvas.width / 2, this.canvas.height / 2); + } + } + drawBlock(x, y, color) { + const padding = 1; + this.ctx.fillStyle = color; + this.ctx.fillRect(x * BLOCK_SIZE + padding, y * BLOCK_SIZE + padding, BLOCK_SIZE - 2 * padding, BLOCK_SIZE - 2 * padding); + // Add border for depth + this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)'; + this.ctx.lineWidth = 1; + this.ctx.strokeRect(x * BLOCK_SIZE + padding, y * BLOCK_SIZE + padding, BLOCK_SIZE - 2 * padding, BLOCK_SIZE - 2 * padding); + } + restart() { + this.board = Array(BOARD_HEIGHT) + .fill(null) + .map(() => Array(BOARD_WIDTH).fill(0)); + this.score = 0; + this.lines = 0; + this.level = 1; + this.dropSpeed = INITIAL_DROP_SPEED; + this.gameOver = false; + this.gamePaused = false; + this.lastDropTime = 0; + this.nextPiece = this.generateRandomPiece(); + this.spawnPiece(); + } + getScore() { + return this.score; + } + getLines() { + return this.lines; + } + getLevel() { + return this.level; + } + isGameOver() { + return this.gameOver; + } + isPaused() { + return this.gamePaused; + } +} +// Initialize game +let game; +window.addEventListener('DOMContentLoaded', () => { + game = new TetrisGame('tetrisCanvas'); + // Setup restart button + const restartBtn = document.getElementById('restartBtn'); + if (restartBtn) { + restartBtn.addEventListener('click', () => { + game.restart(); + }); + } + // Setup pause button + const pauseBtn = document.getElementById('pauseBtn'); + if (pauseBtn) { + pauseBtn.addEventListener('click', () => { + // Pause is also handled by pressing 'P' + const pauseLabel = pauseBtn.textContent?.includes('Resume') + ? 'Pause' + : 'Resume'; + pauseBtn.textContent = pauseLabel; + }); + } + // Update stats display + setInterval(() => { + const scoreEl = document.getElementById('score'); + const linesEl = document.getElementById('lines'); + const levelEl = document.getElementById('level'); + const statusEl = document.getElementById('status'); + if (scoreEl) + scoreEl.textContent = game.getScore().toString(); + if (linesEl) + linesEl.textContent = game.getLines().toString(); + if (levelEl) + levelEl.textContent = game.getLevel().toString(); + if (statusEl) { + statusEl.textContent = game.isGameOver() + ? 'GAME OVER' + : game.isPaused() + ? 'PAUSED' + : 'PLAYING'; + } + }, 100); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts @@ -0,0 +1,70 @@ +declare const BOARD_WIDTH = 10; +declare const BOARD_HEIGHT = 20; +declare const CELL_SIZE = 20; +declare const INITIAL_FALL_SPEED = 500; +declare const SPEED_INCREASE = 0.95; +type TetrominoType = 'I' | 'O' | 'T' | 'S' | 'Z' | 'L' | 'J'; +interface Tetromino { + type: TetrominoType; + color: string; + shape: number[][]; +} +declare const TETROMINOS: Record<TetrominoType, Tetromino>; +interface Piece { + type: TetrominoType; + x: number; + y: number; + rotation: number; +} +declare class TetrisGame { + private canvas; + private ctx; + private nextCanvas; + private nextCtx; + private board; + private currentPiece; + private nextPiece; + private score; + private lines; + private level; + private fallSpeed; + private gameRunning; + private gamePaused; + private gameOver; + private lastFallTime; + private lastMoveTime; + private moveDelay; + private gameLoopId; + private fallLoopId; + private keys; + constructor(); + private initializeBoard; + private setupEventListeners; + private handleKeyDown; + private handleKeyUp; + private startGame; + private resetGame; + private togglePause; + private spawnPiece; + private createRandomPiece; + private getRotatedShape; + private rotateClockwise; + private isValidPosition; + private moveLeft; + private moveRight; + private rotatePiece; + private softDrop; + private hardDrop; + private handleFall; + private lockPiece; + private clearLines; + private endGame; + private updateDisplay; + private update; + private drawBoard; + private drawPiece; + private drawCell; + private drawNextPiece; + private getColorFromIndex; +} +//# sourceMappingURL=game.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"game.d.ts","sourceRoot":"","sources":["../game.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,WAAW,KAAK,CAAC;AACvB,QAAA,MAAM,YAAY,KAAK,CAAC;AACxB,QAAA,MAAM,SAAS,KAAK,CAAC;AACrB,QAAA,MAAM,kBAAkB,MAAM,CAAC;AAC/B,QAAA,MAAM,cAAc,OAAO,CAAC;AAG5B,KAAK,aAAa,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAE7D,UAAU,SAAS;IACf,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;CACrB;AAED,QAAA,MAAM,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,SAAS,CAoChD,CAAC;AAEF,UAAU,KAAK;IACX,IAAI,EAAE,aAAa,CAAC;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,QAAQ,EAAE,MAAM,CAAC;CACpB;AAGD,cAAM,UAAU;IACZ,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,GAAG,CAA2B;IACtC,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,OAAO,CAA2B;IAE1C,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,SAAS,CAAsB;IAEvC,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,SAAS,CAA8B;IAE/C,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,QAAQ,CAAkB;IAElC,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,SAAS,CAAe;IAEhC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,UAAU,CAAuB;IAEzC,OAAO,CAAC,IAAI,CAA+B;;IAc3C,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,aAAa;IA0CrB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,SAAS;IAmBjB,OAAO,CAAC,SAAS;IA0BjB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,UAAU;IAgBlB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,eAAe;IAuBvB,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,WAAW;IA0BnB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,SAAS;IAuBjB,OAAO,CAAC,UAAU;IA4ClB,OAAO,CAAC,OAAO;IAoBf,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,SAAS;IAyCjB,OAAO,CAAC,SAAS;IAkBjB,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,aAAa;IA8BrB,OAAO,CAAC,iBAAiB;CAI5B"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js @@ -0,0 +1,478 @@ +"use strict"; +// Tetris Game in TypeScript +// Game Constants +const BOARD_WIDTH = 10; +const BOARD_HEIGHT = 20; +const CELL_SIZE = 20; +const INITIAL_FALL_SPEED = 500; // milliseconds +const SPEED_INCREASE = 0.95; // Speed multiplier per level +const TETROMINOS = { + I: { + type: 'I', + color: '#00ffff', + shape: [[1, 1, 1, 1]] + }, + O: { + type: 'O', + color: '#ffff00', + shape: [[1, 1], [1, 1]] + }, + T: { + type: 'T', + color: '#ff00ff', + shape: [[0, 1, 0], [1, 1, 1]] + }, + S: { + type: 'S', + color: '#00ff00', + shape: [[0, 1, 1], [1, 1, 0]] + }, + Z: { + type: 'Z', + color: '#ff0000', + shape: [[1, 1, 0], [0, 1, 1]] + }, + L: { + type: 'L', + color: '#ff8800', + shape: [[1, 0], [1, 0], [1, 1]] + }, + J: { + type: 'J', + color: '#0000ff', + shape: [[0, 1], [0, 1], [1, 1]] + } +}; +// Game State +class TetrisGame { + constructor() { + this.board = []; + this.currentPiece = null; + this.nextPiece = null; + this.score = 0; + this.lines = 0; + this.level = 1; + this.fallSpeed = INITIAL_FALL_SPEED; + this.gameRunning = false; + this.gamePaused = false; + this.gameOver = false; + this.lastFallTime = 0; + this.lastMoveTime = 0; + this.moveDelay = 100; // milliseconds between moves + this.gameLoopId = null; + this.fallLoopId = null; + this.keys = {}; + this.canvas = document.getElementById('gameCanvas'); + this.ctx = this.canvas.getContext('2d'); + this.nextCanvas = document.getElementById('nextCanvas'); + this.nextCtx = this.nextCanvas.getContext('2d'); + this.initializeBoard(); + this.setupEventListeners(); + this.drawBoard(); + } + initializeBoard() { + this.board = Array(BOARD_HEIGHT) + .fill(null) + .map(() => Array(BOARD_WIDTH).fill(0)); + } + setupEventListeners() { + // Keyboard events + document.addEventListener('keydown', (e) => this.handleKeyDown(e)); + document.addEventListener('keyup', (e) => this.handleKeyUp(e)); + // Button events + const startBtn = document.getElementById('startBtn'); + const pauseBtn = document.getElementById('pauseBtn'); + const resetBtn = document.getElementById('resetBtn'); + const restartBtn = document.getElementById('restartBtn'); + startBtn.addEventListener('click', () => this.startGame()); + pauseBtn.addEventListener('click', () => this.togglePause()); + resetBtn.addEventListener('click', () => this.resetGame()); + restartBtn.addEventListener('click', () => this.startGame()); + } + handleKeyDown(e) { + const key = e.key.toLowerCase(); + this.keys[key] = true; + if (!this.gameRunning || this.gameOver) + return; + const now = Date.now(); + switch (key) { + case 'arrowleft': + e.preventDefault(); + if (now - this.lastMoveTime > this.moveDelay) { + this.moveLeft(); + this.lastMoveTime = now; + } + break; + case 'arrowright': + e.preventDefault(); + if (now - this.lastMoveTime > this.moveDelay) { + this.moveRight(); + this.lastMoveTime = now; + } + break; + case 'arrowup': + e.preventDefault(); + this.rotatePiece(); + break; + case 'arrowdown': + e.preventDefault(); + this.softDrop(); + break; + case ' ': + e.preventDefault(); + this.hardDrop(); + break; + case 'p': + e.preventDefault(); + this.togglePause(); + break; + } + } + handleKeyUp(e) { + const key = e.key.toLowerCase(); + this.keys[key] = false; + } + startGame() { + this.resetGame(); + this.gameRunning = true; + this.gamePaused = false; + this.gameOver = false; + const startBtn = document.getElementById('startBtn'); + const pauseBtn = document.getElementById('pauseBtn'); + startBtn.disabled = true; + pauseBtn.disabled = false; + document.getElementById('gameOverMessage').style.display = 'none'; + this.spawnPiece(); + this.gameLoopId = window.setInterval(() => this.update(), 1000 / 60); + this.fallLoopId = window.setInterval(() => this.handleFall(), this.fallSpeed); + } + resetGame() { + if (this.gameLoopId !== null) + clearInterval(this.gameLoopId); + if (this.fallLoopId !== null) + clearInterval(this.fallLoopId); + this.score = 0; + this.lines = 0; + this.level = 1; + this.fallSpeed = INITIAL_FALL_SPEED; + this.gameRunning = false; + this.gamePaused = false; + this.gameOver = false; + this.initializeBoard(); + this.currentPiece = null; + this.nextPiece = null; + this.updateDisplay(); + this.drawBoard(); + const startBtn = document.getElementById('startBtn'); + const pauseBtn = document.getElementById('pauseBtn'); + startBtn.disabled = false; + pauseBtn.disabled = true; + } + togglePause() { + if (!this.gameRunning || this.gameOver) + return; + this.gamePaused = !this.gamePaused; + const pauseBtn = document.getElementById('pauseBtn'); + pauseBtn.textContent = this.gamePaused ? 'Resume' : 'Pause'; + } + spawnPiece() { + if (this.nextPiece === null) { + this.nextPiece = this.createRandomPiece(); + } + this.currentPiece = this.nextPiece; + this.nextPiece = this.createRandomPiece(); + // Check if piece can spawn (game over condition) + if (!this.isValidPosition(this.currentPiece)) { + this.endGame(); + } + this.drawNextPiece(); + } + createRandomPiece() { + const types = Object.keys(TETROMINOS); + const type = types[Math.floor(Math.random() * types.length)]; + return { + type: type, + x: Math.floor(BOARD_WIDTH / 2) - 1, + y: 0, + rotation: 0 + }; + } + getRotatedShape(piece) { + const base = TETROMINOS[piece.type].shape; + let rotated = base; + for (let i = 0; i < piece.rotation; i++) { + rotated = this.rotateClockwise(rotated); + } + return rotated; + } + rotateClockwise(shape) { + const n = shape.length; + const m = shape[0].length; + const rotated = Array(m) + .fill(null) + .map(() => Array(n).fill(0)); + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + rotated[j][n - 1 - i] = shape[i][j]; + } + } + return rotated; + } + isValidPosition(piece) { + const shape = this.getRotatedShape(piece); + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 0) + continue; + const x = piece.x + col; + const y = piece.y + row; + if (x < 0 || x >= BOARD_WIDTH || y >= BOARD_HEIGHT) { + return false; + } + if (y >= 0 && this.board[y][x] !== 0) { + return false; + } + } + } + return true; + } + moveLeft() { + if (!this.currentPiece) + return; + this.currentPiece.x--; + if (!this.isValidPosition(this.currentPiece)) { + this.currentPiece.x++; + } + } + moveRight() { + if (!this.currentPiece) + return; + this.currentPiece.x++; + if (!this.isValidPosition(this.currentPiece)) { + this.currentPiece.x--; + } + } + rotatePiece() { + if (!this.currentPiece) + return; + const originalRotation = this.currentPiece.rotation; + this.currentPiece.rotation = (this.currentPiece.rotation + 1) % 4; + if (!this.isValidPosition(this.currentPiece)) { + // Try wall kicks + const kicks = [-2, -1, 1, 2]; + let found = false; + for (const kick of kicks) { + this.currentPiece.x += kick; + if (this.isValidPosition(this.currentPiece)) { + found = true; + break; + } + this.currentPiece.x -= kick; + } + if (!found) { + this.currentPiece.rotation = originalRotation; + } + } + } + softDrop() { + if (!this.currentPiece) + return; + this.currentPiece.y++; + if (!this.isValidPosition(this.currentPiece)) { + this.currentPiece.y--; + this.lockPiece(); + } + } + hardDrop() { + if (!this.currentPiece) + return; + while (this.isValidPosition(this.currentPiece)) { + this.currentPiece.y++; + } + this.currentPiece.y--; + this.lockPiece(); + } + handleFall() { + if (!this.gameRunning || this.gamePaused || this.gameOver || !this.currentPiece) { + return; + } + this.currentPiece.y++; + if (!this.isValidPosition(this.currentPiece)) { + this.currentPiece.y--; + this.lockPiece(); + } + } + lockPiece() { + if (!this.currentPiece) + return; + const shape = this.getRotatedShape(this.currentPiece); + const colorIndex = Object.keys(TETROMINOS).indexOf(this.currentPiece.type) + 1; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 0) + continue; + const x = this.currentPiece.x + col; + const y = this.currentPiece.y + row; + if (y >= 0 && y < BOARD_HEIGHT && x >= 0 && x < BOARD_WIDTH) { + this.board[y][x] = colorIndex; + } + } + } + this.clearLines(); + this.spawnPiece(); + } + clearLines() { + let linesCleared = 0; + const rowsToRemove = []; + for (let row = BOARD_HEIGHT - 1; row >= 0; row--) { + if (this.board[row].every(cell => cell !== 0)) { + rowsToRemove.push(row); + } + } + if (rowsToRemove.length > 0) { + for (const row of rowsToRemove) { + this.board.splice(row, 1); + this.board.unshift(Array(BOARD_WIDTH).fill(0)); + } + linesCleared = rowsToRemove.length; + this.lines += linesCleared; + // Update level and speed + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel > this.level) { + this.level = newLevel; + this.fallSpeed = INITIAL_FALL_SPEED * Math.pow(SPEED_INCREASE, this.level - 1); + // Restart fall loop with new speed + if (this.fallLoopId !== null) { + clearInterval(this.fallLoopId); + } + this.fallLoopId = window.setInterval(() => this.handleFall(), this.fallSpeed); + } + // Calculate score based on lines cleared + const scoreTable = [0, 100, 300, 500, 800]; + const points = scoreTable[linesCleared] * this.level; + this.score += points; + } + this.updateDisplay(); + } + endGame() { + this.gameRunning = false; + this.gameOver = true; + if (this.gameLoopId !== null) + clearInterval(this.gameLoopId); + if (this.fallLoopId !== null) + clearInterval(this.fallLoopId); + const gameOverMessage = document.getElementById('gameOverMessage'); + const finalScore = document.getElementById('finalScore'); + finalScore.textContent = `Final Score: ${this.score}`; + gameOverMessage.style.display = 'flex'; + const startBtn = document.getElementById('startBtn'); + const pauseBtn = document.getElementById('pauseBtn'); + startBtn.disabled = false; + pauseBtn.disabled = true; + } + updateDisplay() { + document.getElementById('score').textContent = this.score.toString(); + document.getElementById('level').textContent = this.level.toString(); + document.getElementById('lines').textContent = this.lines.toString(); + } + update() { + this.drawBoard(); + } + drawBoard() { + // Clear canvas + this.ctx.fillStyle = '#0f3460'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid + this.ctx.strokeStyle = '#1a4d6d'; + this.ctx.lineWidth = 0.5; + for (let i = 0; i <= BOARD_WIDTH; i++) { + this.ctx.beginPath(); + this.ctx.moveTo(i * CELL_SIZE, 0); + this.ctx.lineTo(i * CELL_SIZE, this.canvas.height); + this.ctx.stroke(); + } + for (let i = 0; i <= BOARD_HEIGHT; i++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, i * CELL_SIZE); + this.ctx.lineTo(this.canvas.width, i * CELL_SIZE); + this.ctx.stroke(); + } + // Draw locked pieces + for (let row = 0; row < BOARD_HEIGHT; row++) { + for (let col = 0; col < BOARD_WIDTH; col++) { + if (this.board[row][col] !== 0) { + this.drawCell(col, row, this.getColorFromIndex(this.board[row][col])); + } + } + } + // Draw current piece + if (this.currentPiece) { + this.drawPiece(this.currentPiece); + } + // Draw border + this.ctx.strokeStyle = '#00d4ff'; + this.ctx.lineWidth = 3; + this.ctx.strokeRect(0, 0, this.canvas.width, this.canvas.height); + } + drawPiece(piece) { + const shape = this.getRotatedShape(piece); + const color = TETROMINOS[piece.type].color; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 0) + continue; + const x = piece.x + col; + const y = piece.y + row; + if (y >= 0) { + this.drawCell(x, y, color); + } + } + } + } + drawCell(x, y, color) { + const padding = 1; + const cellX = x * CELL_SIZE + padding; + const cellY = y * CELL_SIZE + padding; + const cellWidth = CELL_SIZE - padding * 2; + this.ctx.fillStyle = color; + this.ctx.fillRect(cellX, cellY, cellWidth, cellWidth); + // Draw darker border for depth + this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)'; + this.ctx.lineWidth = 1; + this.ctx.strokeRect(cellX, cellY, cellWidth, cellWidth); + } + drawNextPiece() { + // Clear next canvas + this.nextCtx.fillStyle = '#0f3460'; + this.nextCtx.fillRect(0, 0, this.nextCanvas.width, this.nextCanvas.height); + if (!this.nextPiece) + return; + const shape = TETROMINOS[this.nextPiece.type].shape; + const color = TETROMINOS[this.nextPiece.type].color; + const cellSize = 20; + const offsetX = (this.nextCanvas.width - shape[0].length * cellSize) / 2; + const offsetY = (this.nextCanvas.height - shape.length * cellSize) / 2; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 0) + continue; + const x = offsetX + col * cellSize + 1; + const y = offsetY + row * cellSize + 1; + this.nextCtx.fillStyle = color; + this.nextCtx.fillRect(x, y, cellSize - 2, cellSize - 2); + this.nextCtx.strokeStyle = 'rgba(255, 255, 255, 0.3)'; + this.nextCtx.lineWidth = 1; + this.nextCtx.strokeRect(x, y, cellSize - 2, cellSize - 2); + } + } + } + getColorFromIndex(index) { + const colors = ['#00ffff', '#ffff00', '#ff00ff', '#00ff00', '#ff0000', '#ff8800', '#0000ff']; + return colors[(index - 1) % colors.length]; + } +} +// Initialize game when DOM is loaded +document.addEventListener('DOMContentLoaded', () => { + new TetrisGame(); +}); +//# sourceMappingURL=game.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js.map @@ -0,0 +1 @@ +{"version":3,"file":"game.js","sourceRoot":"","sources":["../game.ts"],"names":[],"mappings":";AAAA,4BAA4B;AAE5B,iBAAiB;AACjB,MAAM,WAAW,GAAG,EAAE,CAAC;AACvB,MAAM,YAAY,GAAG,EAAE,CAAC;AACxB,MAAM,SAAS,GAAG,EAAE,CAAC;AACrB,MAAM,kBAAkB,GAAG,GAAG,CAAC,CAAC,eAAe;AAC/C,MAAM,cAAc,GAAG,IAAI,CAAC,CAAC,6BAA6B;AAW1D,MAAM,UAAU,GAAqC;IACjD,CAAC,EAAE;QACC,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;KACxB;IACD,CAAC,EAAE;QACC,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACC,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;KAChC;IACD,CAAC,EAAE;QACC,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;KAChC;IACD,CAAC,EAAE;QACC,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;KAChC;IACD,CAAC,EAAE;QACC,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;KAClC;IACD,CAAC,EAAE;QACC,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;KAClC;CACJ,CAAC;AASF,aAAa;AACb,MAAM,UAAU;IA4BZ;QAtBQ,UAAK,GAAe,EAAE,CAAC;QACvB,iBAAY,GAAiB,IAAI,CAAC;QAClC,cAAS,GAAiB,IAAI,CAAC;QAE/B,UAAK,GAAW,CAAC,CAAC;QAClB,UAAK,GAAW,CAAC,CAAC;QAClB,UAAK,GAAW,CAAC,CAAC;QAClB,cAAS,GAAW,kBAAkB,CAAC;QAEvC,gBAAW,GAAY,KAAK,CAAC;QAC7B,eAAU,GAAY,KAAK,CAAC;QAC5B,aAAQ,GAAY,KAAK,CAAC;QAE1B,iBAAY,GAAW,CAAC,CAAC;QACzB,iBAAY,GAAW,CAAC,CAAC;QACzB,cAAS,GAAW,GAAG,CAAC,CAAC,6BAA6B;QAEtD,eAAU,GAAkB,IAAI,CAAC;QACjC,eAAU,GAAkB,IAAI,CAAC;QAEjC,SAAI,GAA4B,EAAE,CAAC;QAGvC,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAsB,CAAC;QACzE,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;QAEzC,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAsB,CAAC;QAC7E,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;QAEjD,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,SAAS,EAAE,CAAC;IACrB,CAAC;IAEO,eAAe;QACnB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC;aAC3B,IAAI,CAAC,IAAI,CAAC;aACV,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IAEO,mBAAmB;QACvB,kBAAkB;QAClB,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QAE/D,gBAAgB;QAChB,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAC1E,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAC1E,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAC1E,MAAM,UAAU,GAAG,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAsB,CAAC;QAE9E,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAC3D,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC7D,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAC3D,UAAU,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IACjE,CAAC;IAEO,aAAa,CAAC,CAAgB;QAClC,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;QAEtB,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAE/C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,QAAQ,GAAG,EAAE,CAAC;YACV,KAAK,WAAW;gBACZ,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,IAAI,GAAG,GAAG,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;oBAC3C,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAChB,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC;gBAC5B,CAAC;gBACD,MAAM;YACV,KAAK,YAAY;gBACb,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,IAAI,GAAG,GAAG,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;oBAC3C,IAAI,CAAC,SAAS,EAAE,CAAC;oBACjB,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC;gBAC5B,CAAC;gBACD,MAAM;YACV,KAAK,SAAS;gBACV,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,IAAI,CAAC,WAAW,EAAE,CAAC;gBACnB,MAAM;YACV,KAAK,WAAW;gBACZ,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAChB,MAAM;YACV,KAAK,GAAG;gBACJ,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAChB,MAAM;YACV,KAAK,GAAG;gBACJ,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,IAAI,CAAC,WAAW,EAAE,CAAC;gBACnB,MAAM;QACd,CAAC;IACL,CAAC;IAEO,WAAW,CAAC,CAAgB;QAChC,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC3B,CAAC;IAEO,SAAS;QACb,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QAEtB,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAC1E,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAE1E,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;QACzB,QAAQ,CAAC,QAAQ,GAAG,KAAK,CAAC;QAE1B,QAAQ,CAAC,cAAc,CAAC,iBAAiB,CAAE,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QAEnE,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QACrE,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAClF,CAAC;IAEO,SAAS;QACb,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI;YAAE,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7D,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI;YAAE,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAE7D,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,SAAS,GAAG,kBAAkB,CAAC;QACpC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QAEtB,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QAEtB,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC,SAAS,EAAE,CAAC;QAEjB,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAC1E,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAE1E,QAAQ,CAAC,QAAQ,GAAG,KAAK,CAAC;QAC1B,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC7B,CAAC;IAEO,WAAW;QACf,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAE/C,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;QAEnC,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAC1E,QAAQ,CAAC,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;IAChE,CAAC;IAEO,UAAU;QACd,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;YAC1B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC9C,CAAC;QAED,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAE1C,iDAAiD;QACjD,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,YAAa,CAAC,EAAE,CAAC;YAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC;QAED,IAAI,CAAC,aAAa,EAAE,CAAC;IACzB,CAAC;IAEO,iBAAiB;QACrB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAoB,CAAC;QACzD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;QAE7D,OAAO;YACH,IAAI,EAAE,IAAI;YACV,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,CAAC;YAClC,CAAC,EAAE,CAAC;YACJ,QAAQ,EAAE,CAAC;SACd,CAAC;IACN,CAAC;IAEO,eAAe,CAAC,KAAY;QAChC,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;QAC1C,IAAI,OAAO,GAAG,IAAI,CAAC;QAEnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QAC5C,CAAC;QAED,OAAO,OAAO,CAAC;IACnB,CAAC;IAEO,eAAe,CAAC,KAAiB;QACrC,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;QACvB,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC1B,MAAM,OAAO,GAAe,KAAK,CAAC,CAAC,CAAC;aAC/B,IAAI,CAAC,IAAI,CAAC;aACV,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAEjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBACzB,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACxC,CAAC;QACL,CAAC;QAED,OAAO,OAAO,CAAC;IACnB,CAAC;IAEO,eAAe,CAAC,KAAY;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAE1C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;YAC1C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;gBAC/C,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;oBAAE,SAAS;gBAEpC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC;gBACxB,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC;gBAExB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,WAAW,IAAI,CAAC,IAAI,YAAY,EAAE,CAAC;oBACjD,OAAO,KAAK,CAAC;gBACjB,CAAC;gBAED,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;oBACnC,OAAO,KAAK,CAAC;gBACjB,CAAC;YACL,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;IAEO,QAAQ;QACZ,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAC/B,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QAC1B,CAAC;IACL,CAAC;IAEO,SAAS;QACb,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAC/B,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QAC1B,CAAC;IACL,CAAC;IAEO,WAAW;QACf,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAE/B,MAAM,gBAAgB,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC;QACpD,IAAI,CAAC,YAAY,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QAElE,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;YAC3C,iBAAiB;YACjB,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC7B,IAAI,KAAK,GAAG,KAAK,CAAC;YAElB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACvB,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,IAAI,CAAC;gBAC5B,IAAI,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;oBAC1C,KAAK,GAAG,IAAI,CAAC;oBACb,MAAM;gBACV,CAAC;gBACD,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,IAAI,CAAC;YAChC,CAAC;YAED,IAAI,CAAC,KAAK,EAAE,CAAC;gBACT,IAAI,CAAC,YAAY,CAAC,QAAQ,GAAG,gBAAgB,CAAC;YAClD,CAAC;QACL,CAAC;IACL,CAAC;IAEO,QAAQ;QACZ,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAC/B,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,SAAS,EAAE,CAAC;QACrB,CAAC;IACL,CAAC;IAEO,QAAQ;QACZ,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAC/B,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7C,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QAC1B,CAAC;QACD,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QACtB,IAAI,CAAC,SAAS,EAAE,CAAC;IACrB,CAAC;IAEO,UAAU;QACd,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YAC9E,OAAO;QACX,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,SAAS,EAAE,CAAC;QACrB,CAAC;IACL,CAAC;IAEO,SAAS;QACb,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAE/B,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACtD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE/E,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;YAC1C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;gBAC/C,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;oBAAE,SAAS;gBAEpC,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,GAAG,CAAC;gBACpC,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,GAAG,CAAC;gBAEpC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,YAAY,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,WAAW,EAAE,CAAC;oBAC1D,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC;gBAClC,CAAC;YACL,CAAC;QACL,CAAC;QAED,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,UAAU,EAAE,CAAC;IACtB,CAAC;IAEO,UAAU;QACd,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,MAAM,YAAY,GAAa,EAAE,CAAC;QAElC,KAAK,IAAI,GAAG,GAAG,YAAY,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;YAC/C,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC5C,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;QACL,CAAC;QAED,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;gBAC7B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBAC1B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACnD,CAAC;YAED,YAAY,GAAG,YAAY,CAAC,MAAM,CAAC;YACnC,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC;YAE3B,yBAAyB;YACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;YACjD,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;gBACxB,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;gBACtB,IAAI,CAAC,SAAS,GAAG,kBAAkB,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;gBAE/E,mCAAmC;gBACnC,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;oBAC3B,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBACnC,CAAC;gBACD,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,WAAW,CAChC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,EACvB,IAAI,CAAC,SAAS,CACjB,CAAC;YACN,CAAC;YAED,yCAAyC;YACzC,MAAM,UAAU,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;YAC3C,MAAM,MAAM,GAAG,UAAU,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;YACrD,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC;QACzB,CAAC;QAED,IAAI,CAAC,aAAa,EAAE,CAAC;IACzB,CAAC;IAEO,OAAO;QACX,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI;YAAE,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7D,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI;YAAE,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAE7D,MAAM,eAAe,GAAG,QAAQ,CAAC,cAAc,CAAC,iBAAiB,CAAE,CAAC;QACpE,MAAM,UAAU,GAAG,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAE,CAAC;QAE1D,UAAU,CAAC,WAAW,GAAG,gBAAgB,IAAI,CAAC,KAAK,EAAE,CAAC;QACtD,eAAe,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QAEvC,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAC1E,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAsB,CAAC;QAE1E,QAAQ,CAAC,QAAQ,GAAG,KAAK,CAAC;QAC1B,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC7B,CAAC;IAEO,aAAa;QACjB,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QACtE,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QACtE,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC1E,CAAC;IAEO,MAAM;QACV,IAAI,CAAC,SAAS,EAAE,CAAC;IACrB,CAAC;IAEO,SAAS;QACb,eAAe;QACf,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAE/D,YAAY;QACZ,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,EAAE,CAAC,CAAC,CAAC;YAClC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACnD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACtB,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,YAAY,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;YAClC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;YAClD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACtB,CAAC;QAED,qBAAqB;QACrB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,YAAY,EAAE,GAAG,EAAE,EAAE,CAAC;YAC1C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,WAAW,EAAE,GAAG,EAAE,EAAE,CAAC;gBACzC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC7B,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC1E,CAAC;YACL,CAAC;QACL,CAAC;QAED,qBAAqB;QACrB,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACpB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACtC,CAAC;QAED,cAAc;QACd,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACrE,CAAC;IAEO,SAAS,CAAC,KAAY;QAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;QAE3C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;YAC1C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;gBAC/C,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;oBAAE,SAAS;gBAEpC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC;gBACxB,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC;gBAExB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACT,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;gBAC/B,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAEO,QAAQ,CAAC,CAAS,EAAE,CAAS,EAAE,KAAa;QAChD,MAAM,OAAO,GAAG,CAAC,CAAC;QAClB,MAAM,KAAK,GAAG,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC;QACtC,MAAM,KAAK,GAAG,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC;QACtC,MAAM,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,CAAC,CAAC;QAE1C,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC;QAC3B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAEtD,+BAA+B;QAC/B,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,0BAA0B,CAAC;QAClD,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC5D,CAAC;IAEO,aAAa;QACjB,oBAAoB;QACpB,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;QACnC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAE3E,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAE5B,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;QACpD,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;QACpD,MAAM,QAAQ,GAAG,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QACzE,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAEvE,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;YAC1C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;gBAC/C,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;oBAAE,SAAS;gBAEpC,MAAM,CAAC,GAAG,OAAO,GAAG,GAAG,GAAG,QAAQ,GAAG,CAAC,CAAC;gBACvC,MAAM,CAAC,GAAG,OAAO,GAAG,GAAG,GAAG,QAAQ,GAAG,CAAC,CAAC;gBAEvC,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,KAAK,CAAC;gBAC/B,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;gBAExD,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG,0BAA0B,CAAC;gBACtD,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;gBAC3B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;YAC9D,CAAC;QACL,CAAC;IACL,CAAC;IAEO,iBAAiB,CAAC,KAAa;QACnC,MAAM,MAAM,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAC7F,OAAO,MAAM,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/C,CAAC;CACJ;AAED,qCAAqC;AACrC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAC/C,IAAI,UAAU,EAAE,CAAC;AACrB,CAAC,CAAC,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,407 @@ +"use strict"; +// Tetris Game in TypeScript +// Constants +const GRID_WIDTH = 10; +const GRID_HEIGHT = 20; +const BLOCK_SIZE = 30; +const INITIAL_DROP_SPEED = 1000; // ms +const MIN_DROP_SPEED = 100; // ms +// Color palette for Tetris pieces +const COLORS = { + I: '#00f0f0', // Cyan + O: '#f0f000', // Yellow + T: '#a000f0', // Purple + S: '#00f000', // Green + Z: '#f00000', // Red + J: '#0000f0', // Blue + L: '#f0a500', // Orange + empty: '#222222', // Dark background + border: '#444444', // Border color +}; +// Tetris piece shapes (in their initial rotation) +const PIECE_SHAPES = { + I: [ + [[1, 1, 1, 1]], + [[1], [1], [1], [1]], + ], + O: [ + [[1, 1], [1, 1]], + ], + T: [ + [[0, 1, 0], [1, 1, 1]], + [[1, 0], [1, 1], [1, 0]], + [[1, 1, 1], [0, 1, 0]], + [[0, 1], [1, 1], [0, 1]], + ], + S: [ + [[0, 1, 1], [1, 1, 0]], + [[1, 0], [1, 1], [0, 1]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1]], + [[0, 1], [1, 1], [1, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1]], + [[1, 1], [1, 0], [1, 0]], + [[1, 1, 1], [0, 0, 1]], + [[0, 1], [0, 1], [1, 1]], + ], + L: [ + [[0, 0, 1], [1, 1, 1]], + [[1, 0], [1, 0], [1, 1]], + [[1, 1, 1], [1, 0, 0]], + [[1, 1], [0, 1], [0, 1]], + ], +}; +class TetrisGame { + constructor(canvasId) { + this.grid = []; + this.currentPiece = null; + this.nextPiece = null; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameRunning = true; + this.lastDropTime = 0; + this.dropSpeed = INITIAL_DROP_SPEED; + this.keys = {}; + this.lastMoveTime = 0; + this.moveDelay = 50; // ms between moves + this.canvas = document.getElementById(canvasId); + if (!this.canvas) { + throw new Error(`Canvas with id ${canvasId} not found`); + } + this.ctx = this.canvas.getContext('2d'); + this.canvas.width = GRID_WIDTH * BLOCK_SIZE; + this.canvas.height = GRID_HEIGHT * BLOCK_SIZE; + this.initializeGrid(); + this.setupEventListeners(); + this.currentPiece = this.createPiece(); + this.nextPiece = this.createPiece(); + this.startGameLoop(); + } + initializeGrid() { + this.grid = Array(GRID_HEIGHT) + .fill(null) + .map(() => Array(GRID_WIDTH).fill(0)); + } + setupEventListeners() { + window.addEventListener('keydown', (e) => { + this.keys[e.key.toLowerCase()] = true; + // Immediate actions + if (e.key === 'ArrowUp' || e.key === 'x' || e.key === 'X') { + e.preventDefault(); + this.rotatePiece(); + } + if (e.key === 'z' || e.key === 'Z') { + e.preventDefault(); + this.rotatePieceCounterClockwise(); + } + if (e.key === ' ') { + e.preventDefault(); + this.hardDrop(); + } + if (e.key === 'p' || e.key === 'P') { + this.togglePause(); + } + }); + window.addEventListener('keyup', (e) => { + this.keys[e.key.toLowerCase()] = false; + }); + } + createPiece() { + const types = Object.keys(PIECE_SHAPES); + const type = types[Math.floor(Math.random() * types.length)]; + const shapes = PIECE_SHAPES[type]; + const rotationIndex = 0; + const shape = shapes[rotationIndex]; + return { + type, + x: Math.floor(GRID_WIDTH / 2) - Math.floor(shape[0].length / 2), + y: 0, + rotationIndex, + shape, + }; + } + canMovePiece(piece, newX, newY) { + for (let y = 0; y < piece.shape.length; y++) { + for (let x = 0; x < piece.shape[y].length; x++) { + if (piece.shape[y][x] === 1) { + const gridX = newX + x; + const gridY = newY + y; + if (gridX < 0 || gridX >= GRID_WIDTH || gridY >= GRID_HEIGHT) { + return false; + } + if (gridY >= 0 && this.grid[gridY][gridX] !== 0) { + return false; + } + } + } + } + return true; + } + rotatePiece() { + if (!this.currentPiece) + return; + const shapes = PIECE_SHAPES[this.currentPiece.type]; + const nextRotationIndex = (this.currentPiece.rotationIndex + 1) % shapes.length; + const nextShape = shapes[nextRotationIndex]; + const testPiece = { + ...this.currentPiece, + rotationIndex: nextRotationIndex, + shape: nextShape, + }; + // Try rotation at current position + if (this.canMovePiece(testPiece, testPiece.x, testPiece.y)) { + this.currentPiece = testPiece; + return; + } + // Try wall kick (offset by -1, 1, -2, 2) + const offsets = [-1, 1, -2, 2]; + for (const offset of offsets) { + if (this.canMovePiece(testPiece, testPiece.x + offset, testPiece.y)) { + testPiece.x += offset; + this.currentPiece = testPiece; + return; + } + } + } + rotatePieceCounterClockwise() { + if (!this.currentPiece) + return; + const shapes = PIECE_SHAPES[this.currentPiece.type]; + const nextRotationIndex = (this.currentPiece.rotationIndex - 1 + shapes.length) % shapes.length; + const nextShape = shapes[nextRotationIndex]; + const testPiece = { + ...this.currentPiece, + rotationIndex: nextRotationIndex, + shape: nextShape, + }; + if (this.canMovePiece(testPiece, testPiece.x, testPiece.y)) { + this.currentPiece = testPiece; + return; + } + const offsets = [-1, 1, -2, 2]; + for (const offset of offsets) { + if (this.canMovePiece(testPiece, testPiece.x + offset, testPiece.y)) { + testPiece.x += offset; + this.currentPiece = testPiece; + return; + } + } + } + movePiece(deltaX) { + if (!this.currentPiece) + return; + const newX = this.currentPiece.x + deltaX; + if (this.canMovePiece(this.currentPiece, newX, this.currentPiece.y)) { + this.currentPiece.x = newX; + } + } + hardDrop() { + if (!this.currentPiece) + return; + while (this.canMovePiece(this.currentPiece, this.currentPiece.x, this.currentPiece.y + 1)) { + this.currentPiece.y++; + } + this.lockPiece(); + } + dropPiece() { + if (!this.currentPiece) + return; + if (this.canMovePiece(this.currentPiece, this.currentPiece.x, this.currentPiece.y + 1)) { + this.currentPiece.y++; + } + else { + this.lockPiece(); + } + } + lockPiece() { + if (!this.currentPiece) + return; + const piece = this.currentPiece; + for (let y = 0; y < piece.shape.length; y++) { + for (let x = 0; x < piece.shape[y].length; x++) { + if (piece.shape[y][x] === 1) { + const gridY = piece.y + y; + const gridX = piece.x + x; + if (gridY >= 0 && gridY < GRID_HEIGHT && gridX >= 0 && gridX < GRID_WIDTH) { + this.grid[gridY][gridX] = piece.type.charCodeAt(0); + } + } + } + } + this.clearLines(); + this.currentPiece = this.nextPiece; + this.nextPiece = this.createPiece(); + // Check for game over + if (this.currentPiece && !this.canMovePiece(this.currentPiece, this.currentPiece.x, this.currentPiece.y)) { + this.gameOver(); + } + } + clearLines() { + let linesCleared = 0; + for (let y = GRID_HEIGHT - 1; y >= 0; y--) { + if (this.grid[y].every(cell => cell !== 0)) { + this.grid.splice(y, 1); + this.grid.unshift(Array(GRID_WIDTH).fill(0)); + linesCleared++; + y++; // Check the same row again + } + } + if (linesCleared > 0) { + this.lines += linesCleared; + const points = [40, 100, 300, 1200]; + this.score += (points[linesCleared - 1] || 0) * this.level; + this.updateLevel(); + } + } + updateLevel() { + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel !== this.level) { + this.level = newLevel; + this.dropSpeed = Math.max(MIN_DROP_SPEED, INITIAL_DROP_SPEED - (this.level - 1) * 50); + } + } + togglePause() { + this.gameRunning = !this.gameRunning; + if (this.gameRunning) { + this.lastDropTime = Date.now(); + } + } + gameOver() { + this.gameRunning = false; + } + update() { + if (!this.gameRunning) + return; + const now = Date.now(); + // Handle continuous movement + if (now - this.lastMoveTime > this.moveDelay) { + if (this.keys['arrowleft']) { + this.movePiece(-1); + } + if (this.keys['arrowright']) { + this.movePiece(1); + } + if (this.keys['arrowdown']) { + this.dropPiece(); + this.lastDropTime = now; + } + this.lastMoveTime = now; + } + // Handle piece drop + if (now - this.lastDropTime > this.dropSpeed) { + this.dropPiece(); + this.lastDropTime = now; + } + } + draw() { + // Clear canvas + this.ctx.fillStyle = COLORS.empty; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid lines + this.ctx.strokeStyle = COLORS.border; + this.ctx.lineWidth = 1; + for (let x = 0; x <= GRID_WIDTH; x++) { + this.ctx.beginPath(); + this.ctx.moveTo(x * BLOCK_SIZE, 0); + this.ctx.lineTo(x * BLOCK_SIZE, this.canvas.height); + this.ctx.stroke(); + } + for (let y = 0; y <= GRID_HEIGHT; y++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, y * BLOCK_SIZE); + this.ctx.lineTo(this.canvas.width, y * BLOCK_SIZE); + this.ctx.stroke(); + } + // Draw locked pieces + for (let y = 0; y < this.grid.length; y++) { + for (let x = 0; x < this.grid[y].length; x++) { + if (this.grid[y][x] !== 0) { + const pieceType = String.fromCharCode(this.grid[y][x]); + this.drawBlock(x, y, COLORS[pieceType]); + } + } + } + // Draw current piece + if (this.currentPiece) { + const color = COLORS[this.currentPiece.type]; + for (let y = 0; y < this.currentPiece.shape.length; y++) { + for (let x = 0; x < this.currentPiece.shape[y].length; x++) { + if (this.currentPiece.shape[y][x] === 1) { + this.drawBlock(this.currentPiece.x + x, this.currentPiece.y + y, color); + } + } + } + } + } + drawBlock(x, y, color) { + const drawX = x * BLOCK_SIZE; + const drawY = y * BLOCK_SIZE; + // Fill block + this.ctx.fillStyle = color; + this.ctx.fillRect(drawX + 1, drawY + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + // Add subtle 3D effect + this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)'; + this.ctx.lineWidth = 2; + this.ctx.beginPath(); + this.ctx.moveTo(drawX + 2, drawY + BLOCK_SIZE - 2); + this.ctx.lineTo(drawX + 2, drawY + 2); + this.ctx.lineTo(drawX + BLOCK_SIZE - 2, drawY + 2); + this.ctx.stroke(); + this.ctx.strokeStyle = 'rgba(0, 0, 0, 0.3)'; + this.ctx.beginPath(); + this.ctx.moveTo(drawX + BLOCK_SIZE - 2, drawY + 2); + this.ctx.lineTo(drawX + BLOCK_SIZE - 2, drawY + BLOCK_SIZE - 2); + this.ctx.lineTo(drawX + 2, drawY + BLOCK_SIZE - 2); + this.ctx.stroke(); + } + startGameLoop() { + const gameLoop = () => { + this.update(); + this.draw(); + this.updateHUD(); + requestAnimationFrame(gameLoop); + }; + gameLoop(); + } + updateHUD() { + const scoreElement = document.getElementById('score'); + const linesElement = document.getElementById('lines'); + const levelElement = document.getElementById('level'); + const statusElement = document.getElementById('status'); + if (scoreElement) + scoreElement.textContent = this.score.toString(); + if (linesElement) + linesElement.textContent = this.lines.toString(); + if (levelElement) + levelElement.textContent = this.level.toString(); + if (statusElement) { + statusElement.textContent = this.gameRunning ? 'Playing' : 'PAUSED'; + statusElement.style.color = this.gameRunning ? '#0f0' : '#f00'; + } + } + reset() { + this.initializeGrid(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.dropSpeed = INITIAL_DROP_SPEED; + this.gameRunning = true; + this.currentPiece = this.createPiece(); + this.nextPiece = this.createPiece(); + } +} +// Initialize game when DOM is ready +let game; +document.addEventListener('DOMContentLoaded', () => { + game = new TetrisGame('tetris-canvas'); + const resetButton = document.getElementById('reset-btn'); + if (resetButton) { + resetButton.addEventListener('click', () => { + game.reset(); + }); + } +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.d.ts @@ -0,0 +1,77 @@ +type Color = 'cyan' | 'blue' | 'orange' | 'yellow' | 'green' | 'purple' | 'red' | 'gray'; +interface Position { + x: number; + y: number; +} +interface Tetromino { + shape: number[][]; + color: Color; +} +declare const TETROMINOES: { + I: { + color: Color; + rotations: number[][][]; + }; + O: { + color: Color; + rotations: number[][][]; + }; + T: { + color: Color; + rotations: number[][][]; + }; + S: { + color: Color; + rotations: number[][][]; + }; + Z: { + color: Color; + rotations: number[][][]; + }; + J: { + color: Color; + rotations: number[][][]; + }; + L: { + color: Color; + rotations: number[][][]; + }; +}; +type TetrominoType = keyof typeof TETROMINOES; +declare class TetrisGame { + private canvas; + private ctx; + private gridWidth; + private gridHeight; + private cellSize; + private board; + private currentPiece; + private nextPiece; + private score; + private level; + private lines; + private gameOver; + private dropInterval; + private lastDropTime; + private dropCounter; + private keys; + constructor(canvasId: string); + private initializeBoard; + private setupEventListeners; + private spawnNewPiece; + private getTetrominoShape; + private isValidPosition; + private lockPiece; + private clearLines; + private updateDropSpeed; + private rotatePiece; + private moveHorizontal; + private moveDown; + private hardDrop; + private draw; + private drawBlock; + private updateUI; + private reset; + start(): void; +} +//# sourceMappingURL=tetris.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.d.ts.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.d.ts","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"AAEA,KAAK,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEzF,UAAU,QAAQ;IAChB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,UAAU,SAAS;IACjB,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;CACd;AAGD,QAAA,MAAM,WAAW;;eAEI,KAAK;;;;eAOH,KAAK;;;;eAML,KAAK;;;;eASN,KAAK;;;;eAOP,KAAK;;;;eAOJ,KAAK;;;;eASH,KAAK;;;CAQ3B,CAAC;AAEF,KAAK,aAAa,GAAG,MAAM,OAAO,WAAW,CAAC;AAE9C,cAAM,UAAU;IACd,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,GAAG,CAA2B;IAEtC,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,QAAQ,CAAM;IAEtB,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,YAAY,CAAyE;IAC7F,OAAO,CAAC,SAAS,CAA8B;IAE/C,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,QAAQ,CAAS;IAEzB,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,WAAW,CAAK;IAExB,OAAO,CAAC,IAAI,CAAkC;gBAElC,QAAQ,EAAE,MAAM;IAoB5B,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,mBAAmB;IAmC3B,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,eAAe;IAuBvB,OAAO,CAAC,SAAS;IAuBjB,OAAO,CAAC,UAAU;IAyBlB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,IAAI;IAsDZ,OAAO,CAAC,SAAS;IAoBjB,OAAO,CAAC,QAAQ;IAkBhB,OAAO,CAAC,KAAK;IAWN,KAAK,IAAI,IAAI;CA8BrB"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.js @@ -0,0 +1,379 @@ +"use strict"; +// Tetris Game in TypeScript +// Tetromino shapes (all rotations precomputed) +const TETROMINOES = { + I: { + color: 'cyan', + rotations: [ + [[1, 1, 1, 1]], + [[1], [1], [1], [1]], + ], + }, + O: { + color: 'yellow', + rotations: [ + [[1, 1], [1, 1]], + ], + }, + T: { + color: 'purple', + rotations: [ + [[1, 1, 1], [0, 1, 0]], + [[1, 0], [1, 1], [1, 0]], + [[0, 1, 0], [1, 1, 1]], + [[0, 1], [1, 1], [0, 1]], + ], + }, + S: { + color: 'green', + rotations: [ + [[0, 1, 1], [1, 1, 0]], + [[1, 0], [1, 1], [0, 1]], + ], + }, + Z: { + color: 'red', + rotations: [ + [[1, 1, 0], [0, 1, 1]], + [[0, 1], [1, 1], [1, 0]], + ], + }, + J: { + color: 'blue', + rotations: [ + [[1, 0, 0], [1, 1, 1]], + [[1, 1], [1, 0], [1, 0]], + [[1, 1, 1], [0, 0, 1]], + [[0, 1], [0, 1], [1, 1]], + ], + }, + L: { + color: 'orange', + rotations: [ + [[0, 0, 1], [1, 1, 1]], + [[1, 0], [1, 0], [1, 1]], + [[1, 1, 1], [1, 0, 0]], + [[1, 1], [0, 1], [0, 1]], + ], + }, +}; +class TetrisGame { + constructor(canvasId) { + this.gridWidth = 10; + this.gridHeight = 20; + this.cellSize = 30; + this.board = []; + this.currentPiece = null; + this.nextPiece = null; + this.score = 0; + this.level = 0; + this.lines = 0; + this.gameOver = false; + this.dropInterval = 1000; + this.lastDropTime = 0; + this.dropCounter = 0; + this.keys = {}; + const canvas = document.getElementById(canvasId); + if (!canvas) { + throw new Error(`Canvas with id "${canvasId}" not found`); + } + this.canvas = canvas; + this.ctx = canvas.getContext('2d'); + if (!this.ctx) { + throw new Error('Failed to get 2D context from canvas'); + } + this.canvas.width = this.gridWidth * this.cellSize; + this.canvas.height = this.gridHeight * this.cellSize; + this.initializeBoard(); + this.setupEventListeners(); + this.spawnNewPiece(); + } + initializeBoard() { + this.board = []; + for (let y = 0; y < this.gridHeight; y++) { + this.board[y] = new Array(this.gridWidth).fill(null); + } + } + setupEventListeners() { + document.addEventListener('keydown', (e) => { + this.keys[e.key] = true; + if (!this.gameOver) { + switch (e.key) { + case 'ArrowLeft': + case 'ArrowRight': + case 'ArrowDown': + case ' ': + case 'z': + case 'x': + e.preventDefault(); + break; + } + if (e.key === ' ') { + this.hardDrop(); + } + else if (e.key === 'z') { + this.rotatePiece(-1); + } + else if (e.key === 'x') { + this.rotatePiece(1); + } + } + if (e.key === 'r') { + this.reset(); + } + }); + document.addEventListener('keyup', (e) => { + this.keys[e.key] = false; + }); + } + spawnNewPiece() { + const types = Object.keys(TETROMINOES); + const type = this.nextPiece || types[Math.floor(Math.random() * types.length)]; + this.nextPiece = types[Math.floor(Math.random() * types.length)]; + const tetrominoData = TETROMINOES[type]; + const rotation = 0; + this.currentPiece = { + type, + rotation, + pos: { x: Math.floor(this.gridWidth / 2) - 1, y: 0 }, + }; + if (!this.isValidPosition(this.currentPiece)) { + this.gameOver = true; + } + } + getTetrominoShape() { + if (!this.currentPiece) + return []; + const tetrominoData = TETROMINOES[this.currentPiece.type]; + return tetrominoData.rotations[this.currentPiece.rotation]; + } + isValidPosition(piece) { + const shape = TETROMINOES[piece.type].rotations[piece.rotation]; + for (let y = 0; y < shape.length; y++) { + for (let x = 0; x < shape[y].length; x++) { + if (shape[y][x]) { + const boardX = piece.pos.x + x; + const boardY = piece.pos.y + y; + if (boardX < 0 || boardX >= this.gridWidth || boardY >= this.gridHeight) { + return false; + } + if (boardY >= 0 && this.board[boardY][boardX] !== null) { + return false; + } + } + } + } + return true; + } + lockPiece() { + if (!this.currentPiece) + return; + const shape = this.getTetrominoShape(); + const color = TETROMINOES[this.currentPiece.type].color; + for (let y = 0; y < shape.length; y++) { + for (let x = 0; x < shape[y].length; x++) { + if (shape[y][x]) { + const boardY = this.currentPiece.pos.y + y; + const boardX = this.currentPiece.pos.x + x; + if (boardY >= 0 && boardY < this.gridHeight && boardX >= 0 && boardX < this.gridWidth) { + this.board[boardY][boardX] = color; + } + } + } + } + this.clearLines(); + this.spawnNewPiece(); + } + clearLines() { + const linesToClear = []; + for (let y = this.gridHeight - 1; y >= 0; y--) { + if (this.board[y].every((cell) => cell !== null)) { + linesToClear.push(y); + } + } + if (linesToClear.length > 0) { + for (const line of linesToClear) { + this.board.splice(line, 1); + this.board.unshift(new Array(this.gridWidth).fill(null)); + } + this.lines += linesToClear.length; + const points = [0, 40, 100, 300, 1200]; + this.score += points[linesToClear.length] * (this.level + 1); + this.level = Math.floor(this.lines / 10); + this.updateDropSpeed(); + } + } + updateDropSpeed() { + this.dropInterval = Math.max(100, 1000 - this.level * 50); + } + rotatePiece(direction) { + if (!this.currentPiece) + return; + const tetrominoData = TETROMINOES[this.currentPiece.type]; + const maxRotation = tetrominoData.rotations.length; + const oldRotation = this.currentPiece.rotation; + this.currentPiece.rotation = (this.currentPiece.rotation + direction + maxRotation) % maxRotation; + if (!this.isValidPosition(this.currentPiece)) { + this.currentPiece.rotation = oldRotation; + } + } + moveHorizontal(direction) { + if (!this.currentPiece) + return; + const newPos = { ...this.currentPiece.pos, x: this.currentPiece.pos.x + direction }; + const testPiece = { ...this.currentPiece, pos: newPos }; + if (this.isValidPosition(testPiece)) { + this.currentPiece.pos.x = newPos.x; + } + } + moveDown() { + if (!this.currentPiece) + return; + const newPos = { ...this.currentPiece.pos, y: this.currentPiece.pos.y + 1 }; + const testPiece = { ...this.currentPiece, pos: newPos }; + if (this.isValidPosition(testPiece)) { + this.currentPiece.pos.y = newPos.y; + } + else { + this.lockPiece(); + } + } + hardDrop() { + if (!this.currentPiece) + return; + while (true) { + const newPos = { ...this.currentPiece.pos, y: this.currentPiece.pos.y + 1 }; + const testPiece = { ...this.currentPiece, pos: newPos }; + if (!this.isValidPosition(testPiece)) { + break; + } + this.currentPiece.pos.y = newPos.y; + } + this.lockPiece(); + } + draw() { + // Clear canvas + this.ctx.fillStyle = '#1a1a1a'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid background + this.ctx.strokeStyle = '#333'; + this.ctx.lineWidth = 0.5; + for (let x = 0; x <= this.gridWidth; x++) { + this.ctx.beginPath(); + this.ctx.moveTo(x * this.cellSize, 0); + this.ctx.lineTo(x * this.cellSize, this.canvas.height); + this.ctx.stroke(); + } + for (let y = 0; y <= this.gridHeight; y++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, y * this.cellSize); + this.ctx.lineTo(this.canvas.width, y * this.cellSize); + this.ctx.stroke(); + } + // Draw placed blocks + for (let y = 0; y < this.gridHeight; y++) { + for (let x = 0; x < this.gridWidth; x++) { + if (this.board[y][x] !== null) { + this.drawBlock(x, y, this.board[y][x]); + } + } + } + // Draw current piece + if (this.currentPiece) { + const shape = this.getTetrominoShape(); + const color = TETROMINOES[this.currentPiece.type].color; + for (let y = 0; y < shape.length; y++) { + for (let x = 0; x < shape[y].length; x++) { + if (shape[y][x]) { + const boardX = this.currentPiece.pos.x + x; + const boardY = this.currentPiece.pos.y + y; + if (boardY >= 0) { + this.drawBlock(boardX, boardY, color); + } + } + } + } + } + // Draw border + this.ctx.strokeStyle = '#fff'; + this.ctx.lineWidth = 2; + this.ctx.strokeRect(0, 0, this.canvas.width, this.canvas.height); + } + drawBlock(x, y, color) { + const colors = { + cyan: '#00f0f0', + blue: '#0000f0', + orange: '#f0a000', + yellow: '#f0f000', + green: '#00f000', + purple: '#a000f0', + red: '#f00000', + gray: '#808080', + }; + this.ctx.fillStyle = colors[color]; + this.ctx.fillRect(x * this.cellSize + 1, y * this.cellSize + 1, this.cellSize - 2, this.cellSize - 2); + this.ctx.strokeStyle = colors[color]; + this.ctx.lineWidth = 1; + this.ctx.strokeRect(x * this.cellSize + 1, y * this.cellSize + 1, this.cellSize - 2, this.cellSize - 2); + } + updateUI() { + const scoreEl = document.getElementById('score'); + const levelEl = document.getElementById('level'); + const linesEl = document.getElementById('lines'); + const nextEl = document.getElementById('next'); + const gameOverEl = document.getElementById('gameOver'); + if (scoreEl) + scoreEl.textContent = this.score.toString(); + if (levelEl) + levelEl.textContent = this.level.toString(); + if (linesEl) + linesEl.textContent = this.lines.toString(); + if (nextEl && this.nextPiece) { + nextEl.textContent = this.nextPiece; + } + if (gameOverEl) { + gameOverEl.style.display = this.gameOver ? 'block' : 'none'; + } + } + reset() { + this.score = 0; + this.level = 0; + this.lines = 0; + this.gameOver = false; + this.dropInterval = 1000; + this.lastDropTime = 0; + this.initializeBoard(); + this.spawnNewPiece(); + } + start() { + const gameLoop = (timestamp) => { + this.lastDropTime += timestamp - (this.dropCounter || timestamp); + this.dropCounter = timestamp; + if (this.lastDropTime > this.dropInterval && !this.gameOver) { + this.moveDown(); + this.lastDropTime = 0; + } + // Handle continuous movement + if (this.keys['ArrowLeft']) { + this.moveHorizontal(-1); + } + if (this.keys['ArrowRight']) { + this.moveHorizontal(1); + } + if (this.keys['ArrowDown'] && !this.gameOver) { + this.moveDown(); + this.lastDropTime = 0; + } + this.draw(); + this.updateUI(); + requestAnimationFrame(gameLoop); + }; + requestAnimationFrame(gameLoop); + } +} +// Initialize game when DOM is ready +document.addEventListener('DOMContentLoaded', () => { + const game = new TetrisGame('gameCanvas'); + game.start(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/tetris-game/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/board.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/board.d.ts @@ -0,0 +1,15 @@ +import { PieceType, Piece } from './types'; +export declare class Board { + private grid; + readonly width: number; + readonly height: number; + constructor(width: number, height: number); + getGrid(): (PieceType | null)[][]; + canPlace(piece: Piece): boolean; + placePiece(piece: Piece): void; + getOccupiedRows(): number[]; + clearRows(rows: number[]): number; + isGameOver(piece: Piece): boolean; + reset(): void; +} +//# sourceMappingURL=board.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/board.d.ts.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/board.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"board.d.ts","sourceRoot":"","sources":["../src/board.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAY,MAAM,SAAS,CAAC;AAGrD,qBAAa,KAAK;IAChB,OAAO,CAAC,IAAI,CAAyB;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAQzC,OAAO,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,EAAE,EAAE;IAIjC,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IAY/B,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAS9B,eAAe,IAAI,MAAM,EAAE;IAU3B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM;IAcjC,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IAKjC,KAAK,IAAI,IAAI;CAKd"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/board.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/board.js @@ -0,0 +1,59 @@ +import { getPieceBlocks } from './piece'; +export class Board { + constructor(width, height) { + this.width = width; + this.height = height; + this.grid = Array(height) + .fill(null) + .map(() => Array(width).fill(null)); + } + getGrid() { + return this.grid; + } + canPlace(piece) { + const blocks = getPieceBlocks(piece); + return blocks.every((block) => block.x >= 0 && + block.x < this.width && + block.y >= 0 && + block.y < this.height && + this.grid[block.y][block.x] === null); + } + placePiece(piece) { + const blocks = getPieceBlocks(piece); + blocks.forEach((block) => { + if (block.y >= 0 && block.y < this.height && block.x >= 0 && block.x < this.width) { + this.grid[block.y][block.x] = piece.type; + } + }); + } + getOccupiedRows() { + const occupied = []; + for (let y = 0; y < this.height; y++) { + if (this.grid[y].every((cell) => cell !== null)) { + occupied.push(y); + } + } + return occupied; + } + clearRows(rows) { + if (rows.length === 0) + return 0; + // Sort rows in descending order for proper removal + const sortedRows = [...rows].sort((a, b) => b - a); + sortedRows.forEach((row) => { + this.grid.splice(row, 1); + this.grid.unshift(Array(this.width).fill(null)); + }); + return rows.length; + } + isGameOver(piece) { + const blocks = getPieceBlocks(piece); + return blocks.some((block) => block.y < 0); + } + reset() { + this.grid = Array(this.height) + .fill(null) + .map(() => Array(this.width).fill(null)); + } +} +//# sourceMappingURL=board.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/board.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/board.js.map @@ -0,0 +1 @@ +{"version":3,"file":"board.js","sourceRoot":"","sources":["../src/board.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,OAAO,KAAK;IAKhB,YAAY,KAAa,EAAE,MAAc;QACvC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC;aACtB,IAAI,CAAC,IAAI,CAAC;aACV,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACxC,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,QAAQ,CAAC,KAAY;QACnB,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACrC,OAAO,MAAM,CAAC,KAAK,CACjB,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,CAAC,IAAI,CAAC;YACZ,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK;YACpB,KAAK,CAAC,CAAC,IAAI,CAAC;YACZ,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM;YACrB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,CACvC,CAAC;IACJ,CAAC;IAED,UAAU,CAAC,KAAY;QACrB,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACrC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YACvB,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;gBAClF,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC;YAC3C,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,eAAe;QACb,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;gBAChD,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,SAAS,CAAC,IAAc;QACtB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QAEhC,mDAAmD;QACnD,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAEnD,UAAU,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YACzB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,UAAU,CAAC,KAAY;QACrB,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACrC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK;QACH,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;aAC3B,IAAI,CAAC,IAAI,CAAC;aACV,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7C,CAAC;CACF"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/bundle.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/bundle.js @@ -0,0 +1,563 @@ +"use strict"; +(() => { + var __getOwnPropNames = Object.getOwnPropertyNames; + var __esm = (fn, res) => function __init() { + return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; + }; + var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; + + // src/types.ts + var PieceType; + var init_types = __esm({ + "src/types.ts"() { + "use strict"; + PieceType = /* @__PURE__ */ ((PieceType2) => { + PieceType2["I"] = "I"; + PieceType2["O"] = "O"; + PieceType2["T"] = "T"; + PieceType2["S"] = "S"; + PieceType2["Z"] = "Z"; + PieceType2["J"] = "J"; + PieceType2["L"] = "L"; + return PieceType2; + })(PieceType || {}); + } + }); + + // src/piece.ts + function createPiece(type, x = 3, y = 0) { + return { + type, + blocks: [...SHAPES[type][0]], + x, + y, + rotation: 0 + }; + } + function getRandomPieceType() { + const types = Object.values(PieceType); + return types[Math.floor(Math.random() * types.length)]; + } + function rotatePiece(piece) { + const newRotation = (piece.rotation + 1) % 4; + const newPiece = { ...piece }; + newPiece.blocks = SHAPES[piece.type][newRotation]; + newPiece.rotation = newRotation; + return newPiece; + } + function getPieceBlocks(piece) { + return piece.blocks.map((block) => ({ + x: piece.x + block.x, + y: piece.y + block.y + })); + } + var SHAPES, PIECE_COLORS; + var init_piece = __esm({ + "src/piece.ts"() { + "use strict"; + init_types(); + SHAPES = { + ["I" /* I */]: [ + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 3, y: 0 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 0, y: 2 }, { x: 0, y: 3 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 3, y: 0 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 0, y: 2 }, { x: 0, y: 3 }] + ], + ["O" /* O */]: [ + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }] + ], + ["T" /* T */]: [ + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 1, y: 1 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 0, y: 2 }], + [{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 1, y: 2 }] + ], + ["S" /* S */]: [ + [{ x: 1, y: 0 }, { x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 1, y: 2 }], + [{ x: 1, y: 0 }, { x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 1, y: 2 }] + ], + ["Z" /* Z */]: [ + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 0, y: 2 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 0, y: 2 }] + ], + ["J" /* J */]: [ + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: 0, y: 2 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 2, y: 1 }], + [{ x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }] + ], + ["L" /* L */]: [ + [{ x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 0, y: 1 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 1, y: 2 }] + ] + }; + PIECE_COLORS = { + ["I" /* I */]: "#00FFFF", + ["O" /* O */]: "#FFFF00", + ["T" /* T */]: "#FF00FF", + ["S" /* S */]: "#00FF00", + ["Z" /* Z */]: "#FF0000", + ["J" /* J */]: "#0000FF", + ["L" /* L */]: "#FFA500" + }; + } + }); + + // src/board.ts + var Board; + var init_board = __esm({ + "src/board.ts"() { + "use strict"; + init_piece(); + Board = class { + constructor(width, height) { + this.width = width; + this.height = height; + this.grid = Array(height).fill(null).map(() => Array(width).fill(null)); + } + getGrid() { + return this.grid; + } + canPlace(piece) { + const blocks = getPieceBlocks(piece); + return blocks.every( + (block) => block.x >= 0 && block.x < this.width && block.y >= 0 && block.y < this.height && this.grid[block.y][block.x] === null + ); + } + placePiece(piece) { + const blocks = getPieceBlocks(piece); + blocks.forEach((block) => { + if (block.y >= 0 && block.y < this.height && block.x >= 0 && block.x < this.width) { + this.grid[block.y][block.x] = piece.type; + } + }); + } + getOccupiedRows() { + const occupied = []; + for (let y = 0; y < this.height; y++) { + if (this.grid[y].every((cell) => cell !== null)) { + occupied.push(y); + } + } + return occupied; + } + clearRows(rows) { + if (rows.length === 0) return 0; + const sortedRows = [...rows].sort((a, b) => b - a); + sortedRows.forEach((row) => { + this.grid.splice(row, 1); + this.grid.unshift(Array(this.width).fill(null)); + }); + return rows.length; + } + isGameOver(piece) { + const blocks = getPieceBlocks(piece); + return blocks.some((block) => block.y < 0); + } + reset() { + this.grid = Array(this.height).fill(null).map(() => Array(this.width).fill(null)); + } + }; + } + }); + + // src/game.ts + var TetrisGame; + var init_game = __esm({ + "src/game.ts"() { + "use strict"; + init_board(); + init_piece(); + TetrisGame = class { + constructor(config) { + this.dropCounter = 0; + this.config = config; + this.board = new Board(config.boardWidth, config.boardHeight); + this.gameState = { + board: this.board.getGrid(), + currentPiece: null, + nextPiece: null, + score: 0, + level: 1, + linesCleared: 0, + gameOver: false, + paused: false + }; + this.dropInterval = config.initialSpeed; + this.spawnNewPiece(); + } + spawnNewPiece() { + if (this.gameState.nextPiece === null) { + this.gameState.nextPiece = createPiece(getRandomPieceType()); + } + this.gameState.currentPiece = this.gameState.nextPiece; + this.gameState.nextPiece = createPiece(getRandomPieceType()); + if (!this.board.canPlace(this.gameState.currentPiece)) { + this.gameState.gameOver = true; + } + } + updateLevel() { + this.gameState.level = Math.floor(this.gameState.linesCleared / 10) + 1; + this.dropInterval = Math.max( + 100, + this.config.initialSpeed - (this.gameState.level - 1) * 50 + ); + } + addScore(points) { + this.gameState.score += points * this.gameState.level; + } + moveLeft() { + if (this.gameState.paused || this.gameState.gameOver || !this.gameState.currentPiece) { + return; + } + const movedPiece = { ...this.gameState.currentPiece }; + movedPiece.x -= 1; + if (this.board.canPlace(movedPiece)) { + this.gameState.currentPiece = movedPiece; + } + } + moveRight() { + if (this.gameState.paused || this.gameState.gameOver || !this.gameState.currentPiece) { + return; + } + const movedPiece = { ...this.gameState.currentPiece }; + movedPiece.x += 1; + if (this.board.canPlace(movedPiece)) { + this.gameState.currentPiece = movedPiece; + } + } + moveDown() { + if (this.gameState.paused || this.gameState.gameOver || !this.gameState.currentPiece) { + return; + } + const movedPiece = { ...this.gameState.currentPiece }; + movedPiece.y += 1; + if (this.board.canPlace(movedPiece)) { + this.gameState.currentPiece = movedPiece; + this.addScore(1); + } else { + this.lock(); + } + } + hardDrop() { + if (this.gameState.paused || this.gameState.gameOver || !this.gameState.currentPiece) { + return; + } + let distance = 0; + const originalPiece = { ...this.gameState.currentPiece }; + while (true) { + const testPiece = { ...this.gameState.currentPiece }; + testPiece.y += 1; + if (!this.board.canPlace(testPiece)) { + break; + } + this.gameState.currentPiece = testPiece; + distance++; + } + this.addScore(distance * 2); + this.lock(); + } + rotate() { + if (this.gameState.paused || this.gameState.gameOver || !this.gameState.currentPiece) { + return; + } + const rotatedPiece = rotatePiece(this.gameState.currentPiece); + if (this.board.canPlace(rotatedPiece)) { + this.gameState.currentPiece = rotatedPiece; + } + } + lock() { + if (!this.gameState.currentPiece) return; + this.board.placePiece(this.gameState.currentPiece); + if (this.board.isGameOver(this.gameState.currentPiece)) { + this.gameState.gameOver = true; + return; + } + const clearedRows = this.board.getOccupiedRows(); + if (clearedRows.length > 0) { + this.board.clearRows(clearedRows); + this.gameState.linesCleared += clearedRows.length; + const scores = { 1: 40, 2: 100, 3: 300, 4: 1200 }; + this.addScore(scores[clearedRows.length] || 0); + this.updateLevel(); + } + this.spawnNewPiece(); + } + update() { + if (this.gameState.paused || this.gameState.gameOver) { + return; + } + this.dropCounter += 16; + if (this.dropCounter >= this.dropInterval) { + this.dropCounter = 0; + this.moveDown(); + } + } + togglePause() { + if (!this.gameState.gameOver) { + this.gameState.paused = !this.gameState.paused; + } + } + restart() { + this.board.reset(); + this.gameState = { + board: this.board.getGrid(), + currentPiece: null, + nextPiece: null, + score: 0, + level: 1, + linesCleared: 0, + gameOver: false, + paused: false + }; + this.dropCounter = 0; + this.dropInterval = this.config.initialSpeed; + this.spawnNewPiece(); + } + getGameState() { + this.gameState.board = this.board.getGrid(); + return this.gameState; + } + }; + } + }); + + // src/renderer.ts + var Renderer, HUDRenderer; + var init_renderer = __esm({ + "src/renderer.ts"() { + "use strict"; + init_piece(); + Renderer = class { + constructor(canvasId, cellSize, boardWidth, boardHeight) { + this.canvas = document.getElementById(canvasId); + if (!this.canvas) { + throw new Error(`Canvas with id "${canvasId}" not found`); + } + this.ctx = this.canvas.getContext("2d"); + this.cellSize = cellSize; + this.boardWidth = boardWidth; + this.boardHeight = boardHeight; + this.canvas.width = boardWidth * cellSize; + this.canvas.height = boardHeight * cellSize; + } + render(gameState) { + this.ctx.fillStyle = "#000000"; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.drawGrid(); + this.drawBoard(gameState.board); + if (gameState.currentPiece) { + this.drawPiece(gameState.currentPiece); + } + if (gameState.gameOver) { + this.drawGameOverOverlay(); + } + if (gameState.paused) { + this.drawPauseOverlay(); + } + } + drawGrid() { + this.ctx.strokeStyle = "#222222"; + this.ctx.lineWidth = 1; + for (let x = 0; x <= this.boardWidth; x++) { + this.ctx.beginPath(); + this.ctx.moveTo(x * this.cellSize, 0); + this.ctx.lineTo(x * this.cellSize, this.canvas.height); + this.ctx.stroke(); + } + for (let y = 0; y <= this.boardHeight; y++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, y * this.cellSize); + this.ctx.lineTo(this.canvas.width, y * this.cellSize); + this.ctx.stroke(); + } + } + drawBoard(board) { + for (let y = 0; y < board.length; y++) { + for (let x = 0; x < board[y].length; x++) { + if (board[y][x] !== null) { + this.drawCell(x, y, board[y][x]); + } + } + } + } + drawPiece(piece) { + const blocks = getPieceBlocks(piece); + blocks.forEach((block) => { + if (block.y >= 0) { + this.drawCell(block.x, block.y, piece.type); + } + }); + } + drawCell(x, y, pieceType) { + const color = PIECE_COLORS[pieceType]; + this.ctx.fillStyle = color; + this.ctx.fillRect(x * this.cellSize, y * this.cellSize, this.cellSize, this.cellSize); + this.ctx.strokeStyle = "#ffffff"; + this.ctx.lineWidth = 2; + this.ctx.strokeRect(x * this.cellSize, y * this.cellSize, this.cellSize, this.cellSize); + } + drawGameOverOverlay() { + this.ctx.fillStyle = "rgba(0, 0, 0, 0.7)"; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = "#ffffff"; + this.ctx.font = "bold 40px Arial"; + this.ctx.textAlign = "center"; + this.ctx.fillText("GAME OVER", this.canvas.width / 2, this.canvas.height / 2 - 20); + this.ctx.font = "20px Arial"; + this.ctx.fillText("Press R to restart", this.canvas.width / 2, this.canvas.height / 2 + 30); + } + drawPauseOverlay() { + this.ctx.fillStyle = "rgba(0, 0, 0, 0.5)"; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = "#ffffff"; + this.ctx.font = "bold 40px Arial"; + this.ctx.textAlign = "center"; + this.ctx.fillText("PAUSED", this.canvas.width / 2, this.canvas.height / 2); + this.ctx.font = "20px Arial"; + this.ctx.fillText("Press SPACE to resume", this.canvas.width / 2, this.canvas.height / 2 + 40); + } + }; + HUDRenderer = class { + constructor(containerId) { + this.container = document.getElementById(containerId); + if (!this.container) { + throw new Error(`Container with id "${containerId}" not found`); + } + } + render(gameState, nextPiece) { + this.container.innerHTML = ` + <div class="hud-item"> + <div class="hud-label">Score</div> + <div class="hud-value">${gameState.score}</div> + </div> + <div class="hud-item"> + <div class="hud-label">Level</div> + <div class="hud-value">${gameState.level}</div> + </div> + <div class="hud-item"> + <div class="hud-label">Lines Cleared</div> + <div class="hud-value">${gameState.linesCleared}</div> + </div> + <div class="hud-item"> + <div class="hud-label">Next Piece</div> + <canvas id="next-piece-canvas" width="100" height="100"></canvas> + </div> + `; + if (nextPiece) { + this.drawNextPiece(nextPiece); + } + } + drawNextPiece(piece) { + const canvas = document.getElementById("next-piece-canvas"); + if (!canvas) return; + const ctx = canvas.getContext("2d"); + const cellSize = 20; + ctx.fillStyle = "#000000"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + const blocks = getPieceBlocks({ ...piece, x: 2, y: 1 }); + const { r, g, b } = this.parseColor(PIECE_COLORS[piece.type]); + blocks.forEach((block) => { + if (block.x >= 0 && block.x < 5 && block.y >= 0 && block.y < 5) { + ctx.fillStyle = PIECE_COLORS[piece.type]; + ctx.fillRect(block.x * cellSize, block.y * cellSize, cellSize, cellSize); + ctx.strokeStyle = "#ffffff"; + ctx.lineWidth = 1; + ctx.strokeRect(block.x * cellSize, block.y * cellSize, cellSize, cellSize); + } + }); + } + parseColor(color) { + const hex = color.replace("#", ""); + return { + r: parseInt(hex.substr(0, 2), 16), + g: parseInt(hex.substr(2, 2), 16), + b: parseInt(hex.substr(4, 2), 16) + }; + } + }; + } + }); + + // src/main.ts + var require_main = __commonJS({ + "src/main.ts"() { + init_game(); + init_renderer(); + var config = { + boardWidth: 10, + boardHeight: 20, + cellSize: 30, + initialSpeed: 400, + speedMultiplier: 0.9 + }; + var game = new TetrisGame(config); + var renderer = new Renderer("game-canvas", config.cellSize, config.boardWidth, config.boardHeight); + var hudRenderer = new HUDRenderer("hud"); + var lastTime = Date.now(); + var gameRunning = true; + function gameLoop() { + const now = Date.now(); + const deltaTime = now - lastTime; + lastTime = now; + if (gameRunning) { + game.update(); + const gameState = game.getGameState(); + renderer.render(gameState); + hudRenderer.render(gameState, gameState.nextPiece); + } + requestAnimationFrame(gameLoop); + } + document.addEventListener("keydown", (e) => { + const key = e.key.toLowerCase(); + switch (key) { + case "arrowleft": + case "a": + e.preventDefault(); + game.moveLeft(); + break; + case "arrowright": + case "d": + e.preventDefault(); + game.moveRight(); + break; + case "arrowdown": + case "s": + e.preventDefault(); + game.moveDown(); + break; + case " ": + e.preventDefault(); + game.togglePause(); + break; + case "w": + case "arrowup": + e.preventDefault(); + game.rotate(); + break; + case "z": + e.preventDefault(); + game.hardDrop(); + break; + case "r": + e.preventDefault(); + game.restart(); + break; + } + }); + gameLoop(); + } + }); + require_main(); +})(); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/game.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/game.d.ts @@ -0,0 +1,23 @@ +import { Config, GameState } from './types'; +export declare class TetrisGame { + private board; + private gameState; + private config; + private dropCounter; + private dropInterval; + constructor(config: Config); + private spawnNewPiece; + private updateLevel; + private addScore; + moveLeft(): void; + moveRight(): void; + moveDown(): void; + hardDrop(): void; + rotate(): void; + private lock; + update(): void; + togglePause(): void; + restart(): void; + getGameState(): GameState; +} +//# sourceMappingURL=game.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/game.d.ts.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/game.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"game.d.ts","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAoB,MAAM,SAAS,CAAC;AAI9D,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,YAAY,CAAS;gBAEjB,MAAM,EAAE,MAAM;IAiB1B,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,QAAQ;IAIhB,QAAQ,IAAI,IAAI;IAahB,SAAS,IAAI,IAAI;IAajB,QAAQ,IAAI,IAAI;IAgBhB,QAAQ,IAAI,IAAI;IAwBhB,MAAM,IAAI,IAAI;IAYd,OAAO,CAAC,IAAI;IAyBZ,MAAM,IAAI,IAAI;IAad,WAAW,IAAI,IAAI;IAMnB,OAAO,IAAI,IAAI;IAiBf,YAAY,IAAI,SAAS;CAI1B"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/game.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/game.js @@ -0,0 +1,154 @@ +import { Board } from './board'; +import { createPiece, getRandomPieceType, rotatePiece } from './piece'; +export class TetrisGame { + constructor(config) { + this.dropCounter = 0; + this.config = config; + this.board = new Board(config.boardWidth, config.boardHeight); + this.gameState = { + board: this.board.getGrid(), + currentPiece: null, + nextPiece: null, + score: 0, + level: 1, + linesCleared: 0, + gameOver: false, + paused: false, + }; + this.dropInterval = config.initialSpeed; + this.spawnNewPiece(); + } + spawnNewPiece() { + if (this.gameState.nextPiece === null) { + this.gameState.nextPiece = createPiece(getRandomPieceType()); + } + this.gameState.currentPiece = this.gameState.nextPiece; + this.gameState.nextPiece = createPiece(getRandomPieceType()); + if (!this.board.canPlace(this.gameState.currentPiece)) { + this.gameState.gameOver = true; + } + } + updateLevel() { + this.gameState.level = Math.floor(this.gameState.linesCleared / 10) + 1; + this.dropInterval = Math.max(100, this.config.initialSpeed - (this.gameState.level - 1) * 50); + } + addScore(points) { + this.gameState.score += points * this.gameState.level; + } + moveLeft() { + if (this.gameState.paused || this.gameState.gameOver || !this.gameState.currentPiece) { + return; + } + const movedPiece = { ...this.gameState.currentPiece }; + movedPiece.x -= 1; + if (this.board.canPlace(movedPiece)) { + this.gameState.currentPiece = movedPiece; + } + } + moveRight() { + if (this.gameState.paused || this.gameState.gameOver || !this.gameState.currentPiece) { + return; + } + const movedPiece = { ...this.gameState.currentPiece }; + movedPiece.x += 1; + if (this.board.canPlace(movedPiece)) { + this.gameState.currentPiece = movedPiece; + } + } + moveDown() { + if (this.gameState.paused || this.gameState.gameOver || !this.gameState.currentPiece) { + return; + } + const movedPiece = { ...this.gameState.currentPiece }; + movedPiece.y += 1; + if (this.board.canPlace(movedPiece)) { + this.gameState.currentPiece = movedPiece; + this.addScore(1); + } + else { + this.lock(); + } + } + hardDrop() { + if (this.gameState.paused || this.gameState.gameOver || !this.gameState.currentPiece) { + return; + } + let distance = 0; + const originalPiece = { ...this.gameState.currentPiece }; + while (true) { + const testPiece = { ...this.gameState.currentPiece }; + testPiece.y += 1; + if (!this.board.canPlace(testPiece)) { + break; + } + this.gameState.currentPiece = testPiece; + distance++; + } + this.addScore(distance * 2); + this.lock(); + } + rotate() { + if (this.gameState.paused || this.gameState.gameOver || !this.gameState.currentPiece) { + return; + } + const rotatedPiece = rotatePiece(this.gameState.currentPiece); + if (this.board.canPlace(rotatedPiece)) { + this.gameState.currentPiece = rotatedPiece; + } + } + lock() { + if (!this.gameState.currentPiece) + return; + this.board.placePiece(this.gameState.currentPiece); + if (this.board.isGameOver(this.gameState.currentPiece)) { + this.gameState.gameOver = true; + return; + } + const clearedRows = this.board.getOccupiedRows(); + if (clearedRows.length > 0) { + this.board.clearRows(clearedRows); + this.gameState.linesCleared += clearedRows.length; + // Scoring: Standard Tetris scoring + const scores = { 1: 40, 2: 100, 3: 300, 4: 1200 }; + this.addScore(scores[clearedRows.length] || 0); + this.updateLevel(); + } + this.spawnNewPiece(); + } + update() { + if (this.gameState.paused || this.gameState.gameOver) { + return; + } + this.dropCounter += 16; // Approximate delta time in ms + if (this.dropCounter >= this.dropInterval) { + this.dropCounter = 0; + this.moveDown(); + } + } + togglePause() { + if (!this.gameState.gameOver) { + this.gameState.paused = !this.gameState.paused; + } + } + restart() { + this.board.reset(); + this.gameState = { + board: this.board.getGrid(), + currentPiece: null, + nextPiece: null, + score: 0, + level: 1, + linesCleared: 0, + gameOver: false, + paused: false, + }; + this.dropCounter = 0; + this.dropInterval = this.config.initialSpeed; + this.spawnNewPiece(); + } + getGameState() { + this.gameState.board = this.board.getGrid(); + return this.gameState; + } +} +//# sourceMappingURL=game.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/game.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/game.js.map @@ -0,0 +1 @@ +{"version":3,"file":"game.js","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/main.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/main.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=main.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/main.d.ts.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/main.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/main.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/main.js @@ -0,0 +1,67 @@ +import { TetrisGame } from './game'; +import { Renderer, HUDRenderer } from './renderer'; +const config = { + boardWidth: 10, + boardHeight: 20, + cellSize: 30, + initialSpeed: 400, + speedMultiplier: 0.9, +}; +const game = new TetrisGame(config); +const renderer = new Renderer('game-canvas', config.cellSize, config.boardWidth, config.boardHeight); +const hudRenderer = new HUDRenderer('hud'); +let lastTime = Date.now(); +let gameRunning = true; +function gameLoop() { + const now = Date.now(); + const deltaTime = now - lastTime; + lastTime = now; + if (gameRunning) { + game.update(); + const gameState = game.getGameState(); + renderer.render(gameState); + hudRenderer.render(gameState, gameState.nextPiece); + } + requestAnimationFrame(gameLoop); +} +// Keyboard controls +document.addEventListener('keydown', (e) => { + const key = e.key.toLowerCase(); + switch (key) { + case 'arrowleft': + case 'a': + e.preventDefault(); + game.moveLeft(); + break; + case 'arrowright': + case 'd': + e.preventDefault(); + game.moveRight(); + break; + case 'arrowdown': + case 's': + e.preventDefault(); + game.moveDown(); + break; + case ' ': + e.preventDefault(); + game.togglePause(); + break; + case 'w': + case 'arrowup': + e.preventDefault(); + game.rotate(); + break; + case 'z': + e.preventDefault(); + game.hardDrop(); + break; + case 'r': + e.preventDefault(); + game.restart(); + break; + } +}); +// Start game loop +gameLoop(); +//# sourceMappingURL=main.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/main.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/main.js.map @@ -0,0 +1 @@ +{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGnD,MAAM,MAAM,GAAW;IACrB,UAAU,EAAE,EAAE;IACd,WAAW,EAAE,EAAE;IACf,QAAQ,EAAE,EAAE;IACZ,YAAY,EAAE,GAAG;IACjB,eAAe,EAAE,GAAG;CACrB,CAAC;AAEF,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;AACpC,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;AACrG,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC;AAE3C,IAAI,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAC1B,IAAI,WAAW,GAAG,IAAI,CAAC;AAEvB,SAAS,QAAQ;IACf,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,SAAS,GAAG,GAAG,GAAG,QAAQ,CAAC;IACjC,QAAQ,GAAG,GAAG,CAAC;IAEf,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACtC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC3B,WAAW,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACrD,CAAC;IAED,qBAAqB,CAAC,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED,oBAAoB;AACpB,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAgB,EAAE,EAAE;IACxD,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;IAEhC,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,WAAW,CAAC;QACjB,KAAK,GAAG;YACN,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,MAAM;QACR,KAAK,YAAY,CAAC;QAClB,KAAK,GAAG;YACN,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,SAAS,EAAE,CAAC;YACjB,MAAM;QACR,KAAK,WAAW,CAAC;QACjB,KAAK,GAAG;YACN,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,MAAM;QACR,KAAK,GAAG;YACN,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,WAAW,EAAE,CAAC;YACnB,MAAM;QACR,KAAK,GAAG,CAAC;QACT,KAAK,SAAS;YACZ,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,MAAM,EAAE,CAAC;YACd,MAAM;QACR,KAAK,GAAG;YACN,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,MAAM;QACR,KAAK,GAAG;YACN,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,MAAM;IACV,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,kBAAkB;AAClB,QAAQ,EAAE,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/piece.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/piece.d.ts @@ -0,0 +1,7 @@ +import { Piece, PieceType, Position } from './types'; +export declare const PIECE_COLORS: Record<PieceType, string>; +export declare function createPiece(type: PieceType, x?: number, y?: number): Piece; +export declare function getRandomPieceType(): PieceType; +export declare function rotatePiece(piece: Piece): Piece; +export declare function getPieceBlocks(piece: Piece): Position[]; +//# sourceMappingURL=piece.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/piece.d.ts.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/piece.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"piece.d.ts","sourceRoot":"","sources":["../src/piece.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAgDrD,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAQlD,CAAC;AAEF,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,GAAE,MAAU,EAAE,CAAC,GAAE,MAAU,GAAG,KAAK,CAQhF;AAED,wBAAgB,kBAAkB,IAAI,SAAS,CAG9C;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAM/C;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,QAAQ,EAAE,CAKvD"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/piece.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/piece.js @@ -0,0 +1,82 @@ +import { PieceType } from './types'; +// Tetromino shapes - defined by relative positions to anchor point (0, 0) +const SHAPES = { + [PieceType.I]: [ + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 3, y: 0 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 0, y: 2 }, { x: 0, y: 3 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 3, y: 0 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 0, y: 2 }, { x: 0, y: 3 }], + ], + [PieceType.O]: [ + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }], + ], + [PieceType.T]: [ + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 1, y: 1 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 0, y: 2 }], + [{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 1, y: 2 }], + ], + [PieceType.S]: [ + [{ x: 1, y: 0 }, { x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 1, y: 2 }], + [{ x: 1, y: 0 }, { x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 1, y: 2 }], + ], + [PieceType.Z]: [ + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 0, y: 2 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 0, y: 2 }], + ], + [PieceType.J]: [ + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: 0, y: 2 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 2, y: 1 }], + [{ x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + ], + [PieceType.L]: [ + [{ x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 0, y: 1 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 1, y: 2 }], + ], +}; +export const PIECE_COLORS = { + [PieceType.I]: '#00FFFF', + [PieceType.O]: '#FFFF00', + [PieceType.T]: '#FF00FF', + [PieceType.S]: '#00FF00', + [PieceType.Z]: '#FF0000', + [PieceType.J]: '#0000FF', + [PieceType.L]: '#FFA500', +}; +export function createPiece(type, x = 3, y = 0) { + return { + type, + blocks: [...SHAPES[type][0]], + x, + y, + rotation: 0, + }; +} +export function getRandomPieceType() { + const types = Object.values(PieceType); + return types[Math.floor(Math.random() * types.length)]; +} +export function rotatePiece(piece) { + const newRotation = (piece.rotation + 1) % 4; + const newPiece = { ...piece }; + newPiece.blocks = SHAPES[piece.type][newRotation]; + newPiece.rotation = newRotation; + return newPiece; +} +export function getPieceBlocks(piece) { + return piece.blocks.map((block) => ({ + x: piece.x + block.x, + y: piece.y + block.y, + })); +} +//# sourceMappingURL=piece.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/piece.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/piece.js.map @@ -0,0 +1 @@ +{"version":3,"file":"piece.js","sourceRoot":"","sources":["../src/piece.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,SAAS,EAAY,MAAM,SAAS,CAAC;AAErD,0EAA0E;AAC1E,MAAM,MAAM,GAAoC;IAC9C,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;QACb,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KACjE;IACD,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;QACb,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KACjE;IACD,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;QACb,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KACjE;IACD,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;QACb,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KACjE;IACD,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;QACb,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KACjE;IACD,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;QACb,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KACjE;IACD,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;QACb,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KACjE;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAA8B;IACrD,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS;IACxB,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS;IACxB,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS;IACxB,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS;IACxB,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS;IACxB,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS;IACxB,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS;CACzB,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,IAAe,EAAE,IAAY,CAAC,EAAE,IAAY,CAAC;IACvE,OAAO;QACL,IAAI;QACJ,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;QACD,CAAC;QACD,QAAQ,EAAE,CAAC;KACZ,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAY;IACtC,MAAM,WAAW,GAAG,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;IAC9B,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC;IAClD,QAAQ,CAAC,QAAQ,GAAG,WAAW,CAAC;IAChC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAY;IACzC,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAClC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;QACpB,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;KACrB,CAAC,CAAC,CAAC;AACN,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/renderer.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/renderer.d.ts @@ -0,0 +1,24 @@ +import { GameState, Piece } from './types'; +export declare class Renderer { + private canvas; + private ctx; + private cellSize; + private boardWidth; + private boardHeight; + constructor(canvasId: string, cellSize: number, boardWidth: number, boardHeight: number); + render(gameState: GameState): void; + private drawGrid; + private drawBoard; + private drawPiece; + private drawCell; + private drawGameOverOverlay; + private drawPauseOverlay; +} +export declare class HUDRenderer { + private container; + constructor(containerId: string); + render(gameState: GameState, nextPiece: Piece | null): void; + private drawNextPiece; + private parseColor; +} +//# sourceMappingURL=renderer.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/renderer.d.ts.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/renderer.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAa,KAAK,EAAE,MAAM,SAAS,CAAC;AAGtD,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,GAAG,CAA2B;IACtC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;gBAEhB,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAevF,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IA2BlC,OAAO,CAAC,QAAQ;IAqBhB,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,QAAQ;IAWhB,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,gBAAgB;CAYzB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAc;gBAEnB,WAAW,EAAE,MAAM;IAO/B,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI;IA0B3D,OAAO,CAAC,aAAa;IAwBrB,OAAO,CAAC,UAAU;CAQnB"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/renderer.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/renderer.js @@ -0,0 +1,161 @@ +import { getPieceBlocks, PIECE_COLORS } from './piece'; +export class Renderer { + constructor(canvasId, cellSize, boardWidth, boardHeight) { + this.canvas = document.getElementById(canvasId); + if (!this.canvas) { + throw new Error(`Canvas with id "${canvasId}" not found`); + } + this.ctx = this.canvas.getContext('2d'); + this.cellSize = cellSize; + this.boardWidth = boardWidth; + this.boardHeight = boardHeight; + this.canvas.width = boardWidth * cellSize; + this.canvas.height = boardHeight * cellSize; + } + render(gameState) { + // Clear canvas + this.ctx.fillStyle = '#000000'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid + this.drawGrid(); + // Draw placed blocks + this.drawBoard(gameState.board); + // Draw current piece + if (gameState.currentPiece) { + this.drawPiece(gameState.currentPiece); + } + // Draw game over overlay + if (gameState.gameOver) { + this.drawGameOverOverlay(); + } + // Draw pause overlay + if (gameState.paused) { + this.drawPauseOverlay(); + } + } + drawGrid() { + this.ctx.strokeStyle = '#222222'; + this.ctx.lineWidth = 1; + // Vertical lines + for (let x = 0; x <= this.boardWidth; x++) { + this.ctx.beginPath(); + this.ctx.moveTo(x * this.cellSize, 0); + this.ctx.lineTo(x * this.cellSize, this.canvas.height); + this.ctx.stroke(); + } + // Horizontal lines + for (let y = 0; y <= this.boardHeight; y++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, y * this.cellSize); + this.ctx.lineTo(this.canvas.width, y * this.cellSize); + this.ctx.stroke(); + } + } + drawBoard(board) { + for (let y = 0; y < board.length; y++) { + for (let x = 0; x < board[y].length; x++) { + if (board[y][x] !== null) { + this.drawCell(x, y, board[y][x]); + } + } + } + } + drawPiece(piece) { + const blocks = getPieceBlocks(piece); + blocks.forEach((block) => { + if (block.y >= 0) { + this.drawCell(block.x, block.y, piece.type); + } + }); + } + drawCell(x, y, pieceType) { + const color = PIECE_COLORS[pieceType]; + this.ctx.fillStyle = color; + this.ctx.fillRect(x * this.cellSize, y * this.cellSize, this.cellSize, this.cellSize); + // Draw border + this.ctx.strokeStyle = '#ffffff'; + this.ctx.lineWidth = 2; + this.ctx.strokeRect(x * this.cellSize, y * this.cellSize, this.cellSize, this.cellSize); + } + drawGameOverOverlay() { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = '#ffffff'; + this.ctx.font = 'bold 40px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('GAME OVER', this.canvas.width / 2, this.canvas.height / 2 - 20); + this.ctx.font = '20px Arial'; + this.ctx.fillText('Press R to restart', this.canvas.width / 2, this.canvas.height / 2 + 30); + } + drawPauseOverlay() { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = '#ffffff'; + this.ctx.font = 'bold 40px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('PAUSED', this.canvas.width / 2, this.canvas.height / 2); + this.ctx.font = '20px Arial'; + this.ctx.fillText('Press SPACE to resume', this.canvas.width / 2, this.canvas.height / 2 + 40); + } +} +export class HUDRenderer { + constructor(containerId) { + this.container = document.getElementById(containerId); + if (!this.container) { + throw new Error(`Container with id "${containerId}" not found`); + } + } + render(gameState, nextPiece) { + this.container.innerHTML = ` + <div class="hud-item"> + <div class="hud-label">Score</div> + <div class="hud-value">${gameState.score}</div> + </div> + <div class="hud-item"> + <div class="hud-label">Level</div> + <div class="hud-value">${gameState.level}</div> + </div> + <div class="hud-item"> + <div class="hud-label">Lines Cleared</div> + <div class="hud-value">${gameState.linesCleared}</div> + </div> + <div class="hud-item"> + <div class="hud-label">Next Piece</div> + <canvas id="next-piece-canvas" width="100" height="100"></canvas> + </div> + `; + // Draw next piece preview + if (nextPiece) { + this.drawNextPiece(nextPiece); + } + } + drawNextPiece(piece) { + const canvas = document.getElementById('next-piece-canvas'); + if (!canvas) + return; + const ctx = canvas.getContext('2d'); + const cellSize = 20; + ctx.fillStyle = '#000000'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + const blocks = getPieceBlocks({ ...piece, x: 2, y: 1 }); + const { r, g, b } = this.parseColor(PIECE_COLORS[piece.type]); + blocks.forEach((block) => { + if (block.x >= 0 && block.x < 5 && block.y >= 0 && block.y < 5) { + ctx.fillStyle = PIECE_COLORS[piece.type]; + ctx.fillRect(block.x * cellSize, block.y * cellSize, cellSize, cellSize); + ctx.strokeStyle = '#ffffff'; + ctx.lineWidth = 1; + ctx.strokeRect(block.x * cellSize, block.y * cellSize, cellSize, cellSize); + } + }); + } + parseColor(color) { + const hex = color.replace('#', ''); + return { + r: parseInt(hex.substr(0, 2), 16), + g: parseInt(hex.substr(2, 2), 16), + b: parseInt(hex.substr(4, 2), 16), + }; + } +} +//# sourceMappingURL=renderer.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/renderer.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/renderer.js.map @@ -0,0 +1 @@ +{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvD,MAAM,OAAO,QAAQ;IAOnB,YAAY,QAAgB,EAAE,QAAgB,EAAE,UAAkB,EAAE,WAAmB;QACrF,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAsB,CAAC;QACrE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,aAAa,CAAC,CAAC;QAC5D,CAAC;QAED,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;QACzC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAE/B,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,UAAU,GAAG,QAAQ,CAAC;QAC1C,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC9C,CAAC;IAED,MAAM,CAAC,SAAoB;QACzB,eAAe;QACf,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAE/D,YAAY;QACZ,IAAI,CAAC,QAAQ,EAAE,CAAC;QAEhB,qBAAqB;QACrB,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAEhC,qBAAqB;QACrB,IAAI,SAAS,CAAC,YAAY,EAAE,CAAC;YAC3B,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACzC,CAAC;QAED,yBAAyB;QACzB,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC;YACvB,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC7B,CAAC;QAED,qBAAqB;QACrB,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC;YACrB,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;IAEO,QAAQ;QACd,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;QAEvB,iBAAiB;QACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1C,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;YACtC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACvD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACpB,CAAC;QAED,mBAAmB;QACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAEO,SAAS,CAAC,KAA6B;QAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACzC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;oBACzB,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAEO,SAAS,CAAC,KAAU;QAC1B,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACrC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YACvB,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,QAAQ,CAAC,CAAS,EAAE,CAAS,EAAE,SAAoB;QACzD,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC;QAC3B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEtF,cAAc;QACd,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1F,CAAC;IAEO,mBAAmB;QACzB,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,oBAAoB,CAAC;QAC1C,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAE/D,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAClC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QAEnF,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,oBAAoB,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IAC9F,CAAC;IAEO,gBAAgB;QACtB,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,oBAAoB,CAAC;QAC1C,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAE/D,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAClC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAE3E,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,uBAAuB,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IACjG,CAAC;CACF;AAED,MAAM,OAAO,WAAW;IAGtB,YAAY,WAAmB;QAC7B,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAE,CAAC;QACvD,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,sBAAsB,WAAW,aAAa,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAED,MAAM,CAAC,SAAoB,EAAE,SAAuB;QAClD,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG;;;iCAGE,SAAS,CAAC,KAAK;;;;iCAIf,SAAS,CAAC,KAAK;;;;iCAIf,SAAS,CAAC,YAAY;;;;;;KAMlD,CAAC;QAEF,0BAA0B;QAC1B,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAEO,aAAa,CAAC,KAAY;QAChC,MAAM,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,mBAAmB,CAAsB,CAAC;QACjF,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,EAAE,CAAC;QAEpB,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC1B,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAEhD,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACxD,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAE9D,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YACvB,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/D,GAAG,CAAC,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACzC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;gBACzE,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC;gBAC5B,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;gBAClB,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC7E,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,UAAU,CAAC,KAAa;QAC9B,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACnC,OAAO;YACL,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;YACjC,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;YACjC,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;SAClC,CAAC;IACJ,CAAC;CACF"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/types.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/types.d.ts @@ -0,0 +1,43 @@ +export declare enum PieceType { + I = "I", + O = "O", + T = "T", + S = "S", + Z = "Z", + J = "J", + L = "L" +} +export interface Position { + x: number; + y: number; +} +export interface Color { + r: number; + g: number; + b: number; +} +export interface Piece { + type: PieceType; + blocks: Position[]; + x: number; + y: number; + rotation: number; +} +export interface GameState { + board: (PieceType | null)[][]; + currentPiece: Piece | null; + nextPiece: Piece | null; + score: number; + level: number; + linesCleared: number; + gameOver: boolean; + paused: boolean; +} +export interface Config { + boardWidth: number; + boardHeight: number; + cellSize: number; + initialSpeed: number; + speedMultiplier: number; +} +//# sourceMappingURL=types.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/types.d.ts.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,oBAAY,SAAS;IACnB,CAAC,MAAM;IACP,CAAC,MAAM;IACP,CAAC,MAAM;IACP,CAAC,MAAM;IACP,CAAC,MAAM;IACP,CAAC,MAAM;IACP,CAAC,MAAM;CACR;AAED,MAAM,WAAW,QAAQ;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,KAAK;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,CAAC,SAAS,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;IAC9B,YAAY,EAAE,KAAK,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,KAAK,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,MAAM;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACzB"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/types.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/types.js @@ -0,0 +1,12 @@ +// Types for Tetris game +export var PieceType; +(function (PieceType) { + PieceType["I"] = "I"; + PieceType["O"] = "O"; + PieceType["T"] = "T"; + PieceType["S"] = "S"; + PieceType["Z"] = "Z"; + PieceType["J"] = "J"; + PieceType["L"] = "L"; +})(PieceType || (PieceType = {})); +//# sourceMappingURL=types.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/types.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAExB,MAAM,CAAN,IAAY,SAQX;AARD,WAAY,SAAS;IACnB,oBAAO,CAAA;IACP,oBAAO,CAAA;IACP,oBAAO,CAAA;IACP,oBAAO,CAAA;IACP,oBAAO,CAAA;IACP,oBAAO,CAAA;IACP,oBAAO,CAAA;AACT,CAAC,EARW,SAAS,KAAT,SAAS,QAQpB"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/game.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/game.d.ts @@ -0,0 +1,70 @@ +type PieceType = 'I' | 'O' | 'T' | 'S' | 'Z' | 'J' | 'L'; +interface Position { + x: number; + y: number; +} +interface Block { + x: number; + y: number; + color: string; +} +interface GamePiece { + type: PieceType; + rotation: number; + position: Position; + blocks: Block[]; + color: string; +} +declare const BOARD_WIDTH = 10; +declare const BOARD_HEIGHT = 20; +declare const CELL_SIZE = 30; +declare const PIECE_COLORS: Record<PieceType, string>; +declare const PIECE_SHAPES: Record<PieceType, number[][]>; +declare class TetrisGame { + private canvas; + private context; + private board; + private currentPiece; + private nextPiece; + private score; + private lines; + private level; + private gameOver; + private gameRunning; + private dropInterval; + private lastDropTime; + private keys; + private lastMoveTime; + private moveDelay; + constructor(canvasId: string); + private initializeBoard; + private setupControls; + private generatePiece; + private getShapeBlocks; + private getRotations; + private rotateMatrixCW; + private deepCopyMatrix; + start(): void; + private spawnNewPiece; + private gameLoop; + private movePiece; + private dropPiece; + private hardDrop; + private rotatePiece; + private isColliding; + private lockPiece; + private checkLineClears; + private clearLines; + private updateScore; + private draw; + private drawBlock; + resetGame(): void; + getGameStats(): { + score: number; + lines: number; + level: number; + gameOver: boolean; + }; + getNextPiece(): GamePiece | null; +} +//# sourceMappingURL=game.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/game.d.ts.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/game.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"game.d.ts","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"AAEA,KAAK,SAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEzD,UAAU,QAAQ;IAChB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,UAAU,KAAK;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,SAAS;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,QAAA,MAAM,WAAW,KAAK,CAAC;AACvB,QAAA,MAAM,YAAY,KAAK,CAAC;AACxB,QAAA,MAAM,SAAS,KAAK,CAAC;AAErB,QAAA,MAAM,YAAY,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAQ3C,CAAC;AAEF,QAAA,MAAM,YAAY,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAoC/C,CAAC;AAEF,cAAM,UAAU;IACd,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,IAAI,CAA0B;IACtC,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,SAAS,CAAe;gBAEpB,QAAQ,EAAE,MAAM;IAW5B,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,aAAa;IAkCrB,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,cAAc;IAkBtB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,cAAc;IAIf,KAAK,IAAI,IAAI;IAOpB,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,QAAQ,CAqCd;IAEF,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,QAAQ;IAWhB,OAAO,CAAC,WAAW;IA2CnB,OAAO,CAAC,WAAW;IAqBnB,OAAO,CAAC,SAAS;IAajB,OAAO,CAAC,eAAe;IAuBvB,OAAO,CAAC,UAAU;IAgBlB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,IAAI;IA0CZ,OAAO,CAAC,SAAS;IAuBV,SAAS,IAAI,IAAI;IAWjB,YAAY,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE;IASlF,YAAY,IAAI,SAAS,GAAG,IAAI;CAGxC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/game.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/game.js @@ -0,0 +1,462 @@ +"use strict"; +// Tetris Game Implementation in TypeScript +const BOARD_WIDTH = 10; +const BOARD_HEIGHT = 20; +const CELL_SIZE = 30; +const PIECE_COLORS = { + I: '#00F0F0', + O: '#F0F000', + T: '#A000F0', + S: '#00F000', + Z: '#F00000', + J: '#0000F0', + L: '#F0A000' +}; +const PIECE_SHAPES = { + I: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0] + ], + O: [ + [1, 1], + [1, 1] + ], + T: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0] + ], + S: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0] + ], + Z: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0] + ], + J: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0] + ], + L: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0] + ] +}; +class TetrisGame { + constructor(canvasId) { + this.board = []; + this.currentPiece = null; + this.nextPiece = null; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.gameRunning = false; + this.dropInterval = 1000; + this.lastDropTime = 0; + this.keys = new Set(); + this.lastMoveTime = 0; + this.moveDelay = 100; + this.gameLoop = () => { + const now = Date.now(); + if (!this.gameRunning || this.gameOver) { + this.draw(); + return; + } + // Handle horizontal movement + if (now - this.lastMoveTime > this.moveDelay) { + if (this.keys.has('arrowleft')) { + this.movePiece(-1); + this.lastMoveTime = now; + } + if (this.keys.has('arrowright')) { + this.movePiece(1); + this.lastMoveTime = now; + } + if (this.keys.has('arrowdown')) { + this.dropPiece(); + this.score += 1; + this.lastMoveTime = now; + } + } + // Handle automatic drop + if (now - this.lastDropTime > this.dropInterval) { + if (!this.dropPiece()) { + this.lockPiece(); + this.checkLineClears(); + this.spawnNewPiece(); + } + this.lastDropTime = now; + } + this.draw(); + requestAnimationFrame(this.gameLoop); + }; + this.canvas = document.getElementById(canvasId); + this.context = this.canvas.getContext('2d'); + this.canvas.width = BOARD_WIDTH * CELL_SIZE; + this.canvas.height = BOARD_HEIGHT * CELL_SIZE; + this.initializeBoard(); + this.setupControls(); + this.nextPiece = this.generatePiece(); + } + initializeBoard() { + this.board = []; + for (let y = 0; y < BOARD_HEIGHT; y++) { + this.board[y] = []; + for (let x = 0; x < BOARD_WIDTH; x++) { + this.board[y][x] = null; + } + } + } + setupControls() { + window.addEventListener('keydown', (e) => { + this.keys.add(e.key.toLowerCase()); + if (e.key === 'ArrowDown') + e.preventDefault(); + if (e.key === 'ArrowLeft') + e.preventDefault(); + if (e.key === 'ArrowRight') + e.preventDefault(); + if (e.key === ' ') + e.preventDefault(); + if (this.gameRunning && !this.gameOver) { + if (e.key.toLowerCase() === 'z') { + this.rotatePiece(-1); + } + if (e.key.toLowerCase() === 'x') { + this.rotatePiece(1); + } + if (e.key === ' ') { + this.hardDrop(); + } + } + if (e.key.toLowerCase() === 'enter') { + if (this.gameOver) { + this.resetGame(); + this.start(); + } + } + }); + window.addEventListener('keyup', (e) => { + this.keys.delete(e.key.toLowerCase()); + }); + } + generatePiece() { + const types = ['I', 'O', 'T', 'S', 'Z', 'J', 'L']; + const type = types[Math.floor(Math.random() * types.length)]; + const color = PIECE_COLORS[type]; + return { + type, + rotation: 0, + position: { x: 3, y: 0 }, + blocks: this.getShapeBlocks(type, 0), + color + }; + } + getShapeBlocks(type, rotation) { + const shape = PIECE_SHAPES[type]; + const rotations = this.getRotations(shape); + const currentShape = rotations[rotation % rotations.length]; + const blocks = []; + const color = PIECE_COLORS[type]; + for (let y = 0; y < currentShape.length; y++) { + for (let x = 0; x < currentShape[y].length; x++) { + if (currentShape[y][x] === 1) { + blocks.push({ x, y, color }); + } + } + } + return blocks; + } + getRotations(shape) { + const rotations = [shape]; + let current = shape; + for (let i = 0; i < 3; i++) { + current = this.rotateMatrixCW(current); + rotations.push(this.deepCopyMatrix(current)); + } + return rotations; + } + rotateMatrixCW(matrix) { + const n = matrix.length; + const rotated = []; + for (let x = 0; x < n; x++) { + rotated[x] = []; + for (let y = n - 1; y >= 0; y--) { + rotated[x][n - 1 - y] = matrix[y][x]; + } + } + return rotated; + } + deepCopyMatrix(matrix) { + return matrix.map(row => [...row]); + } + start() { + this.gameRunning = true; + this.gameOver = false; + this.spawnNewPiece(); + this.gameLoop(); + } + spawnNewPiece() { + this.currentPiece = this.nextPiece; + this.nextPiece = this.generatePiece(); + if (!this.currentPiece) { + this.currentPiece = this.generatePiece(); + } + if (this.isColliding(this.currentPiece.position)) { + this.gameOver = true; + this.gameRunning = false; + } + } + movePiece(direction) { + if (!this.currentPiece) + return; + const newPos = { ...this.currentPiece.position, x: this.currentPiece.position.x + direction }; + if (!this.isColliding(newPos)) { + this.currentPiece.position = newPos; + } + } + dropPiece() { + if (!this.currentPiece) + return false; + const newPos = { ...this.currentPiece.position, y: this.currentPiece.position.y + 1 }; + if (!this.isColliding(newPos)) { + this.currentPiece.position = newPos; + return true; + } + return false; + } + hardDrop() { + if (!this.currentPiece) + return; + while (this.dropPiece()) { + this.score += 2; + } + this.lockPiece(); + this.checkLineClears(); + this.spawnNewPiece(); + } + rotatePiece(direction) { + if (!this.currentPiece) + return; + const newRotation = (this.currentPiece.rotation + direction + 4) % 4; + const newBlocks = this.getShapeBlocks(this.currentPiece.type, newRotation); + const piece = { + ...this.currentPiece, + rotation: newRotation, + blocks: newBlocks + }; + // Try rotation at current position + if (!this.isColliding(this.currentPiece.position, newBlocks)) { + this.currentPiece.rotation = newRotation; + this.currentPiece.blocks = newBlocks; + return; + } + // Wall kick - try adjacent positions + const wallKickOffsets = [ + { x: 1, y: 0 }, + { x: -1, y: 0 }, + { x: 0, y: -1 }, + { x: 2, y: 0 }, + { x: -2, y: 0 } + ]; + for (const offset of wallKickOffsets) { + const testPos = { + x: this.currentPiece.position.x + offset.x, + y: this.currentPiece.position.y + offset.y + }; + if (!this.isColliding(testPos, newBlocks)) { + this.currentPiece.position = testPos; + this.currentPiece.rotation = newRotation; + this.currentPiece.blocks = newBlocks; + return; + } + } + } + isColliding(pos, blocks) { + const piecesBlocks = blocks || (this.currentPiece?.blocks || []); + for (const block of piecesBlocks) { + const worldX = pos.x + block.x; + const worldY = pos.y + block.y; + // Check bounds + if (worldX < 0 || worldX >= BOARD_WIDTH || worldY >= BOARD_HEIGHT) { + return true; + } + // Check collision with placed blocks + if (worldY >= 0 && this.board[worldY][worldX] !== null) { + return true; + } + } + return false; + } + lockPiece() { + if (!this.currentPiece) + return; + for (const block of this.currentPiece.blocks) { + const worldX = this.currentPiece.position.x + block.x; + const worldY = this.currentPiece.position.y + block.y; + if (worldY >= 0 && worldY < BOARD_HEIGHT && worldX >= 0 && worldX < BOARD_WIDTH) { + this.board[worldY][worldX] = this.currentPiece.color; + } + } + } + checkLineClears() { + const linesToClear = []; + for (let y = BOARD_HEIGHT - 1; y >= 0; y--) { + let fullLine = true; + for (let x = 0; x < BOARD_WIDTH; x++) { + if (this.board[y][x] === null) { + fullLine = false; + break; + } + } + if (fullLine) { + linesToClear.push(y); + } + } + if (linesToClear.length > 0) { + this.clearLines(linesToClear); + this.updateScore(linesToClear.length); + } + } + clearLines(lines) { + // Remove cleared lines + for (let i = lines.length - 1; i >= 0; i--) { + this.board.splice(lines[i], 1); + } + // Add new empty lines at the top + for (let i = 0; i < lines.length; i++) { + const newLine = []; + for (let x = 0; x < BOARD_WIDTH; x++) { + newLine.push(null); + } + this.board.unshift(newLine); + } + } + updateScore(clearedLines) { + const points = [0, 100, 300, 500, 800]; + const baseScore = points[Math.min(clearedLines, 4)]; + this.score += baseScore * this.level; + this.lines += clearedLines; + // Increase level every 10 lines + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel > this.level) { + this.level = newLevel; + this.dropInterval = Math.max(100, 1000 - (this.level - 1) * 50); + } + } + draw() { + // Clear canvas + this.context.fillStyle = '#000'; + this.context.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid + this.context.strokeStyle = '#222'; + this.context.lineWidth = 1; + for (let x = 0; x <= BOARD_WIDTH; x++) { + this.context.beginPath(); + this.context.moveTo(x * CELL_SIZE, 0); + this.context.lineTo(x * CELL_SIZE, this.canvas.height); + this.context.stroke(); + } + for (let y = 0; y <= BOARD_HEIGHT; y++) { + this.context.beginPath(); + this.context.moveTo(0, y * CELL_SIZE); + this.context.lineTo(this.canvas.width, y * CELL_SIZE); + this.context.stroke(); + } + // Draw placed blocks + for (let y = 0; y < BOARD_HEIGHT; y++) { + for (let x = 0; x < BOARD_WIDTH; x++) { + if (this.board[y][x] !== null) { + this.drawBlock(x, y, this.board[y][x], true); + } + } + } + // Draw current piece + if (this.currentPiece && this.gameRunning) { + for (const block of this.currentPiece.blocks) { + const x = this.currentPiece.position.x + block.x; + const y = this.currentPiece.position.y + block.y; + if (y >= 0) { + this.drawBlock(x, y, this.currentPiece.color, true); + } + } + } + } + drawBlock(x, y, color, shadow = false) { + const padding = 2; + // Draw main block + this.context.fillStyle = color; + this.context.fillRect(x * CELL_SIZE + padding, y * CELL_SIZE + padding, CELL_SIZE - padding * 2, CELL_SIZE - padding * 2); + // Draw highlight + this.context.strokeStyle = '#fff'; + this.context.lineWidth = 2; + this.context.strokeRect(x * CELL_SIZE + padding, y * CELL_SIZE + padding, CELL_SIZE - padding * 2, CELL_SIZE - padding * 2); + } + resetGame() { + this.initializeBoard(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.dropInterval = 1000; + this.lastDropTime = 0; + this.nextPiece = this.generatePiece(); + } + getGameStats() { + return { + score: this.score, + lines: this.lines, + level: this.level, + gameOver: this.gameOver + }; + } + getNextPiece() { + return this.nextPiece; + } +} +// Initialize game when page loads +window.addEventListener('DOMContentLoaded', () => { + const game = new TetrisGame('gameCanvas'); + // Update UI + const updateUI = () => { + const stats = game.getGameStats(); + const scoreElement = document.getElementById('score'); + const linesElement = document.getElementById('lines'); + const levelElement = document.getElementById('level'); + const gameOverElement = document.getElementById('gameOverMessage'); + if (scoreElement) + scoreElement.textContent = stats.score.toString(); + if (linesElement) + linesElement.textContent = stats.lines.toString(); + if (levelElement) + levelElement.textContent = stats.level.toString(); + if (gameOverElement) { + if (stats.gameOver) { + gameOverElement.style.display = 'block'; + } + else { + gameOverElement.style.display = 'none'; + } + } + requestAnimationFrame(updateUI); + }; + updateUI(); + // Start button + const startButton = document.getElementById('startButton'); + if (startButton) { + startButton.addEventListener('click', () => { + game.resetGame(); + game.start(); + startButton.textContent = 'Restart Game'; + }); + } +}); +//# sourceMappingURL=game.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/game.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/game.js.map @@ -0,0 +1 @@ +{"version":3,"file":"game.js","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/index.html b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/index.html @@ -0,0 +1,72 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Tetris Game</title> + <link rel="stylesheet" href="styles.css" /> + </head> + <body> + <div class="container"> + <div class="game-wrapper"> + <h1>TETRIS</h1> + <canvas id="tetris-canvas"></canvas> + </div> + <div class="sidebar"> + <div class="info-panel"> + <div class="info-item"> + <label>Score</label> + <span id="score">0</span> + </div> + <div class="info-item"> + <label>Lines</label> + <span id="lines">0</span> + </div> + <div class="info-item"> + <label>Level</label> + <span id="level">1</span> + </div> + </div> + <div class="controls"> + <h3>Controls</h3> + <div class="control-list"> + <div class="control"> + <span class="key">← / A</span> + <span>Move Left</span> + </div> + <div class="control"> + <span class="key">→ / D</span> + <span>Move Right</span> + </div> + <div class="control"> + <span class="key">↓ / S</span> + <span>Soft Drop</span> + </div> + <div class="control"> + <span class="key">↑ / W / Space</span> + <span>Rotate</span> + </div> + <div class="control"> + <span class="key">P</span> + <span>Pause/Resume</span> + </div> + <div class="control"> + <span class="key">R</span> + <span>Restart (Game Over)</span> + </div> + </div> + </div> + <div class="instructions"> + <h3>How to Play</h3> + <ul> + <li>Complete horizontal lines to clear blocks and earn points</li> + <li>Clearing 4 lines at once (Tetris) earns bonus points</li> + <li>The game speeds up as you progress to higher levels</li> + <li>Game ends when blocks stack to the top</li> + </ul> + </div> + </div> + </div> + <script src="tetris.js"></script> + </body> +</html> diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/styles.css b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/styles.css @@ -0,0 +1,210 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Arial', sans-serif; + background: linear-gradient(135deg, #1a1a2e 0%, #0f3460 100%); + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; +} + +.container { + display: flex; + gap: 40px; + padding: 20px; + max-width: 1400px; + width: 100%; +} + +.game-wrapper { + display: flex; + flex-direction: column; + align-items: center; + gap: 20px; +} + +h1 { + font-size: 48px; + letter-spacing: 8px; + text-shadow: 0 0 10px rgba(255, 0, 255, 0.5); + animation: glow 2s ease-in-out infinite; +} + +@keyframes glow { + 0%, + 100% { + text-shadow: 0 0 10px rgba(255, 0, 255, 0.5); + } + 50% { + text-shadow: 0 0 20px rgba(255, 0, 255, 0.8), 0 0 30px rgba(0, 255, 255, 0.6); + } +} + +#tetris-canvas { + border: 4px solid #00ff00; + background: #1a1a1a; + box-shadow: 0 0 20px rgba(0, 255, 0, 0.5); + display: block; +} + +.sidebar { + display: flex; + flex-direction: column; + gap: 30px; + min-width: 280px; +} + +.info-panel { + display: flex; + flex-direction: column; + gap: 20px; + background: rgba(15, 52, 96, 0.6); + padding: 20px; + border-radius: 8px; + border: 2px solid #00ff00; + box-shadow: 0 0 15px rgba(0, 255, 0, 0.3); +} + +.info-item { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 20px; + font-weight: bold; +} + +.info-item label { + color: #00ff00; + min-width: 80px; +} + +.info-item span { + color: #ffff00; + font-size: 28px; + text-align: right; +} + +.controls { + background: rgba(15, 52, 96, 0.6); + padding: 20px; + border-radius: 8px; + border: 2px solid #ff00ff; + box-shadow: 0 0 15px rgba(255, 0, 255, 0.3); +} + +.controls h3 { + color: #ff00ff; + margin-bottom: 15px; + font-size: 18px; +} + +.control-list { + display: flex; + flex-direction: column; + gap: 10px; +} + +.control { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 14px; + padding: 8px 0; + border-bottom: 1px solid rgba(255, 255, 255, 0.2); +} + +.control:last-child { + border-bottom: none; +} + +.key { + background: rgba(255, 0, 255, 0.2); + padding: 4px 8px; + border-radius: 4px; + font-family: monospace; + font-weight: bold; + color: #ff00ff; + min-width: 100px; + text-align: center; +} + +.instructions { + background: rgba(15, 52, 96, 0.6); + padding: 20px; + border-radius: 8px; + border: 2px solid #00ffff; + box-shadow: 0 0 15px rgba(0, 255, 255, 0.3); +} + +.instructions h3 { + color: #00ffff; + margin-bottom: 15px; + font-size: 18px; +} + +.instructions ul { + list-style: none; + display: flex; + flex-direction: column; + gap: 8px; + font-size: 13px; + line-height: 1.5; +} + +.instructions li { + padding-left: 20px; + position: relative; +} + +.instructions li:before { + content: '▸'; + position: absolute; + left: 0; + color: #00ffff; +} + +/* Responsive design */ +@media (max-width: 1024px) { + .container { + flex-direction: column; + align-items: center; + } + + .sidebar { + min-width: auto; + width: 100%; + max-width: 300px; + } + + h1 { + font-size: 36px; + } +} + +@media (max-width: 600px) { + .container { + padding: 10px; + gap: 20px; + } + + h1 { + font-size: 28px; + letter-spacing: 4px; + } + + .sidebar { + max-width: 100%; + } + + .control { + flex-direction: column; + align-items: flex-start; + gap: 5px; + } +} diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js @@ -0,0 +1,383 @@ +"use strict"; +// Tetris Game Implementation in TypeScript +const GRID_WIDTH = 10; +const GRID_HEIGHT = 20; +const BLOCK_SIZE = 30; +// Tetromino shapes (4x4 grids with 0 = empty, 1 = block) +const TETROMINOES = { + I: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + O: [ + [0, 0, 0, 0], + [0, 1, 1, 0], + [0, 1, 1, 0], + [0, 0, 0, 0], + ], + T: [ + [0, 0, 0, 0], + [0, 1, 1, 1], + [0, 0, 1, 0], + [0, 0, 0, 0], + ], + S: [ + [0, 0, 0, 0], + [0, 0, 1, 1], + [0, 1, 1, 0], + [0, 0, 0, 0], + ], + Z: [ + [0, 0, 0, 0], + [0, 1, 1, 0], + [0, 0, 1, 1], + [0, 0, 0, 0], + ], + J: [ + [0, 0, 0, 0], + [0, 1, 0, 0], + [0, 1, 1, 1], + [0, 0, 0, 0], + ], + L: [ + [0, 0, 0, 0], + [0, 0, 0, 1], + [0, 1, 1, 1], + [0, 0, 0, 0], + ], +}; +const TETROMINO_COLORS = { + I: '#00f0f0', + O: '#f0f000', + T: '#a000f0', + S: '#00f000', + Z: '#f00000', + J: '#0000f0', + L: '#f0a000', +}; +class TetrisGame { + constructor(canvasId) { + this.grid = []; + this.currentPiece = null; + this.nextPiece = null; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.gamePaused = false; + this.dropCounter = 0; + this.dropInterval = 1000; + this.lastTime = 0; + this.tetrominoes = TETROMINOES; + this.colors = TETROMINO_COLORS; + const canvasElement = document.getElementById(canvasId); + if (!canvasElement || !(canvasElement instanceof HTMLCanvasElement)) { + throw new Error(`Canvas element with id "${canvasId}" not found`); + } + this.canvas = canvasElement; + const context = this.canvas.getContext('2d'); + if (!context) { + throw new Error('Failed to get canvas context'); + } + this.ctx = context; + this.canvas.width = GRID_WIDTH * BLOCK_SIZE; + this.canvas.height = GRID_HEIGHT * BLOCK_SIZE; + this.initializeGrid(); + this.setupEventListeners(); + this.spawnNewPiece(); + this.update(0); + } + initializeGrid() { + this.grid = Array(GRID_HEIGHT) + .fill(null) + .map(() => Array(GRID_WIDTH).fill(0)); + } + setupEventListeners() { + document.addEventListener('keydown', (e) => this.handleKeyPress(e)); + } + handleKeyPress(event) { + if (this.gameOver && event.key.toLowerCase() !== 'r') { + return; + } + switch (event.key.toLowerCase()) { + case 'arrowleft': + case 'a': + event.preventDefault(); + this.movePiece(-1, 0); + break; + case 'arrowright': + case 'd': + event.preventDefault(); + this.movePiece(1, 0); + break; + case 'arrowdown': + case 's': + event.preventDefault(); + this.movePiece(0, 1); + break; + case 'arrowup': + case 'w': + case ' ': + event.preventDefault(); + this.rotatePiece(); + break; + case 'p': + event.preventDefault(); + this.togglePause(); + break; + case 'r': + event.preventDefault(); + if (this.gameOver) { + this.resetGame(); + } + break; + } + } + togglePause() { + this.gamePaused = !this.gamePaused; + } + spawnNewPiece() { + if (this.nextPiece) { + this.currentPiece = this.nextPiece; + } + else { + this.currentPiece = this.getRandomPiece(); + } + this.nextPiece = this.getRandomPiece(); + // Check if spawn position is valid, if not game over + if (!this.isValidPosition(this.currentPiece)) { + this.gameOver = true; + } + } + getRandomPiece() { + const types = Object.keys(this.tetrominoes); + const type = types[Math.floor(Math.random() * types.length)]; + return { + shape: JSON.parse(JSON.stringify(this.tetrominoes[type])), + x: Math.floor(GRID_WIDTH / 2) - 2, + y: 0, + type: type, + }; + } + isValidPosition(piece) { + for (let row = 0; row < piece.shape.length; row++) { + for (let col = 0; col < piece.shape[0].length; col++) { + if (piece.shape[row][col]) { + const x = piece.x + col; + const y = piece.y + row; + if (x < 0 || x >= GRID_WIDTH || y >= GRID_HEIGHT) { + return false; + } + if (y >= 0 && this.grid[y][x]) { + return false; + } + } + } + } + return true; + } + movePiece(dx, dy) { + if (!this.currentPiece || this.gameOver || this.gamePaused) { + return; + } + this.currentPiece.x += dx; + this.currentPiece.y += dy; + if (!this.isValidPosition(this.currentPiece)) { + this.currentPiece.x -= dx; + this.currentPiece.y -= dy; + // If movement was down and failed, piece should lock + if (dy > 0) { + this.lockPiece(); + } + return; + } + } + rotatePiece() { + if (!this.currentPiece || this.gameOver || this.gamePaused) { + return; + } + const originalShape = this.currentPiece.shape; + this.currentPiece.shape = this.rotateShape(this.currentPiece.shape); + if (!this.isValidPosition(this.currentPiece)) { + this.currentPiece.shape = originalShape; + } + } + rotateShape(shape) { + const n = shape.length; + const rotated = Array(n) + .fill(null) + .map(() => Array(n).fill(0)); + for (let row = 0; row < n; row++) { + for (let col = 0; col < n; col++) { + rotated[col][n - 1 - row] = shape[row][col]; + } + } + return rotated; + } + lockPiece() { + if (!this.currentPiece) { + return; + } + // Place piece in grid + for (let row = 0; row < this.currentPiece.shape.length; row++) { + for (let col = 0; col < this.currentPiece.shape[0].length; col++) { + if (this.currentPiece.shape[row][col]) { + const x = this.currentPiece.x + col; + const y = this.currentPiece.y + row; + if (y >= 0 && y < GRID_HEIGHT && x >= 0 && x < GRID_WIDTH) { + this.grid[y][x] = 1; + } + } + } + } + this.clearLines(); + this.spawnNewPiece(); + } + clearLines() { + let linesCleared = 0; + for (let row = GRID_HEIGHT - 1; row >= 0; row--) { + if (this.grid[row].every((cell) => cell)) { + this.grid.splice(row, 1); + this.grid.unshift(Array(GRID_WIDTH).fill(0)); + linesCleared++; + row++; // Re-check this row + } + } + if (linesCleared > 0) { + this.lines += linesCleared; + // Score calculation + const points = [0, 40, 100, 300, 1200]; + this.score += points[linesCleared] * (this.level + 1); + // Increase level every 10 lines + this.level = Math.floor(this.lines / 10) + 1; + // Increase speed + this.dropInterval = Math.max(100, 1000 - this.level * 50); + this.updateUI(); + } + } + drawGrid() { + this.ctx.fillStyle = '#1a1a1a'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid lines + this.ctx.strokeStyle = '#333333'; + this.ctx.lineWidth = 1; + for (let x = 0; x <= GRID_WIDTH; x++) { + this.ctx.beginPath(); + this.ctx.moveTo(x * BLOCK_SIZE, 0); + this.ctx.lineTo(x * BLOCK_SIZE, this.canvas.height); + this.ctx.stroke(); + } + for (let y = 0; y <= GRID_HEIGHT; y++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, y * BLOCK_SIZE); + this.ctx.lineTo(this.canvas.width, y * BLOCK_SIZE); + this.ctx.stroke(); + } + } + drawBlock(x, y, color) { + this.ctx.fillStyle = color; + this.ctx.fillRect(x * BLOCK_SIZE + 2, y * BLOCK_SIZE + 2, BLOCK_SIZE - 4, BLOCK_SIZE - 4); + this.ctx.strokeStyle = '#ffffff'; + this.ctx.lineWidth = 2; + this.ctx.strokeRect(x * BLOCK_SIZE + 2, y * BLOCK_SIZE + 2, BLOCK_SIZE - 4, BLOCK_SIZE - 4); + } + drawPlacedPieces() { + for (let row = 0; row < GRID_HEIGHT; row++) { + for (let col = 0; col < GRID_WIDTH; col++) { + if (this.grid[row][col]) { + this.drawBlock(col, row, '#ffffff'); + } + } + } + } + drawCurrentPiece() { + if (!this.currentPiece) { + return; + } + const color = this.colors[this.currentPiece.type]; + for (let row = 0; row < this.currentPiece.shape.length; row++) { + for (let col = 0; col < this.currentPiece.shape[0].length; col++) { + if (this.currentPiece.shape[row][col]) { + const x = this.currentPiece.x + col; + const y = this.currentPiece.y + row; + if (y >= 0) { + this.drawBlock(x, y, color); + } + } + } + } + } + draw() { + this.drawGrid(); + this.drawPlacedPieces(); + this.drawCurrentPiece(); + if (this.gameOver) { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = '#ff0000'; + this.ctx.font = 'bold 40px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('GAME OVER', this.canvas.width / 2, this.canvas.height / 2 - 30); + this.ctx.font = '20px Arial'; + this.ctx.fillText('Press R to Restart', this.canvas.width / 2, this.canvas.height / 2 + 30); + } + if (this.gamePaused) { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = '#ffff00'; + this.ctx.font = 'bold 40px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('PAUSED', this.canvas.width / 2, this.canvas.height / 2); + this.ctx.font = '16px Arial'; + this.ctx.fillText('Press P to Resume', this.canvas.width / 2, this.canvas.height / 2 + 40); + } + } + updateUI() { + const scoreElement = document.getElementById('score'); + const linesElement = document.getElementById('lines'); + const levelElement = document.getElementById('level'); + if (scoreElement) + scoreElement.textContent = this.score.toString(); + if (linesElement) + linesElement.textContent = this.lines.toString(); + if (levelElement) + levelElement.textContent = this.level.toString(); + } + update(currentTime) { + if (this.lastTime === 0) { + this.lastTime = currentTime; + } + const deltaTime = currentTime - this.lastTime; + this.lastTime = currentTime; + if (!this.gamePaused) { + this.dropCounter += deltaTime; + if (this.dropCounter >= this.dropInterval) { + this.dropCounter = 0; + this.movePiece(0, 1); + } + } + this.draw(); + requestAnimationFrame((time) => this.update(time)); + } + resetGame() { + this.initializeGrid(); + this.currentPiece = null; + this.nextPiece = null; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.gamePaused = false; + this.dropCounter = 0; + this.dropInterval = 1000; + this.lastTime = 0; + this.spawnNewPiece(); + this.updateUI(); + } +} +// Initialize game when DOM is ready +document.addEventListener('DOMContentLoaded', () => { + new TetrisGame('tetris-canvas'); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/tetris.js @@ -0,0 +1,362 @@ +"use strict"; +// Tetris Game in TypeScript +var PieceType; +(function (PieceType) { + PieceType["I"] = "I"; + PieceType["O"] = "O"; + PieceType["T"] = "T"; + PieceType["S"] = "S"; + PieceType["Z"] = "Z"; + PieceType["J"] = "J"; + PieceType["L"] = "L"; +})(PieceType || (PieceType = {})); +const PIECE_SHAPES = { + [PieceType.I]: [ + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 3, y: 0 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 0, y: 2 }, { x: 0, y: 3 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 3, y: 0 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 0, y: 2 }, { x: 0, y: 3 }] + ], + [PieceType.O]: [ + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }] + ], + [PieceType.T]: [ + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 1, y: 1 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 0, y: 2 }], + [{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 1, y: 2 }] + ], + [PieceType.S]: [ + [{ x: 1, y: 0 }, { x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 1, y: 2 }] + ], + [PieceType.Z]: [ + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 0, y: 2 }] + ], + [PieceType.J]: [ + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: 0, y: 2 }], + [{ x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }, { x: 2, y: 0 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 0, y: 2 }] + ], + [PieceType.L]: [ + [{ x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 2, y: 0 }, { x: 0, y: 1 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 1, y: 2 }] + ] +}; +const PIECE_COLORS = { + [PieceType.I]: '#00D9FF', + [PieceType.O]: '#FFD500', + [PieceType.T]: '#A100F2', + [PieceType.S]: '#00D100', + [PieceType.Z]: '#FF0000', + [PieceType.J]: '#0041FF', + [PieceType.L]: '#FF8C00' +}; +class TetrisGame { + constructor() { + this.GRID_WIDTH = 10; + this.GRID_HEIGHT = 20; + this.CELL_SIZE = 30; + this.grid = []; + this.currentPiece = null; + this.nextPiece = null; + this.score = 0; + this.level = 1; + this.linesCleared = 0; + this.gameOver = false; + this.isPaused = false; + this.dropInterval = 1000; + this.dropTimer = null; + // Initialize grid + this.grid = Array(this.GRID_HEIGHT) + .fill(null) + .map(() => Array(this.GRID_WIDTH).fill(null)); + // Get canvas + this.canvas = document.getElementById('tetrisCanvas'); + this.ctx = this.canvas.getContext('2d'); + this.canvas.width = this.GRID_WIDTH * this.CELL_SIZE; + this.canvas.height = this.GRID_HEIGHT * this.CELL_SIZE; + // Get UI elements + this.scoreElement = document.getElementById('score'); + this.levelElement = document.getElementById('level'); + this.linesElement = document.getElementById('lines'); + this.gameOverElement = document.getElementById('gameOverScreen'); + // Setup keyboard controls + this.setupControls(); + // Initialize game + this.nextPiece = this.createRandomPiece(); + this.spawnNewPiece(); + this.draw(); + } + setupControls() { + document.addEventListener('keydown', (e) => { + if (this.gameOver) { + if (e.key === 'Enter') { + this.restart(); + } + return; + } + switch (e.key) { + case 'ArrowLeft': + e.preventDefault(); + this.movePiece(-1, 0); + break; + case 'ArrowRight': + e.preventDefault(); + this.movePiece(1, 0); + break; + case 'ArrowDown': + e.preventDefault(); + this.movePiece(0, 1); + break; + case 'ArrowUp': + case 'z': + case 'Z': + e.preventDefault(); + this.rotatePiece(); + break; + case ' ': + e.preventDefault(); + this.hardDrop(); + break; + case 'p': + case 'P': + e.preventDefault(); + this.togglePause(); + break; + } + }); + } + createRandomPiece() { + const types = Object.values(PieceType); + const type = types[Math.floor(Math.random() * types.length)]; + return { + type, + x: Math.floor(this.GRID_WIDTH / 2) - 1, + y: 0, + rotationIndex: 0 + }; + } + spawnNewPiece() { + this.currentPiece = this.nextPiece; + this.nextPiece = this.createRandomPiece(); + if (this.currentPiece && !this.isValidPosition(this.currentPiece)) { + this.endGame(); + } + } + getBlocksForPiece(piece) { + const shapes = PIECE_SHAPES[piece.type]; + const shape = shapes[piece.rotationIndex % shapes.length]; + return shape.map(block => ({ + x: piece.x + block.x, + y: piece.y + block.y + })); + } + isValidPosition(piece) { + const blocks = this.getBlocksForPiece(piece); + for (const block of blocks) { + if (block.x < 0 || block.x >= this.GRID_WIDTH || + block.y < 0 || block.y >= this.GRID_HEIGHT) { + return false; + } + if (this.grid[block.y][block.x] !== null) { + return false; + } + } + return true; + } + movePiece(dx, dy) { + if (!this.currentPiece || this.isPaused) + return; + const newPiece = { ...this.currentPiece, x: this.currentPiece.x + dx, y: this.currentPiece.y + dy }; + if (this.isValidPosition(newPiece)) { + this.currentPiece = newPiece; + this.draw(); + } + else if (dy > 0) { + // Piece can't move down, lock it in place + this.lockPiece(); + } + } + rotatePiece() { + if (!this.currentPiece || this.isPaused) + return; + const newPiece = { ...this.currentPiece, rotationIndex: this.currentPiece.rotationIndex + 1 }; + if (this.isValidPosition(newPiece)) { + this.currentPiece = newPiece; + this.draw(); + } + } + hardDrop() { + if (!this.currentPiece || this.isPaused) + return; + while (this.isValidPosition({ ...this.currentPiece, y: this.currentPiece.y + 1 })) { + this.currentPiece.y++; + } + this.lockPiece(); + } + lockPiece() { + if (!this.currentPiece) + return; + const blocks = this.getBlocksForPiece(this.currentPiece); + for (const block of blocks) { + if (block.y >= 0) { + this.grid[block.y][block.x] = this.currentPiece.type; + } + } + this.clearLines(); + this.spawnNewPiece(); + this.draw(); + } + clearLines() { + let linesCleared = 0; + for (let y = this.GRID_HEIGHT - 1; y >= 0; y--) { + if (this.grid[y].every(cell => cell !== null)) { + this.grid.splice(y, 1); + this.grid.unshift(Array(this.GRID_WIDTH).fill(null)); + linesCleared++; + } + } + if (linesCleared > 0) { + this.linesCleared += linesCleared; + const points = [40, 100, 300, 1200]; + this.score += points[linesCleared - 1] * this.level; + this.updateLevel(); + this.updateUI(); + } + } + updateLevel() { + const newLevel = Math.floor(this.linesCleared / 10) + 1; + if (newLevel !== this.level) { + this.level = newLevel; + this.dropInterval = Math.max(100, 1000 - (this.level - 1) * 50); + this.resetDropTimer(); + } + } + updateUI() { + this.scoreElement.textContent = `Score: ${this.score}`; + this.levelElement.textContent = `Level: ${this.level}`; + this.linesElement.textContent = `Lines: ${this.linesCleared}`; + } + togglePause() { + if (this.gameOver) + return; + this.isPaused = !this.isPaused; + if (this.isPaused) { + if (this.dropTimer !== null) + clearTimeout(this.dropTimer); + } + else { + this.scheduleNextDrop(); + } + this.draw(); + } + scheduleNextDrop() { + this.dropTimer = window.setTimeout(() => { + if (!this.gameOver && !this.isPaused) { + this.movePiece(0, 1); + this.scheduleNextDrop(); + } + }, this.dropInterval); + } + resetDropTimer() { + if (this.dropTimer !== null) + clearTimeout(this.dropTimer); + this.scheduleNextDrop(); + } + draw() { + // Clear canvas + this.ctx.fillStyle = '#000'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid lines + this.ctx.strokeStyle = '#222'; + this.ctx.lineWidth = 0.5; + for (let i = 0; i <= this.GRID_WIDTH; i++) { + this.ctx.beginPath(); + this.ctx.moveTo(i * this.CELL_SIZE, 0); + this.ctx.lineTo(i * this.CELL_SIZE, this.canvas.height); + this.ctx.stroke(); + } + for (let i = 0; i <= this.GRID_HEIGHT; i++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, i * this.CELL_SIZE); + this.ctx.lineTo(this.canvas.width, i * this.CELL_SIZE); + this.ctx.stroke(); + } + // Draw locked blocks + for (let y = 0; y < this.GRID_HEIGHT; y++) { + for (let x = 0; x < this.GRID_WIDTH; x++) { + if (this.grid[y][x] !== null) { + this.drawBlock(x, y, this.grid[y][x]); + } + } + } + // Draw current piece + if (this.currentPiece && !this.isPaused) { + const blocks = this.getBlocksForPiece(this.currentPiece); + for (const block of blocks) { + this.drawBlock(block.x, block.y, this.currentPiece.type); + } + } + // Draw pause text + if (this.isPaused) { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = '#FFF'; + this.ctx.font = '30px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('PAUSED', this.canvas.width / 2, this.canvas.height / 2 - 15); + this.ctx.font = '16px Arial'; + this.ctx.fillText('Press P to resume', this.canvas.width / 2, this.canvas.height / 2 + 20); + } + } + drawBlock(x, y, type) { + const color = PIECE_COLORS[type]; + this.ctx.fillStyle = color; + this.ctx.fillRect(x * this.CELL_SIZE + 1, y * this.CELL_SIZE + 1, this.CELL_SIZE - 2, this.CELL_SIZE - 2); + // Draw border for depth + this.ctx.strokeStyle = '#FFF'; + this.ctx.lineWidth = 1; + this.ctx.strokeRect(x * this.CELL_SIZE + 1, y * this.CELL_SIZE + 1, this.CELL_SIZE - 2, this.CELL_SIZE - 2); + } + endGame() { + this.gameOver = true; + if (this.dropTimer !== null) + clearTimeout(this.dropTimer); + this.gameOverElement.style.display = 'flex'; + document.getElementById('finalScore').textContent = `${this.score}`; + this.draw(); + } + restart() { + // Reset game state + this.grid = Array(this.GRID_HEIGHT) + .fill(null) + .map(() => Array(this.GRID_WIDTH).fill(null)); + this.score = 0; + this.level = 1; + this.linesCleared = 0; + this.gameOver = false; + this.isPaused = false; + this.dropInterval = 1000; + // Reset UI + this.gameOverElement.style.display = 'none'; + this.updateUI(); + // Start new game + this.nextPiece = this.createRandomPiece(); + this.spawnNewPiece(); + this.resetDropTimer(); + this.draw(); + } + start() { + this.resetDropTimer(); + } +} +// Initialize game when page loads +window.addEventListener('DOMContentLoaded', () => { + const game = new TetrisGame(); + game.start(); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts @@ -0,0 +1,32 @@ +import { GameState, Piece } from './types'; +export declare class TetrisGame { + board: (string | null)[][]; + currentPiece: Piece; + nextPiece: Piece; + score: number; + level: number; + lines: number; + gameState: GameState; + dropSpeed: number; + private lastDropTime; + constructor(); + private initializeBoard; + moveLeft(): void; + moveRight(): void; + moveDown(): void; + rotatePiece(): void; + hardDrop(): void; + private isColliding; + private lockPiece; + private clearLines; + update(): void; + togglePause(): void; + reset(): void; + getBoard(): (string | null)[][]; + getCurrentPiece(): Piece; + getNextPiece(): Piece; + getScore(): number; + getLevel(): number; + getLines(): number; + getGameState(): GameState; +} diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js @@ -0,0 +1,286 @@ +import { BOARD_WIDTH, BOARD_HEIGHT } from './types'; +import { createRandomPiece, getNextRotation } from './pieces'; +export class TetrisGame { + constructor() { + this.board = []; + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameState = 'playing'; + this.dropSpeed = 1000; // milliseconds + this.lastDropTime = 0; + this.initializeBoard(); + this.currentPiece = createRandomPiece(); + this.nextPiece = createRandomPiece(); + } + initializeBoard() { + this.board = Array(BOARD_HEIGHT) + .fill(null) + .map(() => Array(BOARD_WIDTH).fill(null)); + } + moveLeft() { + if (this.gameState !== 'playing') + return; + const newPos = { ...this.currentPiece.position, x: this.currentPiece.position.x - 1 }; + if (!this.isColliding(this.currentPiece.shape, newPos)) { + this.currentPiece.position = newPos; + } + } + moveRight() { + if (this.gameState !== 'playing') + return; + const newPos = { ...this.currentPiece.position, x: this.currentPiece.position.x + 1 }; + if (!this.isColliding(this.currentPiece.shape, newPos)) { + this.currentPiece.position = newPos; + } + } + moveDown() { + if (this.gameState !== 'playing') + return; + const newPos = { ...this.currentPiece.position, y: this.currentPiece.position.y + 1 }; + if (!this.isColliding(this.currentPiece.shape, newPos)) { + this.currentPiece.position = newPos; + return; + } + // Can't move down anymore, lock the piece + this.lockPiece(); + } + rotatePiece() { + if (this.gameState !== 'playing') + return; + const newShape = getNextRotation(this.currentPiece); + // Try rotating at current position + if (!this.isColliding(newShape, this.currentPiece.position)) { + this.currentPiece.shape = newShape; + const def = pieceDefinitions.find(d => d.color === this.currentPiece.color); + if (def) { + this.currentPiece.rotationIndex = (this.currentPiece.rotationIndex + 1) % def.rotations.length; + } + return; + } + // Wall kick: try positions to the right + for (let i = 1; i <= 2; i++) { + const kickPos = { ...this.currentPiece.position, x: this.currentPiece.position.x + i }; + if (!this.isColliding(newShape, kickPos)) { + this.currentPiece.shape = newShape; + this.currentPiece.position = kickPos; + const def = pieceDefinitions.find(d => d.color === this.currentPiece.color); + if (def) { + this.currentPiece.rotationIndex = (this.currentPiece.rotationIndex + 1) % def.rotations.length; + } + return; + } + } + // Wall kick: try positions to the left + for (let i = 1; i <= 2; i++) { + const kickPos = { ...this.currentPiece.position, x: this.currentPiece.position.x - i }; + if (!this.isColliding(newShape, kickPos)) { + this.currentPiece.shape = newShape; + this.currentPiece.position = kickPos; + const def = pieceDefinitions.find(d => d.color === this.currentPiece.color); + if (def) { + this.currentPiece.rotationIndex = (this.currentPiece.rotationIndex + 1) % def.rotations.length; + } + return; + } + } + } + hardDrop() { + if (this.gameState !== 'playing') + return; + while (true) { + const newPos = { ...this.currentPiece.position, y: this.currentPiece.position.y + 1 }; + if (this.isColliding(this.currentPiece.shape, newPos)) { + break; + } + this.currentPiece.position = newPos; + } + this.lockPiece(); + } + isColliding(shape, pos) { + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 0) + continue; + const boardX = pos.x + col; + const boardY = pos.y + row; + if (boardX < 0 || boardX >= BOARD_WIDTH || boardY >= BOARD_HEIGHT) { + return true; + } + if (boardY >= 0 && this.board[boardY] && this.board[boardY][boardX] !== null) { + return true; + } + } + } + return false; + } + lockPiece() { + const shape = this.currentPiece.shape; + const pos = this.currentPiece.position; + const color = this.currentPiece.color; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 0) + continue; + const boardX = pos.x + col; + const boardY = pos.y + row; + if (boardY >= 0) { + this.board[boardY][boardX] = color; + } + } + } + this.clearLines(); + this.currentPiece = this.nextPiece; + this.nextPiece = createRandomPiece(); + // Check if game is over + if (this.isColliding(this.currentPiece.shape, this.currentPiece.position)) { + this.gameState = 'gameOver'; + } + } + clearLines() { + let linesCleared = 0; + for (let row = BOARD_HEIGHT - 1; row >= 0; row--) { + if (this.board[row].every(cell => cell !== null)) { + this.board.splice(row, 1); + this.board.unshift(Array(BOARD_WIDTH).fill(null)); + linesCleared++; + row++; // Check this row again + } + } + if (linesCleared > 0) { + this.lines += linesCleared; + // Scoring + const points = [0, 40, 100, 300, 1200]; + this.score += points[linesCleared] * this.level; + // Level up every 10 lines + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel > this.level) { + this.level = newLevel; + this.dropSpeed = Math.max(100, 1000 - (this.level - 1) * 50); + } + } + } + update() { + if (this.gameState !== 'playing') + return; + const now = Date.now(); + if (now - this.lastDropTime >= this.dropSpeed) { + this.moveDown(); + this.lastDropTime = now; + } + } + togglePause() { + if (this.gameState === 'playing') { + this.gameState = 'paused'; + } + else if (this.gameState === 'paused') { + this.gameState = 'playing'; + } + } + reset() { + this.initializeBoard(); + this.currentPiece = createRandomPiece(); + this.nextPiece = createRandomPiece(); + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameState = 'playing'; + this.dropSpeed = 1000; + this.lastDropTime = Date.now(); + } + getBoard() { + return this.board; + } + getCurrentPiece() { + return this.currentPiece; + } + getNextPiece() { + return this.nextPiece; + } + getScore() { + return this.score; + } + getLevel() { + return this.level; + } + getLines() { + return this.lines; + } + getGameState() { + return this.gameState; + } +} +// Add piece definitions to avoid circular import +const pieceDefinitions = [ + { + name: 'I', + color: '#00F0F0', + rotations: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + ], + }, + { + name: 'O', + color: '#F0F000', + rotations: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + }, + { + name: 'T', + color: '#A000F0', + rotations: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + }, + { + name: 'S', + color: '#00F000', + rotations: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + ], + }, + { + name: 'Z', + color: '#F00000', + rotations: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + ], + }, + { + name: 'J', + color: '#0000F0', + rotations: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + }, + { + name: 'L', + color: '#F0A000', + rotations: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], + }, +]; +//# sourceMappingURL=game.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js.map @@ -0,0 +1 @@ +{"version":3,"file":"game.js","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/input.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/input.d.ts @@ -0,0 +1,10 @@ +import { TetrisGame } from './game'; +export declare class InputHandler { + private game; + private keys; + constructor(game: TetrisGame); + private setupListeners; + private handleKeyDown; + private handleKeyUp; + processMovement(): void; +} diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/input.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/input.js @@ -0,0 +1,66 @@ +export class InputHandler { + constructor(game) { + this.keys = new Set(); + this.game = game; + this.setupListeners(); + } + setupListeners() { + window.addEventListener('keydown', (e) => this.handleKeyDown(e)); + window.addEventListener('keyup', (e) => this.handleKeyUp(e)); + } + handleKeyDown(event) { + const key = event.key.toLowerCase(); + if (this.keys.has(key)) + return; // Ignore repeat events + this.keys.add(key); + switch (key) { + case 'arrowleft': + case 'a': + event.preventDefault(); + this.game.moveLeft(); + break; + case 'arrowright': + case 'd': + event.preventDefault(); + this.game.moveRight(); + break; + case 'arrowdown': + case 's': + event.preventDefault(); + this.game.moveDown(); + break; + case ' ': + event.preventDefault(); + this.game.hardDrop(); + break; + case 'w': + case 'arrowup': + case 'z': + event.preventDefault(); + this.game.rotatePiece(); + break; + case 'p': + event.preventDefault(); + this.game.togglePause(); + break; + case 'r': + event.preventDefault(); + this.game.reset(); + break; + } + } + handleKeyUp(event) { + const key = event.key.toLowerCase(); + this.keys.delete(key); + } + processMovement() { + // For continuous movement with held keys + if (this.keys.has('arrowleft') || this.keys.has('a')) { + // Movement is already handled in moveLeft on keydown + } + if (this.keys.has('arrowright') || this.keys.has('d')) { + // Movement is already handled in moveRight on keydown + } + } +} +//# sourceMappingURL=input.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/input.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/input.js.map @@ -0,0 +1 @@ +{"version":3,"file":"input.js","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,YAAY;IAIvB,YAAY,IAAgB;QAFpB,SAAI,GAAgB,IAAI,GAAG,EAAE,CAAC;QAGpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAEO,cAAc;QACpB,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QACjE,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC;IAEO,aAAa,CAAC,KAAoB;QACxC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;QAEpC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,uBAAuB;QAEvD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEnB,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,WAAW,CAAC;YACjB,KAAK,GAAG;gBACN,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACrB,MAAM;YACR,KAAK,YAAY,CAAC;YAClB,KAAK,GAAG;gBACN,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACtB,MAAM;YACR,KAAK,WAAW,CAAC;YACjB,KAAK,GAAG;gBACN,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACrB,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACrB,MAAM;YACR,KAAK,GAAG,CAAC;YACT,KAAK,SAAS,CAAC;YACf,KAAK,GAAG;gBACN,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACxB,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACxB,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAClB,MAAM;QACV,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,KAAoB;QACtC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAED,eAAe;QACb,yCAAyC;QACzC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACrD,qDAAqD;QACvD,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACtD,sDAAsD;QACxD,CAAC;IACH,CAAC;CACF"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js @@ -0,0 +1,41 @@ +import { TetrisGame } from './game'; +import { Renderer } from './renderer'; +import { InputHandler } from './input'; +const gameContainer = document.getElementById('game-container'); +if (!gameContainer) + throw new Error('Game container not found'); +const gameCanvas = document.getElementById('game-canvas'); +if (!gameCanvas) + throw new Error('Game canvas not found'); +const nextPieceCanvas = document.getElementById('next-piece-canvas'); +if (!nextPieceCanvas) + throw new Error('Next piece canvas not found'); +const scoreElement = document.getElementById('score'); +const levelElement = document.getElementById('level'); +const linesElement = document.getElementById('lines'); +if (!scoreElement || !levelElement || !linesElement) { + throw new Error('UI elements not found'); +} +const game = new TetrisGame(); +const renderer = new Renderer(gameCanvas, game); +const input = new InputHandler(game); +let lastUpdateTime = Date.now(); +function updateUI() { + scoreElement.textContent = String(game.getScore()); + levelElement.textContent = String(game.getLevel()); + linesElement.textContent = String(game.getLines()); +} +function gameLoop() { + const now = Date.now(); + const deltaTime = now - lastUpdateTime; + lastUpdateTime = now; + game.update(); + renderer.render(); + renderer.renderNext(nextPieceCanvas); + updateUI(); + requestAnimationFrame(gameLoop); +} +// Start the game loop +updateUI(); +gameLoop(); +//# sourceMappingURL=main.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js.map @@ -0,0 +1 @@ +{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,aAAa,GAAG,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;AAChE,IAAI,CAAC,aAAa;IAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;AAEhE,MAAM,UAAU,GAAG,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAsB,CAAC;AAC/E,IAAI,CAAC,UAAU;IAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;AAE1D,MAAM,eAAe,GAAG,QAAQ,CAAC,cAAc,CAAC,mBAAmB,CAAsB,CAAC;AAC1F,IAAI,CAAC,eAAe;IAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;AAErE,MAAM,YAAY,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAgB,CAAC;AACrE,MAAM,YAAY,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAgB,CAAC;AACrE,MAAM,YAAY,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAgB,CAAC;AAErE,IAAI,CAAC,YAAY,IAAI,CAAC,YAAY,IAAI,CAAC,YAAY,EAAE,CAAC;IACpD,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,IAAI,GAAG,IAAI,UAAU,EAAE,CAAC;AAC9B,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AAChD,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;AAErC,IAAI,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAEhC,SAAS,QAAQ;IACf,YAAY,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IACnD,YAAY,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IACnD,YAAY,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,QAAQ;IACf,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,SAAS,GAAG,GAAG,GAAG,cAAc,CAAC;IACvC,cAAc,GAAG,GAAG,CAAC;IAErB,IAAI,CAAC,MAAM,EAAE,CAAC;IACd,QAAQ,CAAC,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;IACrC,QAAQ,EAAE,CAAC;IAEX,qBAAqB,CAAC,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED,sBAAsB;AACtB,QAAQ,EAAE,CAAC;AACX,QAAQ,EAAE,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.d.ts @@ -0,0 +1,4 @@ +import { Piece } from './types'; +export declare function createRandomPiece(): Piece; +export declare function getNextRotation(piece: Piece): number[][]; +export declare function getPieceIndex(color: string): number; diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.js @@ -0,0 +1,93 @@ +// Tetris piece definitions with all rotations +const pieceDefinitions = [ + { + name: 'I', + color: '#00F0F0', // Cyan + rotations: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + ], + }, + { + name: 'O', + color: '#F0F000', // Yellow + rotations: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + }, + { + name: 'T', + color: '#A000F0', // Purple + rotations: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + }, + { + name: 'S', + color: '#00F000', // Green + rotations: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + ], + }, + { + name: 'Z', + color: '#F00000', // Red + rotations: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + ], + }, + { + name: 'J', + color: '#0000F0', // Blue + rotations: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + }, + { + name: 'L', + color: '#F0A000', // Orange + rotations: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], + }, +]; +export function createRandomPiece() { + const def = pieceDefinitions[Math.floor(Math.random() * pieceDefinitions.length)]; + return { + shape: def.rotations[0], + color: def.color, + position: { x: 3, y: 0 }, + rotationIndex: 0, + }; +} +export function getNextRotation(piece) { + const def = pieceDefinitions.find((d) => d.color === piece.color); + if (!def) + return piece.shape; + const nextIndex = (piece.rotationIndex + 1) % def.rotations.length; + return def.rotations[nextIndex]; +} +export function getPieceIndex(color) { + return pieceDefinitions.findIndex((d) => d.color === color); +} +//# sourceMappingURL=pieces.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.js.map @@ -0,0 +1 @@ +{"version":3,"file":"pieces.js","sourceRoot":"","sources":["../src/pieces.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.d.ts @@ -0,0 +1,13 @@ +import { TetrisGame } from './game'; +export declare class Renderer { + private canvas; + private ctx; + private game; + constructor(canvas: HTMLCanvasElement, game: TetrisGame); + render(): void; + private drawBlock; + private drawPiece; + private drawGameOverScreen; + private drawPausedScreen; + renderNext(canvas: HTMLCanvasElement): void; +} diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.js @@ -0,0 +1,123 @@ +import { BOARD_WIDTH, BOARD_HEIGHT, BLOCK_SIZE } from './types'; +export class Renderer { + constructor(canvas, game) { + this.canvas = canvas; + const ctx = canvas.getContext('2d'); + if (!ctx) + throw new Error('Could not get canvas context'); + this.ctx = ctx; + this.game = game; + this.canvas.width = BOARD_WIDTH * BLOCK_SIZE; + this.canvas.height = BOARD_HEIGHT * BLOCK_SIZE; + } + render() { + this.ctx.fillStyle = '#000'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid + this.ctx.strokeStyle = '#222'; + this.ctx.lineWidth = 0.5; + for (let i = 0; i <= BOARD_WIDTH; i++) { + this.ctx.beginPath(); + this.ctx.moveTo(i * BLOCK_SIZE, 0); + this.ctx.lineTo(i * BLOCK_SIZE, this.canvas.height); + this.ctx.stroke(); + } + for (let i = 0; i <= BOARD_HEIGHT; i++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, i * BLOCK_SIZE); + this.ctx.lineTo(this.canvas.width, i * BLOCK_SIZE); + this.ctx.stroke(); + } + // Draw board + const board = this.game.getBoard(); + for (let y = 0; y < BOARD_HEIGHT; y++) { + for (let x = 0; x < BOARD_WIDTH; x++) { + const color = board[y][x]; + if (color) { + this.drawBlock(x, y, color); + } + } + } + // Draw current piece + const piece = this.game.getCurrentPiece(); + this.drawPiece(piece); + // Draw game state overlay + const gameState = this.game.getGameState(); + if (gameState === 'gameOver') { + this.drawGameOverScreen(); + } + else if (gameState === 'paused') { + this.drawPausedScreen(); + } + } + drawBlock(x, y, color) { + const px = x * BLOCK_SIZE; + const py = y * BLOCK_SIZE; + this.ctx.fillStyle = color; + this.ctx.fillRect(px + 1, py + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + // Draw highlight + this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)'; + this.ctx.lineWidth = 1; + this.ctx.strokeRect(px + 1, py + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + } + drawPiece(piece) { + const shape = piece.shape; + const pos = piece.position; + const color = piece.color; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 0) + continue; + const x = pos.x + col; + const y = pos.y + row; + if (y >= 0) { + this.drawBlock(x, y, color); + } + } + } + } + drawGameOverScreen() { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = '#FFF'; + this.ctx.font = 'bold 40px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('GAME OVER', this.canvas.width / 2, this.canvas.height / 2 - 40); + this.ctx.font = '20px Arial'; + this.ctx.fillText(`Score: ${this.game.getScore()}`, this.canvas.width / 2, this.canvas.height / 2 + 20); + this.ctx.fillText('Press R to restart', this.canvas.width / 2, this.canvas.height / 2 + 60); + } + drawPausedScreen() { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = '#FFF'; + this.ctx.font = 'bold 40px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('PAUSED', this.canvas.width / 2, this.canvas.height / 2); + this.ctx.font = '16px Arial'; + this.ctx.fillText('Press P to resume', this.canvas.width / 2, this.canvas.height / 2 + 50); + } + renderNext(canvas) { + const ctx = canvas.getContext('2d'); + if (!ctx) + return; + const size = 100; + canvas.width = size; + canvas.height = size; + ctx.fillStyle = '#000'; + ctx.fillRect(0, 0, size, size); + const piece = this.game.getNextPiece(); + const blockSize = 20; + const offsetX = (size - piece.shape[0].length * blockSize) / 2; + const offsetY = (size - piece.shape.length * blockSize) / 2; + ctx.fillStyle = piece.color; + for (let row = 0; row < piece.shape.length; row++) { + for (let col = 0; col < piece.shape[row].length; col++) { + if (piece.shape[row][col] === 1) { + ctx.fillRect(offsetX + col * blockSize + 1, offsetY + row * blockSize + 1, blockSize - 2, blockSize - 2); + } + } + } + } +} +//# sourceMappingURL=renderer.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.js.map @@ -0,0 +1 @@ +{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/types.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/types.d.ts @@ -0,0 +1,19 @@ +export interface Position { + x: number; + y: number; +} +export interface Block { + x: number; + y: number; + color: string; +} +export interface Piece { + shape: number[][]; + color: string; + position: Position; + rotationIndex: number; +} +export declare const BOARD_WIDTH = 10; +export declare const BOARD_HEIGHT = 20; +export declare const BLOCK_SIZE = 30; +export type GameState = 'playing' | 'gameOver' | 'paused'; diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/types.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/types.js @@ -0,0 +1,4 @@ +export const BOARD_WIDTH = 10; +export const BOARD_HEIGHT = 20; +export const BLOCK_SIZE = 30; +//# sourceMappingURL=types.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/types.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAC9B,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAC/B,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts @@ -0,0 +1,60 @@ +declare const BOARD_WIDTH = 10; +declare const BOARD_HEIGHT = 20; +declare const BLOCK_SIZE = 30; +declare const INITIAL_SPEED = 800; +declare const MIN_SPEED = 100; +declare const SPEED_INCREASE = 0.98; +declare const TETROMINOS: { + T: number[][]; + S: number[][]; + Z: number[][]; + J: number[][]; + L: number[][]; + I: number[][]; + O: number[][]; +}; +declare const COLORS: { + [key in keyof typeof TETROMINOS]: string; +}; +type TetrominoKey = keyof typeof TETROMINOS; +interface Piece { + shape: number[][]; + x: number; + y: number; + type: TetrominoKey; +} +declare class TetrisGame { + private canvas; + private ctx; + private board; + private currentPiece; + private nextPiece; + private score; + private level; + private lines; + private gameOver; + private gamePaused; + private dropSpeed; + private lastDropTime; + private gameLoopId; + constructor(canvasId: string); + private initializeBoard; + private generatePiece; + private spawnNewPiece; + private setupControls; + private moveLeft; + private moveRight; + private moveDown; + private rotate; + private rotateMatrix; + private isColliding; + private placePiece; + private clearLines; + private startGameLoop; + private render; + private drawBlock; + private togglePause; + private endGame; + private restart; + private updateUI; +} diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js @@ -0,0 +1,412 @@ +"use strict"; +// Tetris Game in TypeScript +// Constants +const BOARD_WIDTH = 10; +const BOARD_HEIGHT = 20; +const BLOCK_SIZE = 30; +const INITIAL_SPEED = 800; // milliseconds +const MIN_SPEED = 100; +const SPEED_INCREASE = 0.98; +// Tetromino shapes (T, S, Z, J, L, I, O) +const TETROMINOS = { + T: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + S: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + Z: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + J: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + L: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], + I: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + O: [ + [1, 1], + [1, 1], + ], +}; +// Colors for each tetromino +const COLORS = { + T: '#9C27B0', + S: '#4CAF50', + Z: '#F44336', + J: '#2196F3', + L: '#FF9800', + I: '#00BCD4', + O: '#FFEB3B', +}; +class TetrisGame { + constructor(canvasId) { + this.board = []; + this.currentPiece = null; + this.nextPiece = null; + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameOver = false; + this.gamePaused = false; + this.dropSpeed = INITIAL_SPEED; + this.lastDropTime = 0; + this.gameLoopId = 0; + this.canvas = document.getElementById(canvasId); + const ctx = this.canvas.getContext('2d'); + if (!ctx) + throw new Error('Failed to get canvas context'); + this.ctx = ctx; + this.canvas.width = BOARD_WIDTH * BLOCK_SIZE; + this.canvas.height = BOARD_HEIGHT * BLOCK_SIZE; + this.initializeBoard(); + this.setupControls(); + this.nextPiece = this.generatePiece(); + this.spawnNewPiece(); + this.startGameLoop(); + this.updateUI(); + } + initializeBoard() { + this.board = Array.from({ length: BOARD_HEIGHT }, () => Array(BOARD_WIDTH).fill(0)); + } + generatePiece() { + const keys = Object.keys(TETROMINOS); + const type = keys[Math.floor(Math.random() * keys.length)]; + const shape = JSON.parse(JSON.stringify(TETROMINOS[type])); + return { + shape, + x: Math.floor(BOARD_WIDTH / 2) - Math.floor(shape[0].length / 2), + y: 0, + type, + }; + } + spawnNewPiece() { + this.currentPiece = this.nextPiece; + this.nextPiece = this.generatePiece(); + if (this.currentPiece && this.isColliding(this.currentPiece)) { + this.endGame(); + } + } + setupControls() { + window.addEventListener('keydown', (e) => { + if (this.gameOver) + return; + switch (e.key) { + case 'ArrowLeft': + e.preventDefault(); + this.moveLeft(); + break; + case 'ArrowRight': + e.preventDefault(); + this.moveRight(); + break; + case 'ArrowDown': + e.preventDefault(); + this.moveDown(); + break; + case 'ArrowUp': + case ' ': + e.preventDefault(); + this.rotate(); + break; + case 'p': + case 'P': + this.togglePause(); + break; + case 'r': + case 'R': + if (this.gameOver) { + this.restart(); + } + break; + } + }); + } + moveLeft() { + if (!this.currentPiece) + return; + this.currentPiece.x--; + if (this.isColliding(this.currentPiece)) { + this.currentPiece.x++; + } + } + moveRight() { + if (!this.currentPiece) + return; + this.currentPiece.x++; + if (this.isColliding(this.currentPiece)) { + this.currentPiece.x--; + } + } + moveDown() { + if (!this.currentPiece) + return; + this.currentPiece.y++; + if (this.isColliding(this.currentPiece)) { + this.currentPiece.y--; + this.placePiece(); + } + } + rotate() { + if (!this.currentPiece) + return; + const originalShape = this.currentPiece.shape; + this.currentPiece.shape = this.rotateMatrix(this.currentPiece.shape); + if (this.isColliding(this.currentPiece)) { + // Try wall kick + const kickOffsets = [ + [1, 0], + [-1, 0], + [2, 0], + [-2, 0], + ]; + let rotated = false; + for (const [dx, dy] of kickOffsets) { + this.currentPiece.x += dx; + this.currentPiece.y += dy; + if (!this.isColliding(this.currentPiece)) { + rotated = true; + break; + } + this.currentPiece.x -= dx; + this.currentPiece.y -= dy; + } + if (!rotated) { + this.currentPiece.shape = originalShape; + } + } + } + rotateMatrix(matrix) { + const n = matrix.length; + const rotated = Array.from({ length: n }, () => Array(n).fill(0)); + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + rotated[j][n - 1 - i] = matrix[i][j]; + } + } + return rotated; + } + isColliding(piece) { + for (let row = 0; row < piece.shape.length; row++) { + for (let col = 0; col < piece.shape[row].length; col++) { + if (piece.shape[row][col] === 0) + continue; + const x = piece.x + col; + const y = piece.y + row; + if (x < 0 || x >= BOARD_WIDTH || y >= BOARD_HEIGHT) { + return true; + } + if (y >= 0 && this.board[y][x] !== 0) { + return true; + } + } + } + return false; + } + placePiece() { + if (!this.currentPiece) + return; + const { shape, x, y, type } = this.currentPiece; + const colorValue = COLORS[type].charCodeAt(0); // Simple color encoding + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] === 0) + continue; + const boardY = y + row; + const boardX = x + col; + if (boardY >= 0 && boardY < BOARD_HEIGHT && boardX >= 0 && boardX < BOARD_WIDTH) { + this.board[boardY][boardX] = type.charCodeAt(0); + } + } + } + this.clearLines(); + this.spawnNewPiece(); + } + clearLines() { + let linesCleared = 0; + for (let row = BOARD_HEIGHT - 1; row >= 0; row--) { + if (this.board[row].every((cell) => cell !== 0)) { + this.board.splice(row, 1); + this.board.unshift(Array(BOARD_WIDTH).fill(0)); + linesCleared++; + row++; // Recheck this row + } + } + if (linesCleared > 0) { + this.lines += linesCleared; + const points = [40, 100, 300, 1200][linesCleared - 1] || 0; + this.score += points * this.level; + // Update level every 10 lines + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel > this.level) { + this.level = newLevel; + this.dropSpeed = Math.max(MIN_SPEED, this.dropSpeed * SPEED_INCREASE); + } + this.updateUI(); + } + } + startGameLoop() { + this.lastDropTime = Date.now(); + const gameLoopFn = () => { + this.gameLoopId = requestAnimationFrame(gameLoopFn); + if (this.gamePaused || this.gameOver) { + this.render(); + return; + } + const now = Date.now(); + if (now - this.lastDropTime >= this.dropSpeed) { + this.moveDown(); + this.lastDropTime = now; + } + this.render(); + }; + this.gameLoopId = requestAnimationFrame(gameLoopFn); + } + render() { + // Clear canvas + this.ctx.fillStyle = '#000'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid + this.ctx.strokeStyle = '#222'; + this.ctx.lineWidth = 1; + for (let i = 0; i <= BOARD_WIDTH; i++) { + this.ctx.beginPath(); + this.ctx.moveTo(i * BLOCK_SIZE, 0); + this.ctx.lineTo(i * BLOCK_SIZE, this.canvas.height); + this.ctx.stroke(); + } + for (let i = 0; i <= BOARD_HEIGHT; i++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, i * BLOCK_SIZE); + this.ctx.lineTo(this.canvas.width, i * BLOCK_SIZE); + this.ctx.stroke(); + } + // Draw placed blocks + for (let row = 0; row < BOARD_HEIGHT; row++) { + for (let col = 0; col < BOARD_WIDTH; col++) { + if (this.board[row][col] !== 0) { + const cellType = String.fromCharCode(this.board[row][col]); + const color = COLORS[cellType]; + this.drawBlock(col, row, color); + } + } + } + // Draw current piece + if (this.currentPiece) { + const { shape, x, y, type } = this.currentPiece; + const color = COLORS[type]; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (shape[row][col] !== 0) { + this.drawBlock(x + col, y + row, color); + } + } + } + } + // Draw pause overlay + if (this.gamePaused) { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = '#fff'; + this.ctx.font = 'bold 30px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('PAUSED', this.canvas.width / 2, this.canvas.height / 2); + } + // Draw game over overlay + if (this.gameOver) { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = '#f44336'; + this.ctx.font = 'bold 40px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('GAME OVER', this.canvas.width / 2, this.canvas.height / 2 - 20); + this.ctx.fillStyle = '#fff'; + this.ctx.font = '20px Arial'; + this.ctx.fillText('Press R to restart', this.canvas.width / 2, this.canvas.height / 2 + 30); + } + } + drawBlock(col, row, color) { + const x = col * BLOCK_SIZE; + const y = row * BLOCK_SIZE; + this.ctx.fillStyle = color; + this.ctx.fillRect(x + 1, y + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + // Draw border + this.ctx.strokeStyle = '#fff'; + this.ctx.lineWidth = 2; + this.ctx.strokeRect(x + 1, y + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + // Draw highlight + this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)'; + this.ctx.lineWidth = 1; + this.ctx.strokeRect(x + 3, y + 3, BLOCK_SIZE - 6, BLOCK_SIZE - 6); + } + togglePause() { + if (!this.gameOver) { + this.gamePaused = !this.gamePaused; + this.updateUI(); + } + } + endGame() { + this.gameOver = true; + this.updateUI(); + } + restart() { + this.score = 0; + this.level = 1; + this.lines = 0; + this.dropSpeed = INITIAL_SPEED; + this.gameOver = false; + this.gamePaused = false; + this.initializeBoard(); + this.nextPiece = this.generatePiece(); + this.spawnNewPiece(); + this.lastDropTime = Date.now(); + this.updateUI(); + } + updateUI() { + const scoreEl = document.getElementById('score'); + const levelEl = document.getElementById('level'); + const linesEl = document.getElementById('lines'); + const statusEl = document.getElementById('status'); + if (scoreEl) + scoreEl.textContent = this.score.toString(); + if (levelEl) + levelEl.textContent = this.level.toString(); + if (linesEl) + linesEl.textContent = this.lines.toString(); + if (statusEl) { + if (this.gameOver) { + statusEl.textContent = 'GAME OVER'; + statusEl.style.color = '#f44336'; + } + else if (this.gamePaused) { + statusEl.textContent = 'PAUSED'; + statusEl.style.color = '#ff9800'; + } + else { + statusEl.textContent = 'PLAYING'; + statusEl.style.color = '#4caf50'; + } + } + } +} +// Initialize game when DOM is ready +document.addEventListener('DOMContentLoaded', () => { + new TetrisGame('gameCanvas'); +}); +//# sourceMappingURL=game.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js.map @@ -0,0 +1 @@ +{"version":3,"file":"game.js","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,366 @@ +"use strict"; +// ── Types & Constants ─────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const CELL = 30; // px per cell +const INITIAL_SPEED = 800; // ms between drops at level 0 +const SPEED_DECAY = 0.85; // multiplier per level +const LINES_PER_LEVEL = 10; +// Standard 7 tetrominoes (SRS shapes) +const SHAPES = [ + { shape: [[1, 1, 1, 1]], color: "#00f0f0" }, // I + { shape: [[1, 0, 0], [1, 1, 1]], color: "#0000f0" }, // J + { shape: [[0, 0, 1], [1, 1, 1]], color: "#f0a000" }, // L + { shape: [[1, 1], [1, 1]], color: "#f0f000" }, // O + { shape: [[0, 1, 1], [1, 1, 0]], color: "#00f000" }, // S + { shape: [[0, 1, 0], [1, 1, 1]], color: "#a000f0" }, // T + { shape: [[1, 1, 0], [0, 1, 1]], color: "#f00000" }, // Z +]; +const LINE_SCORES = [0, 100, 300, 500, 800]; +// ── State ─────────────────────────────────────────────────────────── +let canvas; +let ctx; +let nextCanvas; +let nextCtx; +let grid; +let current; +let nextPiece; +let score; +let level; +let lines; +let gameOver; +let paused; +let dropInterval; +let lastDrop; +let animFrameId; +let bag = []; +// ── Helpers ───────────────────────────────────────────────────────── +function createGrid() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function cloneShape(shape) { + return shape.map((row) => [...row]); +} +/** 7‑bag randomiser – guarantees every piece appears once per 7 */ +function nextFromBag() { + if (bag.length === 0) { + bag = [...SHAPES].sort(() => Math.random() - 0.5); + } + return bag.pop(); +} +function spawnPiece(template) { + const shape = cloneShape(template.shape); + return { + shape, + color: template.color, + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + }; +} +function rotateCW(shape) { + const rows = shape.length; + const cols = shape[0].length; + const rotated = Array.from({ length: cols }, () => Array(rows).fill(0)); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + rotated[c][rows - 1 - r] = shape[r][c]; + } + } + return rotated; +} +function collides(piece, grid, dx = 0, dy = 0) { + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + const nx = piece.x + c + dx; + const ny = piece.y + r + dy; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && grid[ny][nx]) + return true; + } + } + return false; +} +function lockPiece(piece, grid) { + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + const ny = piece.y + r; + const nx = piece.x + c; + if (ny >= 0 && ny < ROWS && nx >= 0 && nx < COLS) { + grid[ny][nx] = piece.color; + } + } + } +} +function clearLines(grid) { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (grid[r].every((cell) => cell !== null)) { + grid.splice(r, 1); + grid.unshift(Array(COLS).fill(null)); + cleared++; + r++; // recheck same index + } + } + return cleared; +} +function ghostY(piece, grid) { + let dy = 0; + while (!collides(piece, grid, 0, dy + 1)) + dy++; + return piece.y + dy; +} +// ── Wall‑kick rotation ────────────────────────────────────────────── +function tryRotate(piece, grid) { + const original = piece.shape; + const rotated = rotateCW(original); + const kicks = [0, -1, 1, -2, 2]; // horizontal offsets to try + for (const kick of kicks) { + piece.shape = rotated; + piece.x += kick; + if (!collides(piece, grid)) + return true; + piece.x -= kick; + } + piece.shape = original; + return false; +} +// ── Drawing ───────────────────────────────────────────────────────── +function drawCell(context, x, y, color, alpha = 1) { + context.globalAlpha = alpha; + context.fillStyle = color; + context.fillRect(x * CELL, y * CELL, CELL, CELL); + // highlight + context.fillStyle = "rgba(255,255,255,0.25)"; + context.fillRect(x * CELL, y * CELL, CELL, 2); + context.fillRect(x * CELL, y * CELL, 2, CELL); + // shadow + context.fillStyle = "rgba(0,0,0,0.25)"; + context.fillRect(x * CELL + CELL - 2, y * CELL, 2, CELL); + context.fillRect(x * CELL, y * CELL + CELL - 2, CELL, 2); + // border + context.globalAlpha = alpha; + context.strokeStyle = "#222"; + context.strokeRect(x * CELL, y * CELL, CELL, CELL); + context.globalAlpha = 1; +} +function drawGrid() { + // background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // grid lines (subtle) + ctx.strokeStyle = "#1a1a1a"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(COLS * CELL, r * CELL); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, ROWS * CELL); + ctx.stroke(); + } + ctx.lineWidth = 1; + // locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c]) + drawCell(ctx, c, r, grid[r][c]); + } + } +} +function drawPiece(piece, alpha = 1) { + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + const py = piece.y + r; + if (py < 0) + continue; + drawCell(ctx, piece.x + c, py, piece.color, alpha); + } + } +} +function drawGhost() { + const gy = ghostY(current, grid); + for (let r = 0; r < current.shape.length; r++) { + for (let c = 0; c < current.shape[r].length; c++) { + if (!current.shape[r][c]) + continue; + const py = gy + r; + if (py < 0) + continue; + drawCell(ctx, current.x + c, py, current.color, 0.2); + } + } +} +function drawNext() { + nextCtx.fillStyle = "#1a1a1a"; + nextCtx.fillRect(0, 0, nextCanvas.width, nextCanvas.height); + if (!nextPiece) + return; + const shape = nextPiece.shape; + const offsetX = Math.floor((4 - shape[0].length) / 2); + const offsetY = Math.floor((4 - shape.length) / 2); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + drawCell(nextCtx, offsetX + c, offsetY + r, nextPiece.color); + } + } + } +} +function updateScoreboard() { + document.getElementById("score").textContent = String(score); + document.getElementById("level").textContent = String(level); + document.getElementById("lines").textContent = String(lines); +} +function drawOverlay(text) { + ctx.fillStyle = "rgba(0,0,0,0.6)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px monospace"; + ctx.textAlign = "center"; + ctx.textBaseline = "middle"; + ctx.fillText(text, canvas.width / 2, canvas.height / 2); +} +// ── Game Loop ─────────────────────────────────────────────────────── +function calcSpeed() { + return INITIAL_SPEED * Math.pow(SPEED_DECAY, level); +} +function step() { + if (!collides(current, grid, 0, 1)) { + current.y++; + } + else { + lockPiece(current, grid); + const cleared = clearLines(grid); + if (cleared) { + lines += cleared; + score += LINE_SCORES[cleared] * (level + 1); + level = Math.floor(lines / LINES_PER_LEVEL); + dropInterval = calcSpeed(); + } + // spawn next + current = nextPiece; + nextPiece = spawnPiece(nextFromBag()); + if (collides(current, grid)) { + gameOver = true; + } + } +} +function hardDrop() { + let rows = 0; + while (!collides(current, grid, 0, 1)) { + current.y++; + rows++; + } + score += rows * 2; + step(); // lock immediately +} +function render() { + drawGrid(); + if (!gameOver) { + drawGhost(); + drawPiece(current); + } + drawNext(); + updateScoreboard(); + if (gameOver) + drawOverlay("GAME OVER — press R"); + if (paused && !gameOver) + drawOverlay("PAUSED"); +} +function loop(timestamp) { + animFrameId = requestAnimationFrame(loop); + if (gameOver || paused) { + render(); + return; + } + if (timestamp - lastDrop > dropInterval) { + step(); + lastDrop = timestamp; + } + render(); +} +// ── Input ─────────────────────────────────────────────────────────── +function handleKey(e) { + if (e.key === "r" || e.key === "R") { + init(); + return; + } + if (gameOver) + return; + if (e.key === "p" || e.key === "P") { + paused = !paused; + return; + } + if (paused) + return; + switch (e.key) { + case "ArrowLeft": + if (!collides(current, grid, -1, 0)) + current.x--; + break; + case "ArrowRight": + if (!collides(current, grid, 1, 0)) + current.x++; + break; + case "ArrowDown": + if (!collides(current, grid, 0, 1)) { + current.y++; + score += 1; // soft‑drop bonus + } + break; + case "ArrowUp": + tryRotate(current, grid); + break; + case " ": + hardDrop(); + break; + } + e.preventDefault(); +} +// ── Init ──────────────────────────────────────────────────────────── +function init() { + grid = createGrid(); + score = 0; + level = 0; + lines = 0; + gameOver = false; + paused = false; + bag = []; + dropInterval = calcSpeed(); + lastDrop = performance.now(); + current = spawnPiece(nextFromBag()); + nextPiece = spawnPiece(nextFromBag()); + render(); +} +function main() { + canvas = document.getElementById("game"); + ctx = canvas.getContext("2d"); + canvas.width = COLS * CELL; + canvas.height = ROWS * CELL; + nextCanvas = document.getElementById("next"); + nextCtx = nextCanvas.getContext("2d"); + nextCanvas.width = 4 * CELL; + nextCanvas.height = 4 * CELL; + document.addEventListener("keydown", handleKey); + init(); + animFrameId = requestAnimationFrame(loop); +} +// Start when DOM is ready +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", main); +} +else { + main(); +} +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,550 @@ +"use strict"; +// ─── Constants ─────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const CELL = 32; // px per cell +const PREVIEW_CELLS = 4; +const LOCK_DELAY_MS = 500; +const LINES_PER_LEVEL = 10; +const BASE_SPEED_MS = 800; +const MIN_SPEED_MS = 50; +const SPEED_DECAY = 0.85; // multiplicative per level +// Scoring (NES-style) +const SCORE_TABLE = { 1: 100, 2: 300, 3: 500, 4: 800 }; +const SOFT_DROP_SCORE = 1; +const HARD_DROP_SCORE = 2; +// Colors for each tetromino type (index 0 = empty) +const COLORS = [ + "#111", // empty / background + "#00f0f0", // I – cyan + "#f0f000", // O – yellow + "#a000f0", // T – purple + "#00f000", // S – green + "#f00000", // Z – red + "#0000f0", // J – blue + "#f0a000", // L – orange +]; +const GHOST_ALPHA = 0.25; +function rotateGrid(g) { + const size = g.length; + const out = Array.from({ length: size }, () => Array(size).fill(0)); + for (let r = 0; r < size; r++) + for (let c = 0; c < size; c++) + out[c][size - 1 - r] = g[r][c]; + return out; +} +function buildRotations(base, count) { + const rots = [base]; + let cur = base; + for (let i = 1; i < count; i++) { + cur = rotateGrid(cur); + rots.push(cur); + } + return rots; +} +// SRS wall-kick data (non-I pieces) +const KICKS_NORMAL = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// SRS wall-kick data (I piece) +const KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +const PIECES = [ + { + colorIndex: 1, + rotations: buildRotations([ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], 4), + }, + { + colorIndex: 2, + rotations: buildRotations([ + [1, 1], + [1, 1], + ], 1), + }, + { + colorIndex: 3, + rotations: buildRotations([ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], 4), + }, + { + colorIndex: 4, + rotations: buildRotations([ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], 4), + }, + { + colorIndex: 5, + rotations: buildRotations([ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], 4), + }, + { + colorIndex: 6, + rotations: buildRotations([ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], 4), + }, + { + colorIndex: 7, + rotations: buildRotations([ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], 4), + }, +]; +// ─── Board ─────────────────────────────────────────────────────────────────── +class Board { + constructor(rows, cols) { + this.rows = rows; + this.cols = cols; + this.grid = Array.from({ length: rows }, () => Array(cols).fill(0)); + } + isInside(r, c) { + return r >= 0 && r < this.rows && c >= 0 && c < this.cols; + } + isEmpty(r, c) { + return this.isInside(r, c) && this.grid[r][c] === 0; + } + /** Returns true if the given piece grid at (row, col) doesn't collide. */ + fits(g, row, col) { + for (let r = 0; r < g.length; r++) + for (let c = 0; c < g[r].length; c++) + if (g[r][c]) { + const br = row + r; + const bc = col + c; + if (!this.isInside(br, bc) || this.grid[br][bc] !== 0) + return false; + } + return true; + } + /** Lock piece into the board. */ + lock(g, row, col, colorIndex) { + for (let r = 0; r < g.length; r++) + for (let c = 0; c < g[r].length; c++) + if (g[r][c]) + this.grid[row + r][col + c] = colorIndex; + } + /** Clear full lines; returns number cleared. */ + clearLines() { + let cleared = 0; + for (let r = this.rows - 1; r >= 0; r--) { + if (this.grid[r].every(v => v !== 0)) { + this.grid.splice(r, 1); + this.grid.unshift(Array(this.cols).fill(0)); + cleared++; + r++; // re-check same index + } + } + return cleared; + } +} +// ─── 7-bag random generator ───────────────────────────────────────────────── +class BagRandom { + constructor() { + this.bag = []; + } + next() { + if (this.bag.length === 0) { + this.bag = [0, 1, 2, 3, 4, 5, 6]; + // Fisher-Yates + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop(); + } +} +// ─── Game ──────────────────────────────────────────────────────────────────── +class TetrisGame { + constructor() { + // Current piece state + this.pieceIdx = 0; + this.rotation = 0; + this.pieceRow = 0; + this.pieceCol = 0; + // Next piece + this.nextPieceIdx = 0; + // Stats + this.score = 0; + this.lines = 0; + this.level = 1; + // Timing + this.dropInterval = BASE_SPEED_MS; + this.lastDrop = 0; + this.lockTimer = -1; // -1 = not ticking + this.gameOver = false; + this.paused = false; + // Animation: rows that were just cleared (for flash effect) + this.clearingRows = []; + this.clearAnimEnd = 0; + this.CLEAR_ANIM_MS = 250; + this.board = new Board(ROWS, COLS); + this.rng = new BagRandom(); + this.nextPieceIdx = this.rng.next(); + this.spawnPiece(); + } + // ── helpers ── + get def() { return PIECES[this.pieceIdx]; } + get grid() { return this.def.rotations[this.rotation]; } + get kicks() { return this.pieceIdx === 0 ? KICKS_I : KICKS_NORMAL; } + spawnPiece() { + this.pieceIdx = this.nextPieceIdx; + this.nextPieceIdx = this.rng.next(); + this.rotation = 0; + const g = this.grid; + this.pieceCol = Math.floor((COLS - g[0].length) / 2); + this.pieceRow = 0; + // Move up if top rows of grid are empty + for (let r = 0; r < g.length; r++) { + if (g[r].some(v => v !== 0)) + break; + this.pieceRow--; + } + this.lockTimer = -1; + if (!this.board.fits(this.grid, this.pieceRow, this.pieceCol)) { + this.gameOver = true; + } + } + /** Attempt to move the piece by (dr, dc). Returns success. */ + move(dr, dc) { + if (this.gameOver || this.paused) + return false; + const nr = this.pieceRow + dr; + const nc = this.pieceCol + dc; + if (this.board.fits(this.grid, nr, nc)) { + this.pieceRow = nr; + this.pieceCol = nc; + // Reset lock timer on successful move if piece is still above ground + if (dr === 0) + this.resetLockIfNeeded(); + return true; + } + return false; + } + /** Attempt SRS rotation. dir = +1 (CW) or -1 (CCW). */ + rotate(dir) { + if (this.gameOver || this.paused) + return false; + const rots = this.def.rotations.length; + if (rots <= 1) + return false; // O piece + const oldRot = this.rotation; + const newRot = ((this.rotation + dir) % rots + rots) % rots; + const newGrid = this.def.rotations[newRot]; + const key = `${oldRot}>${newRot}`; + const kickTable = this.kicks[key] || [[0, 0]]; + for (const [dx, dy] of kickTable) { + // SRS convention: dx is col offset, dy is row offset (up positive) + const nr = this.pieceRow - dy; + const nc = this.pieceCol + dx; + if (this.board.fits(newGrid, nr, nc)) { + this.rotation = newRot; + this.pieceRow = nr; + this.pieceCol = nc; + this.resetLockIfNeeded(); + return true; + } + } + return false; + } + /** Soft-drop one row. */ + softDrop() { + if (this.move(1, 0)) { + this.score += SOFT_DROP_SCORE; + return true; + } + return false; + } + /** Hard-drop: instant placement. */ + hardDrop() { + if (this.gameOver || this.paused) + return; + let rows = 0; + while (this.board.fits(this.grid, this.pieceRow + 1, this.pieceCol)) { + this.pieceRow++; + rows++; + } + this.score += rows * HARD_DROP_SCORE; + this.lockPiece(); + } + /** Where the ghost piece sits. */ + ghostRow() { + let r = this.pieceRow; + while (this.board.fits(this.grid, r + 1, this.pieceCol)) + r++; + return r; + } + // ── internal ── + resetLockIfNeeded() { + if (!this.board.fits(this.grid, this.pieceRow + 1, this.pieceCol)) { + this.lockTimer = performance.now() + LOCK_DELAY_MS; + } + else { + this.lockTimer = -1; + } + } + lockPiece() { + this.board.lock(this.grid, this.pieceRow, this.pieceCol, this.def.colorIndex); + const cleared = this.board.clearLines(); + if (cleared > 0) { + this.lines += cleared; + this.score += (SCORE_TABLE[cleared] || 0) * this.level; + this.level = Math.floor(this.lines / LINES_PER_LEVEL) + 1; + this.dropInterval = Math.max(MIN_SPEED_MS, BASE_SPEED_MS * Math.pow(SPEED_DECAY, this.level - 1)); + } + this.spawnPiece(); + } + /** Called every frame with the current timestamp (ms). */ + update(now) { + if (this.gameOver || this.paused) + return; + // Gravity + if (now - this.lastDrop >= this.dropInterval) { + this.lastDrop = now; + if (!this.move(1, 0)) { + // Can't move down – start lock timer if not already + if (this.lockTimer < 0) { + this.lockTimer = now + LOCK_DELAY_MS; + } + } + } + // Lock timer + if (this.lockTimer > 0 && now >= this.lockTimer) { + if (!this.board.fits(this.grid, this.pieceRow + 1, this.pieceCol)) { + this.lockPiece(); + } + else { + this.lockTimer = -1; + } + } + } + togglePause() { + if (this.gameOver) + return; + this.paused = !this.paused; + } + restart() { + this.board = new Board(ROWS, COLS); + this.rng = new BagRandom(); + this.nextPieceIdx = this.rng.next(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.dropInterval = BASE_SPEED_MS; + this.lastDrop = 0; + this.gameOver = false; + this.paused = false; + this.spawnPiece(); + } +} +// ─── Renderer ──────────────────────────────────────────────────────────────── +class Renderer { + constructor(canvas, previewCanvas) { + this.canvas = canvas; + this.previewCanvas = previewCanvas; + this.ctx = canvas.getContext("2d"); + this.previewCtx = previewCanvas.getContext("2d"); + canvas.width = COLS * CELL; + canvas.height = ROWS * CELL; + previewCanvas.width = PREVIEW_CELLS * CELL; + previewCanvas.height = PREVIEW_CELLS * CELL; + } + draw(game) { + const ctx = this.ctx; + // Background + ctx.fillStyle = COLORS[0]; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(COLS * CELL, r * CELL); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, ROWS * CELL); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < ROWS; r++) + for (let c = 0; c < COLS; c++) + if (game.board.grid[r][c]) + this.drawCell(ctx, c, r, COLORS[game.board.grid[r][c]], 1); + // Ghost piece + if (!game.gameOver) { + const gr = game.ghostRow(); + const g = PIECES[game.pieceIdx].rotations[game.rotation]; + const color = COLORS[PIECES[game.pieceIdx].colorIndex]; + for (let r = 0; r < g.length; r++) + for (let c = 0; c < g[r].length; c++) + if (g[r][c]) + this.drawCell(ctx, game.pieceCol + c, gr + r, color, GHOST_ALPHA); + } + // Current piece + if (!game.gameOver && !game.paused) { + const g = PIECES[game.pieceIdx].rotations[game.rotation]; + const color = COLORS[PIECES[game.pieceIdx].colorIndex]; + for (let r = 0; r < g.length; r++) + for (let c = 0; c < g[r].length; c++) + if (g[r][c]) + this.drawCell(ctx, game.pieceCol + c, game.pieceRow + r, color, 1); + } + // Pause overlay + if (game.paused) { + ctx.fillStyle = "rgba(0,0,0,0.6)"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px monospace"; + ctx.textAlign = "center"; + ctx.fillText("PAUSED", this.canvas.width / 2, this.canvas.height / 2); + } + // Game-over overlay + if (game.gameOver) { + ctx.fillStyle = "rgba(0,0,0,0.7)"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + ctx.fillStyle = "#f44"; + ctx.font = "bold 30px monospace"; + ctx.textAlign = "center"; + ctx.fillText("GAME OVER", this.canvas.width / 2, this.canvas.height / 2 - 20); + ctx.fillStyle = "#fff"; + ctx.font = "18px monospace"; + ctx.fillText("Press R to restart", this.canvas.width / 2, this.canvas.height / 2 + 20); + } + // Preview + this.drawPreview(game); + } + drawPreview(game) { + const ctx = this.previewCtx; + ctx.fillStyle = COLORS[0]; + ctx.fillRect(0, 0, this.previewCanvas.width, this.previewCanvas.height); + const def = PIECES[game.nextPieceIdx]; + const g = def.rotations[0]; + const color = COLORS[def.colorIndex]; + const offsetX = Math.floor((PREVIEW_CELLS - g[0].length) / 2); + const offsetY = Math.floor((PREVIEW_CELLS - g.length) / 2); + for (let r = 0; r < g.length; r++) + for (let c = 0; c < g[r].length; c++) + if (g[r][c]) + this.drawCell(ctx, offsetX + c, offsetY + r, color, 1); + } + drawCell(ctx, col, row, color, alpha) { + if (row < 0) + return; // above visible area + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(col * CELL + 1, row * CELL + 1, CELL - 2, CELL - 2); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.18)"; + ctx.fillRect(col * CELL + 1, row * CELL + 1, CELL - 2, 4); + ctx.fillRect(col * CELL + 1, row * CELL + 1, 4, CELL - 2); + // Shadow + ctx.fillStyle = "rgba(0,0,0,0.18)"; + ctx.fillRect(col * CELL + 1, row * CELL + CELL - 5, CELL - 2, 4); + ctx.fillRect(col * CELL + CELL - 5, row * CELL + 1, 4, CELL - 2); + ctx.globalAlpha = 1; + } +} +// ─── Input ─────────────────────────────────────────────────────────────────── +function bindInput(game) { + // DAS (Delayed Auto Shift) settings + const DAS_DELAY = 170; // ms before auto-repeat starts + const DAS_RATE = 50; // ms between auto-repeat moves + const held = {}; + const dasTimers = {}; + const actions = { + ArrowLeft: () => game.move(0, -1), + ArrowRight: () => game.move(0, 1), + ArrowDown: () => game.softDrop(), + ArrowUp: () => game.rotate(1), + x: () => game.rotate(1), + z: () => game.rotate(-1), + " ": () => game.hardDrop(), + p: () => game.togglePause(), + r: () => { if (game.gameOver) + game.restart(); }, + }; + const repeatableKeys = new Set(["ArrowLeft", "ArrowRight", "ArrowDown"]); + document.addEventListener("keydown", (e) => { + const key = e.key; + if (actions[key]) { + e.preventDefault(); + if (!held[key]) { + held[key] = true; + actions[key](); + if (repeatableKeys.has(key)) { + dasTimers[key] = window.setTimeout(() => { + dasTimers[key] = window.setInterval(() => actions[key](), DAS_RATE); + }, DAS_DELAY); + } + } + } + }); + document.addEventListener("keyup", (e) => { + const key = e.key; + held[key] = false; + if (dasTimers[key] !== undefined) { + clearTimeout(dasTimers[key]); + clearInterval(dasTimers[key]); + delete dasTimers[key]; + } + }); +} +// ─── HUD ───────────────────────────────────────────────────────────────────── +function updateHUD(game) { + const el = (id) => document.getElementById(id); + el("score").textContent = String(game.score); + el("lines").textContent = String(game.lines); + el("level").textContent = String(game.level); +} +// ─── Bootstrap ─────────────────────────────────────────────────────────────── +function main() { + const canvas = document.getElementById("board"); + const preview = document.getElementById("preview"); + const game = new TetrisGame(); + const renderer = new Renderer(canvas, preview); + bindInput(game); + function loop(now) { + game.update(now); + renderer.draw(game); + updateHUD(game); + requestAnimationFrame(loop); + } + requestAnimationFrame(loop); +} +document.addEventListener("DOMContentLoaded", main); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,558 @@ +"use strict"; +// ── Types ────────────────────────────────────────────────────────────────── +// ── Constants ────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 32; // pixels per cell +const PREVIEW_BLOCK = 20; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const GHOST_ALPHA = 0.25; +const SHAPES = { + I: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + O: [ + [1, 1], + [1, 1], + ], + T: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + S: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + Z: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + J: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + L: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], +}; +// SRS wall-kick data (non-I pieces) +const WALL_KICKS = { + "0>1": [{ x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "1>0": [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], + "1>2": [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], + "2>1": [{ x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "2>3": [{ x: 1, y: 0 }, { x: 1, y: -1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], + "3>2": [{ x: -1, y: 0 }, { x: -1, y: 1 }, { x: 0, y: -2 }, { x: -1, y: -2 }], + "3>0": [{ x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "0>3": [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], +}; +// SRS wall-kick data (I piece) +const WALL_KICKS_I = { + "0>1": [{ x: -2, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 1 }, { x: 1, y: -2 }], + "1>0": [{ x: 2, y: 0 }, { x: -1, y: 0 }, { x: 2, y: -1 }, { x: -1, y: 2 }], + "1>2": [{ x: -1, y: 0 }, { x: 2, y: 0 }, { x: -1, y: -2 }, { x: 2, y: 1 }], + "2>1": [{ x: 1, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 2 }, { x: -2, y: -1 }], + "2>3": [{ x: 2, y: 0 }, { x: -1, y: 0 }, { x: 2, y: -1 }, { x: -1, y: 2 }], + "3>2": [{ x: -2, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 1 }, { x: 1, y: -2 }], + "3>0": [{ x: 1, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 2 }, { x: -2, y: -1 }], + "0>3": [{ x: -1, y: 0 }, { x: 2, y: 0 }, { x: -1, y: -2 }, { x: 2, y: 1 }], +}; +const LINE_SCORES = [0, 100, 300, 500, 800]; +const LINES_PER_LEVEL = 10; +const BASE_DROP_INTERVAL = 1000; // ms at level 0 +const MIN_DROP_INTERVAL = 50; +const LOCK_DELAY = 500; // ms +const PIECE_NAMES = Object.keys(SHAPES); +// ── Canvas Setup ─────────────────────────────────────────────────────────── +const canvas = document.getElementById("game"); +const ctx = canvas.getContext("2d"); +canvas.width = COLS * BLOCK; +canvas.height = ROWS * BLOCK; +const previewCanvas = document.getElementById("preview"); +const previewCtx = previewCanvas.getContext("2d"); +previewCanvas.width = 6 * PREVIEW_BLOCK; +previewCanvas.height = 6 * PREVIEW_BLOCK; +const holdCanvas = document.getElementById("hold"); +const holdCtx = holdCanvas.getContext("2d"); +holdCanvas.width = 6 * PREVIEW_BLOCK; +holdCanvas.height = 6 * PREVIEW_BLOCK; +const scoreEl = document.getElementById("score"); +const levelEl = document.getElementById("level"); +const linesEl = document.getElementById("lines"); +// ── Game State ───────────────────────────────────────────────────────────── +let grid; +let current; +let currentType; +let currentRotation; +let nextType; +let holdType; +let holdUsed; +let score; +let level; +let lines; +let gameOver; +let paused; +let lastDrop; +let lockTimer; +let locking; +let bag; +let animatingRows; +let animStart; +const ANIM_DURATION = 300; +// DAS / auto-repeat +const DAS_DELAY = 170; // ms before auto-repeat starts +const ARR_DELAY = 50; // ms between repeated moves +let heldKey = null; +let dasTimer = 0; +let arrTimer = 0; +// ── Helpers ──────────────────────────────────────────────────────────────── +function createGrid() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function shuffledBag() { + const a = [...PIECE_NAMES]; + for (let i = a.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [a[i], a[j]] = [a[j], a[i]]; + } + return a; +} +function nextFromBag() { + if (bag.length === 0) + bag = shuffledBag(); + return bag.pop(); +} +function spawn(type) { + const shape = SHAPES[type].map((r) => [...r]); + return { + shape, + color: COLORS[type], + pos: { x: Math.floor((COLS - shape[0].length) / 2), y: 0 }, + }; +} +function rotate(shape) { + const n = shape.length; + const out = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) + for (let c = 0; c < n; c++) + out[c][n - 1 - r] = shape[r][c]; + return out; +} +function valid(shape, pos) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const x = pos.x + c; + const y = pos.y + r; + if (x < 0 || x >= COLS || y >= ROWS) + return false; + if (y >= 0 && grid[y][x]) + return false; + } + } + return true; +} +function lock() { + const { shape, color, pos } = current; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const y = pos.y + r; + const x = pos.x + c; + if (y < 0) { + gameOver = true; + return; + } + grid[y][x] = color; + } + } + clearLines(); + spawnNext(); +} +function clearLines() { + const full = []; + for (let r = 0; r < ROWS; r++) { + if (grid[r].every((c) => c !== null)) + full.push(r); + } + if (full.length === 0) + return; + // Start line-clear animation + animatingRows = full; + animStart = performance.now(); + // Defer the actual clearing — we'll handle it in the animation callback + setTimeout(() => { + for (const r of full) + grid.splice(r, 1); + while (grid.length < ROWS) + grid.unshift(Array(COLS).fill(null)); + animatingRows = []; + const cleared = full.length; + lines += cleared; + score += LINE_SCORES[cleared] * (level + 1); + level = Math.floor(lines / LINES_PER_LEVEL); + updateHUD(); + }, ANIM_DURATION); +} +function spawnNext() { + currentType = nextType; + currentRotation = 0; + nextType = nextFromBag(); + current = spawn(currentType); + holdUsed = false; + locking = false; + if (!valid(current.shape, current.pos)) { + gameOver = true; + } +} +function dropInterval() { + return Math.max(MIN_DROP_INTERVAL, BASE_DROP_INTERVAL - level * 75); +} +function ghostY() { + let gy = current.pos.y; + while (valid(current.shape, { x: current.pos.x, y: gy + 1 })) + gy++; + return gy; +} +// ── Drawing ──────────────────────────────────────────────────────────────── +function drawBlock(context, x, y, color, size, alpha = 1) { + context.globalAlpha = alpha; + context.fillStyle = color; + context.fillRect(x * size, y * size, size, size); + // highlight + context.fillStyle = "rgba(255,255,255,0.25)"; + context.fillRect(x * size, y * size, size, size * 0.1); + context.fillRect(x * size, y * size, size * 0.1, size); + // shadow + context.fillStyle = "rgba(0,0,0,0.25)"; + context.fillRect(x * size, y * size + size * 0.9, size, size * 0.1); + context.fillRect(x * size + size * 0.9, y * size, size * 0.1, size); + // grid line + context.strokeStyle = "rgba(0,0,0,0.4)"; + context.lineWidth = 1; + context.strokeRect(x * size + 0.5, y * size + 0.5, size - 1, size - 1); + context.globalAlpha = 1; +} +function drawGrid() { + // background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // subtle grid lines + ctx.strokeStyle = "rgba(255,255,255,0.03)"; + ctx.lineWidth = 1; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(canvas.width, r * BLOCK); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, canvas.height); + ctx.stroke(); + } + const now = performance.now(); + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c]) { + let alpha = 1; + if (animatingRows.includes(r)) { + const t = Math.min(1, (now - animStart) / ANIM_DURATION); + alpha = 1 - t; + } + drawBlock(ctx, c, r, grid[r][c], BLOCK, alpha); + } + } + } +} +function drawPiece(piece, alpha = 1, yOverride) { + const y0 = yOverride ?? piece.pos.y; + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + const dy = y0 + r; + if (dy < 0) + continue; + drawBlock(ctx, piece.pos.x + c, dy, piece.color, BLOCK, alpha); + } + } +} +function drawPreviewPiece(context, type) { + context.fillStyle = "#1a1a2e"; + context.fillRect(0, 0, context.canvas.width, context.canvas.height); + if (!type) + return; + const shape = SHAPES[type]; + const color = COLORS[type]; + const offsetX = (6 - shape[0].length) / 2; + const offsetY = (6 - shape.length) / 2; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + drawBlock(context, offsetX + c, offsetY + r, color, PREVIEW_BLOCK); + } + } + } +} +function drawScene() { + drawGrid(); + // ghost + const gy = ghostY(); + if (gy !== current.pos.y) { + drawPiece(current, GHOST_ALPHA, gy); + } + // active piece + drawPiece(current); + // preview & hold + drawPreviewPiece(previewCtx, nextType); + drawPreviewPiece(holdCtx, holdType); +} +function updateHUD() { + scoreEl.textContent = score.toString(); + levelEl.textContent = level.toString(); + linesEl.textContent = lines.toString(); +} +// ── Input ────────────────────────────────────────────────────────────────── +function tryMove(dx, dy) { + const newPos = { x: current.pos.x + dx, y: current.pos.y + dy }; + if (valid(current.shape, newPos)) { + current.pos = newPos; + if (dy === 0) + resetLock(); + return true; + } + return false; +} +function tryRotate(dir) { + // dir: 1 = CW, -1 = CCW (CCW = 3 CW rotations) + let newShape = current.shape; + const turns = dir === 1 ? 1 : 3; + for (let i = 0; i < turns; i++) + newShape = rotate(newShape); + const oldRot = currentRotation; + const newRot = (currentRotation + dir + 4) % 4; + const kickKey = `${oldRot}>${newRot}`; + const isI = currentType === "I"; + const kicks = isI ? WALL_KICKS_I[kickKey] : WALL_KICKS[kickKey]; + // Test 0: no offset + if (valid(newShape, current.pos)) { + current.shape = newShape; + currentRotation = newRot; + resetLock(); + return; + } + // Tests 1-4 + if (kicks) { + for (const k of kicks) { + const newPos = { x: current.pos.x + k.x, y: current.pos.y - k.y }; + if (valid(newShape, newPos)) { + current.shape = newShape; + current.pos = newPos; + currentRotation = newRot; + resetLock(); + return; + } + } + } +} +function hardDrop() { + let rows = 0; + while (valid(current.shape, { x: current.pos.x, y: current.pos.y + 1 })) { + current.pos.y++; + rows++; + } + score += rows * 2; + updateHUD(); + lock(); +} +function holdPiece() { + if (holdUsed) + return; + holdUsed = true; + const tmp = holdType; + holdType = currentType; + if (tmp) { + currentType = tmp; + currentRotation = 0; + current = spawn(currentType); + } + else { + spawnNext(); + } +} +function resetLock() { + locking = false; +} +function handleMovement(key) { + if (key === "ArrowLeft") + tryMove(-1, 0); + else if (key === "ArrowRight") + tryMove(1, 0); + else if (key === "ArrowDown") { + if (tryMove(0, 1)) { + score += 1; + updateHUD(); + } + } +} +document.addEventListener("keydown", (e) => { + if (gameOver) { + if (e.key === "Enter") { + init(); + } + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + paused = !paused; + if (!paused) + lastDrop = performance.now(); + return; + } + if (paused) + return; + switch (e.key) { + case "ArrowLeft": + case "ArrowRight": + case "ArrowDown": + e.preventDefault(); + if (heldKey !== e.key) { + heldKey = e.key; + dasTimer = performance.now(); + arrTimer = 0; + handleMovement(e.key); + } + break; + case "ArrowUp": + e.preventDefault(); + tryRotate(1); + break; + case "z": + case "Z": + tryRotate(-1); + break; + case " ": + e.preventDefault(); + hardDrop(); + break; + case "c": + case "C": + case "Shift": + holdPiece(); + break; + } +}); +document.addEventListener("keyup", (e) => { + if (e.key === heldKey) { + heldKey = null; + } +}); +// ── Game Loop ────────────────────────────────────────────────────────────── +function init() { + grid = createGrid(); + bag = shuffledBag(); + nextType = nextFromBag(); + holdType = null; + holdUsed = false; + score = 0; + level = 0; + lines = 0; + gameOver = false; + paused = false; + lastDrop = performance.now(); + locking = false; + lockTimer = 0; + animatingRows = []; + animStart = 0; + heldKey = null; + spawnNext(); + updateHUD(); +} +function update(now) { + if (gameOver || paused) + return; + if (animatingRows.length > 0) + return; // wait for clear animation + // DAS auto-repeat + if (heldKey && (heldKey === "ArrowLeft" || heldKey === "ArrowRight" || heldKey === "ArrowDown")) { + const elapsed = now - dasTimer; + if (elapsed >= DAS_DELAY) { + const arrElapsed = now - (arrTimer || (dasTimer + DAS_DELAY)); + if (arrElapsed >= ARR_DELAY) { + handleMovement(heldKey); + arrTimer = now; + } + } + } + const interval = dropInterval(); + if (now - lastDrop >= interval) { + if (valid(current.shape, { x: current.pos.x, y: current.pos.y + 1 })) { + current.pos.y++; + locking = false; + } + else { + // Start lock delay + if (!locking) { + locking = true; + lockTimer = now; + } + else if (now - lockTimer >= LOCK_DELAY) { + lock(); + } + } + lastDrop = now; + } + // Also handle lock delay between gravity ticks + if (locking && !valid(current.shape, { x: current.pos.x, y: current.pos.y + 1 })) { + if (now - lockTimer >= LOCK_DELAY) { + lock(); + } + } +} +function drawOverlay(text, sub) { + ctx.fillStyle = "rgba(0,0,0,0.65)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "#fff"; + ctx.font = "bold 36px monospace"; + ctx.textAlign = "center"; + ctx.fillText(text, canvas.width / 2, canvas.height / 2 - 10); + if (sub) { + ctx.font = "18px monospace"; + ctx.fillStyle = "#aaa"; + ctx.fillText(sub, canvas.width / 2, canvas.height / 2 + 25); + } +} +function frame(now) { + update(now); + drawScene(); + if (gameOver) { + drawOverlay("GAME OVER", "Press Enter to restart"); + } + else if (paused) { + drawOverlay("PAUSED", "Press P or Esc to resume"); + } + requestAnimationFrame(frame); +} +// ── Start ────────────────────────────────────────────────────────────────── +init(); +requestAnimationFrame(frame); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=detailed_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=detailed_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,444 @@ +"use strict"; +// ============================================================ +// Tetris – Single-page browser game (TypeScript source) +// ============================================================ +// ----- Constants -------------------------------------------- +const COLS = 10; +const ROWS = 20; +const CELL = 32; // px per cell +const PREVIEW_CELL = 20; // px per cell in preview +const COLORS = { + 1: "#00e5ff", // I – cyan + 2: "#fdd835", // O – yellow + 3: "#ab47bc", // T – purple + 4: "#66bb6a", // S – green + 5: "#ef5350", // Z – red + 6: "#42a5f5", // J – blue + 7: "#ffa726", // L – orange +}; +const GHOST_ALPHA = 0.25; +// All rotation states for each piece. +// Convention: shapes are stored as row-major 2-D arrays where 1 = filled. +const SHAPES = [ + [], // index 0 unused + // 1 – I + [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + // 2 – O + [ + [[1, 1], [1, 1]], + ], + // 3 – T + [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + // 4 – S + [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + // 5 – Z + [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + // 6 – J + [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + // 7 – L + [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +]; +// Spawn x-offsets so pieces appear centred (roughly column 3) +const SPAWN_X = [0, 3, 4, 3, 3, 3, 3, 3]; +const SPAWN_Y = [0, -1, 0, -1, -1, -1, -1, -1]; +// Basic wall-kick offsets to try (dx, dy) after a failed rotation. +const KICKS = [ + [0, 0], [-1, 0], [1, 0], [0, -1], [-1, -1], [1, -1], [-2, 0], [2, 0], +]; +// Scoring table (index = lines cleared) +const BASE_POINTS = [0, 100, 300, 500, 800]; +// Speed curve: milliseconds per drop at each level +function dropInterval(level) { + return Math.max(50, 800 - (level - 1) * 75); +} +// ----- Random bag ------------------------------------------- +class Bag { + constructor() { + this.queue = []; + } + fillBag() { + const a = [1, 2, 3, 4, 5, 6, 7]; + for (let i = a.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [a[i], a[j]] = [a[j], a[i]]; + } + this.queue.push(...a); + } + next() { + if (this.queue.length < 2) + this.fillBag(); + return this.queue.shift(); + } + peek() { + if (this.queue.length < 2) + this.fillBag(); + return this.queue[0]; + } +} +// ----- Helpers ---------------------------------------------- +function createGrid() { + return Array.from({ length: ROWS }, () => new Array(COLS).fill(0)); +} +function clonePiece(p) { + return { type: p.type, shapes: p.shapes, rotation: p.rotation, x: p.x, y: p.y }; +} +function shape(p) { + return p.shapes[p.rotation % p.shapes.length]; +} +function collides(grid, p) { + const s = shape(p); + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const nx = p.x + c; + const ny = p.y + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && grid[ny][nx] !== 0) + return true; + } + } + return false; +} +function lock(grid, p) { + const s = shape(p); + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const ny = p.y + r; + const nx = p.x + c; + if (ny >= 0 && ny < ROWS && nx >= 0 && nx < COLS) { + grid[ny][nx] = p.type; + } + } + } +} +function clearLines(grid) { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (grid[r].every(c => c !== 0)) { + grid.splice(r, 1); + grid.unshift(new Array(COLS).fill(0)); + cleared++; + r++; // re-check same index + } + } + return cleared; +} +function ghostY(grid, p) { + const g = clonePiece(p); + while (!collides(grid, g)) + g.y++; + return g.y - 1; +} +// ----- Game ------------------------------------------------- +class TetrisGame { + constructor() { + this.grid = createGrid(); + this.bag = new Bag(); + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameOver = false; + this.lastDrop = 0; + this.animId = 0; + // --- Main loop -------------------------------------------- + this.loop = (time) => { + this.animId = requestAnimationFrame(this.loop); + if (this.gameOver) { + this.draw(); + return; + } + const interval = dropInterval(this.level); + if (time - this.lastDrop >= interval) { + this.lastDrop = time; + if (!this.tryMove(0, 1)) { + this.lockAndAdvance(); + } + } + this.draw(); + }; + this.canvas = document.getElementById("board"); + this.ctx = this.canvas.getContext("2d"); + this.previewCanvas = document.getElementById("preview"); + this.previewCtx = this.previewCanvas.getContext("2d"); + this.scoreEl = document.getElementById("score"); + this.levelEl = document.getElementById("level"); + this.linesEl = document.getElementById("lines"); + this.overlay = document.getElementById("overlay"); + this.overlayMsg = document.getElementById("overlay-msg"); + this.overlayScore = document.getElementById("overlay-score"); + this.restartBtn = document.getElementById("restart-btn"); + this.canvas.width = COLS * CELL; + this.canvas.height = ROWS * CELL; + this.previewCanvas.width = 5 * PREVIEW_CELL; + this.previewCanvas.height = 5 * PREVIEW_CELL; + window.addEventListener("keydown", (e) => this.onKey(e)); + this.restartBtn.addEventListener("click", () => this.restart()); + this.spawn(); + this.lastDrop = performance.now(); + this.loop(this.lastDrop); + } + // --- Piece management --- + makePiece(type) { + return { + type, + shapes: SHAPES[type], + rotation: 0, + x: SPAWN_X[type], + y: SPAWN_Y[type], + }; + } + spawn() { + const type = this.bag.next(); + this.current = this.makePiece(type); + if (collides(this.grid, this.current)) { + this.endGame(); + } + } + // --- Movement helpers --- + tryMove(dx, dy) { + const p = clonePiece(this.current); + p.x += dx; + p.y += dy; + if (!collides(this.grid, p)) { + this.current = p; + return true; + } + return false; + } + tryRotate(dir) { + if (this.current.shapes.length === 1) + return false; // O-piece + const p = clonePiece(this.current); + p.rotation = (p.rotation + dir + p.shapes.length) % p.shapes.length; + for (const [kx, ky] of KICKS) { + const t = clonePiece(p); + t.x += kx; + t.y += ky; + if (!collides(this.grid, t)) { + this.current = t; + return true; + } + } + return false; + } + hardDrop() { + const gy = ghostY(this.grid, this.current); + this.current.y = gy; + this.lockAndAdvance(); + } + lockAndAdvance() { + lock(this.grid, this.current); + const cleared = clearLines(this.grid); + if (cleared > 0) { + this.lines += cleared; + this.score += BASE_POINTS[cleared] * this.level; + this.level = Math.floor(this.lines / 10) + 1; + } + this.spawn(); + } + // --- Input ------------------------------------------------ + onKey(e) { + if (this.gameOver) { + if (e.key === "Enter" || e.key === "r" || e.key === "R") + this.restart(); + return; + } + switch (e.key) { + case "ArrowLeft": + e.preventDefault(); + this.tryMove(-1, 0); + break; + case "ArrowRight": + e.preventDefault(); + this.tryMove(1, 0); + break; + case "ArrowDown": + e.preventDefault(); + if (this.tryMove(0, 1)) { + this.lastDrop = performance.now(); + } + break; + case "ArrowUp": + e.preventDefault(); + this.tryRotate(1); + break; + case "z": + case "Z": + e.preventDefault(); + this.tryRotate(-1); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + } + } + // --- Game flow -------------------------------------------- + endGame() { + this.gameOver = true; + this.overlay.classList.add("visible"); + this.overlayMsg.textContent = "Game Over"; + this.overlayScore.textContent = "Score: " + this.score; + } + restart() { + this.grid = createGrid(); + this.bag = new Bag(); + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameOver = false; + this.overlay.classList.remove("visible"); + this.spawn(); + this.lastDrop = performance.now(); + } + // --- Rendering -------------------------------------------- + draw() { + const ctx = this.ctx; + // Background + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Grid lines + ctx.strokeStyle = "#2a2a45"; + ctx.lineWidth = 1; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(COLS * CELL, r * CELL); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, ROWS * CELL); + ctx.stroke(); + } + // Locked blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.grid[r][c]) { + this.drawCell(ctx, c, r, COLORS[this.grid[r][c]], CELL, 1.0); + } + } + } + if (!this.gameOver && this.current) { + // Ghost piece + const gy = ghostY(this.grid, this.current); + const s = shape(this.current); + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const ny = gy + r; + const nx = this.current.x + c; + if (ny >= 0 && ny < ROWS && nx >= 0 && nx < COLS) { + this.drawCell(ctx, nx, ny, COLORS[this.current.type], CELL, GHOST_ALPHA); + } + } + } + // Current piece + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const ny = this.current.y + r; + const nx = this.current.x + c; + if (ny >= 0 && ny < ROWS && nx >= 0 && nx < COLS) { + this.drawCell(ctx, nx, ny, COLORS[this.current.type], CELL, 1.0); + } + } + } + } + // HUD + this.scoreEl.textContent = String(this.score); + this.levelEl.textContent = String(this.level); + this.linesEl.textContent = String(this.lines); + // Next piece preview + this.drawPreview(); + } + drawCell(ctx, cx, cy, color, size, alpha) { + const x = cx * size; + const y = cy * size; + const inset = 2; + ctx.globalAlpha = alpha; + // Main fill + ctx.fillStyle = color; + ctx.fillRect(x + inset, y + inset, size - inset * 2, size - inset * 2); + // Highlight (top-left bevel) + ctx.fillStyle = "rgba(255,255,255,0.3)"; + ctx.fillRect(x + inset, y + inset, size - inset * 2, 3); + ctx.fillRect(x + inset, y + inset, 3, size - inset * 2); + // Shadow (bottom-right bevel) + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(x + inset, y + size - inset - 3, size - inset * 2, 3); + ctx.fillRect(x + size - inset - 3, y + inset, 3, size - inset * 2); + ctx.globalAlpha = 1; + } + drawPreview() { + const pctx = this.previewCtx; + const cw = this.previewCanvas.width; + const ch = this.previewCanvas.height; + pctx.fillStyle = "#16162a"; + pctx.fillRect(0, 0, cw, ch); + const nextType = this.bag.peek(); + const s = SHAPES[nextType][0]; + const rows = s.length; + const cols = s[0].length; + const ox = Math.floor((cw - cols * PREVIEW_CELL) / 2); + const oy = Math.floor((ch - rows * PREVIEW_CELL) / 2); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (!s[r][c]) + continue; + const x = ox + c * PREVIEW_CELL; + const y = oy + r * PREVIEW_CELL; + const inset = 1; + pctx.fillStyle = COLORS[nextType]; + pctx.fillRect(x + inset, y + inset, PREVIEW_CELL - inset * 2, PREVIEW_CELL - inset * 2); + pctx.fillStyle = "rgba(255,255,255,0.25)"; + pctx.fillRect(x + inset, y + inset, PREVIEW_CELL - inset * 2, 2); + pctx.fillRect(x + inset, y + inset, 2, PREVIEW_CELL - inset * 2); + pctx.fillStyle = "rgba(0,0,0,0.25)"; + pctx.fillRect(x + inset, y + PREVIEW_CELL - inset - 2, PREVIEW_CELL - inset * 2, 2); + pctx.fillRect(x + PREVIEW_CELL - inset - 2, y + inset, 2, PREVIEW_CELL - inset * 2); + } + } + } +} +// ----- Bootstrap -------------------------------------------- +window.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,569 @@ +"use strict"; +// ── Types & Constants ────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 30; +const PREVIEW_BLOCK = 20; +const LINES_PER_LEVEL = 10; +const BASE_SPEED = 800; // ms per drop at level 1 +const SPEED_FACTOR = 0.85; // multiplied each level +const MIN_SPEED = 50; +const LOCK_DELAY = 500; // ms before piece locks after landing +const MAX_LOCK_RESETS = 15; +// SRS kick tables ───────────────────────────────────────────────── +// Wall-kick data for J, L, S, T, Z (non-I) pieces +const KICK_DATA_JLSTZ = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// Wall-kick data for I piece +const KICK_DATA_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// Tetromino definitions (spawn orientation = state 0) ──────────── +const TETROMINOES = [ + { name: "I", color: "#00f0f0", shape: [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]] }, + { name: "O", color: "#f0f000", shape: [[1, 1], [1, 1]] }, + { name: "T", color: "#a000f0", shape: [[0, 1, 0], [1, 1, 1], [0, 0, 0]] }, + { name: "S", color: "#00f000", shape: [[0, 1, 1], [1, 1, 0], [0, 0, 0]] }, + { name: "Z", color: "#f00000", shape: [[1, 1, 0], [0, 1, 1], [0, 0, 0]] }, + { name: "J", color: "#0000f0", shape: [[1, 0, 0], [1, 1, 1], [0, 0, 0]] }, + { name: "L", color: "#f0a000", shape: [[0, 0, 1], [1, 1, 1], [0, 0, 0]] }, +]; +// ── Helpers ───────────────────────────────────────────────────────── +function createGrid() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function rotateCW(shape) { + const n = shape.length; + return shape.map((_, i) => shape.map((_, j) => shape[n - 1 - j][i])); +} +function rotateCCW(shape) { + const n = shape.length; + return shape.map((_, i) => shape.map((_, j) => shape[j][n - 1 - i])); +} +// ── Bag-random piece generator ────────────────────────────────────── +function createBag() { + const bag = [0, 1, 2, 3, 4, 5, 6]; + for (let i = bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [bag[i], bag[j]] = [bag[j], bag[i]]; + } + return bag; +} +// ── Game Class ────────────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.grid = createGrid(); + this.currentRotation = 0; + this.currentIndex = -1; // index into TETROMINOES + this.bag = []; + this.nextIndices = []; + this.holdIndex = null; + this.holdUsed = false; + this.score = 0; + this.level = 1; + this.lines = 0; + this.combo = -1; + this.dropInterval = BASE_SPEED; + this.lastDrop = 0; + this.animationId = 0; + this.gameOver = false; + this.paused = false; + // Lock-delay state + this.lockTimer = null; + this.lockResets = 0; + this.isOnGround = false; + // Soft-drop tracking + this.softDropping = false; + // Ghost + this.ghostY = 0; + // ── Game Loop ──────────────────────────────────────────────────── + this.loop = (now) => { + this.animationId = requestAnimationFrame(this.loop); + if (this.gameOver) { + this.draw(); + return; + } + if (this.paused) { + this.draw(); + return; + } + // Gravity + const interval = this.softDropping ? this.dropInterval / 10 : this.dropInterval; + if (now - this.lastDrop > interval) { + if (!this.move(0, 1)) { + // piece can't move down + } + else if (this.softDropping) { + this.score += 1; + } + this.lastDrop = now; + } + // Lock delay check + this.checkLanding(); + if (this.isOnGround && this.lockTimer !== null && now - this.lockTimer >= LOCK_DELAY) { + this.lockPiece(); + } + this.draw(); + }; + this.canvas = document.getElementById("board"); + this.ctx = this.canvas.getContext("2d"); + this.canvas.width = COLS * BLOCK_SIZE; + this.canvas.height = ROWS * BLOCK_SIZE; + this.previewCanvas = document.getElementById("preview"); + this.previewCtx = this.previewCanvas.getContext("2d"); + this.holdCanvas = document.getElementById("hold"); + this.holdCtx = this.holdCanvas.getContext("2d"); + this.scoreEl = document.getElementById("score"); + this.levelEl = document.getElementById("level"); + this.linesEl = document.getElementById("lines"); + this.bindKeys(); + this.fillQueue(); + this.spawnPiece(); + this.lastDrop = performance.now(); + this.loop(performance.now()); + } + // ── Bag / Queue ────────────────────────────────────────────────── + refillBag() { + if (this.bag.length === 0) + this.bag = createBag(); + } + pullFromBag() { + this.refillBag(); + return this.bag.pop(); + } + fillQueue() { + while (this.nextIndices.length < 3) { + this.nextIndices.push(this.pullFromBag()); + } + } + // ── Piece Spawning ─────────────────────────────────────────────── + spawnPiece() { + this.currentIndex = this.nextIndices.shift(); + this.fillQueue(); + const t = TETROMINOES[this.currentIndex]; + this.current = { + shape: t.shape.map(r => [...r]), + color: t.color, + x: Math.floor((COLS - t.shape[0].length) / 2), + y: 0, + }; + this.currentRotation = 0; + this.holdUsed = false; + this.lockTimer = null; + this.lockResets = 0; + this.isOnGround = false; + this.updateGhost(); + if (!this.isValid(this.current.shape, this.current.x, this.current.y)) { + this.gameOver = true; + } + } + // ── Collision ──────────────────────────────────────────────────── + isValid(shape, px, py) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = px + c; + const ny = py + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return false; + if (ny >= 0 && this.grid[ny][nx] !== null) + return false; + } + } + return true; + } + // ── Movement ───────────────────────────────────────────────────── + move(dx, dy) { + if (this.isValid(this.current.shape, this.current.x + dx, this.current.y + dy)) { + this.current.x += dx; + this.current.y += dy; + this.updateGhost(); + this.resetLockIfNeeded(); + return true; + } + return false; + } + // ── SRS Rotation ───────────────────────────────────────────────── + rotate(direction) { + const newShape = direction === 1 + ? rotateCW(this.current.shape) + : rotateCCW(this.current.shape); + const newRot = ((this.currentRotation + direction) % 4 + 4) % 4; + const key = `${this.currentRotation}>${newRot}`; + const isI = TETROMINOES[this.currentIndex].name === "I"; + const isO = TETROMINOES[this.currentIndex].name === "O"; + if (isO) + return; // O doesn't rotate + const kicks = (isI ? KICK_DATA_I : KICK_DATA_JLSTZ)[key]; + if (!kicks) + return; + for (const [kx, ky] of kicks) { + if (this.isValid(newShape, this.current.x + kx, this.current.y - ky)) { + this.current.shape = newShape; + this.current.x += kx; + this.current.y -= ky; + this.currentRotation = newRot; + this.updateGhost(); + this.resetLockIfNeeded(); + return; + } + } + } + // ── Lock Delay ─────────────────────────────────────────────────── + resetLockIfNeeded() { + if (this.isOnGround && this.lockResets < MAX_LOCK_RESETS) { + this.lockTimer = performance.now(); + this.lockResets++; + } + } + checkLanding() { + const onGround = !this.isValid(this.current.shape, this.current.x, this.current.y + 1); + if (onGround && !this.isOnGround) { + this.isOnGround = true; + this.lockTimer = performance.now(); + } + else if (!onGround) { + this.isOnGround = false; + this.lockTimer = null; + } + } + // ── Ghost ──────────────────────────────────────────────────────── + updateGhost() { + let gy = this.current.y; + while (this.isValid(this.current.shape, this.current.x, gy + 1)) + gy++; + this.ghostY = gy; + } + // ── Hard Drop ──────────────────────────────────────────────────── + hardDrop() { + let dropped = 0; + while (this.isValid(this.current.shape, this.current.x, this.current.y + 1)) { + this.current.y++; + dropped++; + } + this.score += dropped * 2; + this.lockPiece(); + } + // ── Lock & Clear ───────────────────────────────────────────────── + lockPiece() { + const { shape, color, x, y } = this.current; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const ny = y + r; + const nx = x + c; + if (ny < 0) { + this.gameOver = true; + return; + } + this.grid[ny][nx] = color; + } + } + this.clearLines(); + this.spawnPiece(); + } + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.grid[r].every(c => c !== null)) { + this.grid.splice(r, 1); + this.grid.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check row + } + } + if (cleared > 0) { + this.combo++; + const basePoints = [0, 100, 300, 500, 800][cleared] ?? 800; + this.score += basePoints * this.level; + if (this.combo > 0) { + this.score += 50 * this.combo * this.level; + } + this.lines += cleared; + this.level = Math.floor(this.lines / LINES_PER_LEVEL) + 1; + this.dropInterval = Math.max(MIN_SPEED, BASE_SPEED * Math.pow(SPEED_FACTOR, this.level - 1)); + } + else { + this.combo = -1; + } + } + // ── Hold ───────────────────────────────────────────────────────── + holdPiece() { + if (this.holdUsed) + return; + this.holdUsed = true; + const prevHold = this.holdIndex; + this.holdIndex = this.currentIndex; + if (prevHold !== null) { + const t = TETROMINOES[prevHold]; + this.currentIndex = prevHold; + this.current = { + shape: t.shape.map(r => [...r]), + color: t.color, + x: Math.floor((COLS - t.shape[0].length) / 2), + y: 0, + }; + this.currentRotation = 0; + this.lockTimer = null; + this.lockResets = 0; + this.isOnGround = false; + this.updateGhost(); + } + else { + this.spawnPiece(); + } + } + // ── Input ──────────────────────────────────────────────────────── + bindKeys() { + document.addEventListener("keydown", (e) => { + if (this.gameOver) { + if (e.key === "r" || e.key === "R") + this.restart(); + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.paused = !this.paused; + if (!this.paused) { + this.lastDrop = performance.now(); + } + return; + } + if (this.paused) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + this.move(-1, 0); + break; + case "ArrowRight": + case "d": + this.move(1, 0); + break; + case "ArrowDown": + case "s": + if (this.move(0, 1)) + this.score += 1; // soft drop + this.softDropping = true; + this.lastDrop = performance.now(); + break; + case "ArrowUp": + case "w": + this.rotate(1); // CW + break; + case "z": + case "Z": + this.rotate(-1); // CCW + break; + case " ": + this.hardDrop(); + break; + case "c": + case "C": + case "Shift": + this.holdPiece(); + break; + } + e.preventDefault(); + }); + document.addEventListener("keyup", (e) => { + if (e.key === "ArrowDown" || e.key === "s") { + this.softDropping = false; + } + }); + } + // ── Restart ────────────────────────────────────────────────────── + restart() { + this.grid = createGrid(); + this.score = 0; + this.level = 1; + this.lines = 0; + this.combo = -1; + this.dropInterval = BASE_SPEED; + this.gameOver = false; + this.paused = false; + this.holdIndex = null; + this.holdUsed = false; + this.bag = []; + this.nextIndices = []; + this.fillQueue(); + this.spawnPiece(); + this.lastDrop = performance.now(); + } + // ── Rendering ──────────────────────────────────────────────────── + drawBlock(ctx, x, y, size, color, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size, y * size, size, size); + // highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x * size, y * size, size, size * 0.15); + ctx.fillRect(x * size, y * size, size * 0.15, size); + // shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x * size, y * size + size * 0.85, size, size * 0.15); + ctx.fillRect(x * size + size * 0.85, y * size, size * 0.15, size); + // border + ctx.strokeStyle = "rgba(0,0,0,0.3)"; + ctx.lineWidth = 1; + ctx.strokeRect(x * size + 0.5, y * size + 0.5, size - 1, size - 1); + ctx.globalAlpha = 1; + } + draw() { + const { ctx, canvas } = this; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + ctx.lineWidth = 1; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(canvas.width, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, canvas.height); + ctx.stroke(); + } + // Placed blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.grid[r][c]) { + this.drawBlock(ctx, c, r, BLOCK_SIZE, this.grid[r][c]); + } + } + } + if (!this.gameOver) { + // Ghost piece + const { shape, x } = this.current; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + this.drawBlock(ctx, x + c, this.ghostY + r, BLOCK_SIZE, this.current.color, 0.2); + } + } + // Current piece + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + this.drawBlock(ctx, x + c, this.current.y + r, BLOCK_SIZE, this.current.color); + } + } + } + // Preview (next 3) + this.drawPreview(); + // Hold + this.drawHold(); + // HUD + this.scoreEl.textContent = this.score.toString(); + this.levelEl.textContent = this.level.toString(); + this.linesEl.textContent = this.lines.toString(); + // Overlays + if (this.paused) { + ctx.fillStyle = "rgba(0,0,0,0.6)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px 'Segoe UI', sans-serif"; + ctx.textAlign = "center"; + ctx.fillText("PAUSED", canvas.width / 2, canvas.height / 2); + } + if (this.gameOver) { + ctx.fillStyle = "rgba(0,0,0,0.7)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "#ff4444"; + ctx.font = "bold 32px 'Segoe UI', sans-serif"; + ctx.textAlign = "center"; + ctx.fillText("GAME OVER", canvas.width / 2, canvas.height / 2 - 20); + ctx.fillStyle = "#ccc"; + ctx.font = "18px 'Segoe UI', sans-serif"; + ctx.fillText("Press R to restart", canvas.width / 2, canvas.height / 2 + 20); + } + } + drawMiniPiece(ctx, index, offsetX, offsetY, blockSize) { + const t = TETROMINOES[index]; + const shape = t.shape; + // center the piece in the box + const w = shape[0].length; + const h = shape.length; + // find actual bounding box of filled cells + let minR = h, maxR = 0, minC = w, maxC = 0; + for (let r = 0; r < h; r++) { + for (let c = 0; c < w; c++) { + if (shape[r][c]) { + minR = Math.min(minR, r); + maxR = Math.max(maxR, r); + minC = Math.min(minC, c); + maxC = Math.max(maxC, c); + } + } + } + const pw = maxC - minC + 1; + const ph = maxR - minR + 1; + const ox = offsetX + (4 * blockSize - pw * blockSize) / 2 - minC * blockSize; + const oy = offsetY + (2 * blockSize - ph * blockSize) / 2 - minR * blockSize; + for (let r = 0; r < h; r++) { + for (let c = 0; c < w; c++) { + if (!shape[r][c]) + continue; + const bx = ox + c * blockSize; + const by = oy + r * blockSize; + ctx.fillStyle = t.color; + ctx.fillRect(bx, by, blockSize, blockSize); + ctx.strokeStyle = "rgba(0,0,0,0.3)"; + ctx.lineWidth = 1; + ctx.strokeRect(bx + 0.5, by + 0.5, blockSize - 1, blockSize - 1); + ctx.fillStyle = "rgba(255,255,255,0.2)"; + ctx.fillRect(bx, by, blockSize, blockSize * 0.15); + ctx.fillRect(bx, by, blockSize * 0.15, blockSize); + } + } + } + drawPreview() { + const ctx = this.previewCtx; + const cvs = this.previewCanvas; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, cvs.width, cvs.height); + for (let i = 0; i < 3 && i < this.nextIndices.length; i++) { + this.drawMiniPiece(ctx, this.nextIndices[i], 5, i * 55 + 5, PREVIEW_BLOCK); + } + } + drawHold() { + const ctx = this.holdCtx; + const cvs = this.holdCanvas; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, cvs.width, cvs.height); + if (this.holdIndex !== null) { + const alpha = this.holdUsed ? 0.4 : 1.0; + ctx.globalAlpha = alpha; + this.drawMiniPiece(ctx, this.holdIndex, 5, 5, PREVIEW_BLOCK); + ctx.globalAlpha = 1; + } + } +} +// ── Bootstrap ────────────────────────────────────────────────────── +window.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,594 @@ +"use strict"; +// ────────────────────────────────────────────── +// Types & Constants +// ────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const CELL_SIZE = 32; +const PREVIEW_CELLS = 4; +const LOCK_DELAY_MS = 500; +// SRS-style shapes: each is an array of rotations, each rotation is an array of [row, col] offsets +const TETROMINOES = { + I: { + color: "#00f0f0", + rotations: [ + [[0, 0], [0, 1], [0, 2], [0, 3]], + [[0, 2], [1, 2], [2, 2], [3, 2]], + [[2, 0], [2, 1], [2, 2], [2, 3]], + [[0, 1], [1, 1], [2, 1], [3, 1]], + ], + }, + O: { + color: "#f0f000", + rotations: [ + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + ], + }, + T: { + color: "#a000f0", + rotations: [ + [[0, 1], [1, 0], [1, 1], [1, 2]], + [[0, 0], [1, 0], [1, 1], [2, 0]], + [[0, 0], [0, 1], [0, 2], [1, 1]], + [[0, 1], [1, 0], [1, 1], [2, 1]], + ], + }, + S: { + color: "#00f000", + rotations: [ + [[0, 1], [0, 2], [1, 0], [1, 1]], + [[0, 0], [1, 0], [1, 1], [2, 1]], + [[1, 1], [1, 2], [2, 0], [2, 1]], + [[0, 0], [1, 0], [1, 1], [2, 1]], + ], + }, + Z: { + color: "#f00000", + rotations: [ + [[0, 0], [0, 1], [1, 1], [1, 2]], + [[0, 1], [1, 0], [1, 1], [2, 0]], + [[1, 0], [1, 1], [2, 1], [2, 2]], + [[0, 1], [1, 0], [1, 1], [2, 0]], + ], + }, + J: { + color: "#0000f0", + rotations: [ + [[0, 0], [1, 0], [1, 1], [1, 2]], + [[0, 0], [0, 1], [1, 0], [2, 0]], + [[0, 0], [0, 1], [0, 2], [1, 2]], + [[0, 1], [1, 1], [2, 0], [2, 1]], + ], + }, + L: { + color: "#f0a000", + rotations: [ + [[0, 2], [1, 0], [1, 1], [1, 2]], + [[0, 0], [1, 0], [2, 0], [2, 1]], + [[0, 0], [0, 1], [0, 2], [1, 0]], + [[0, 0], [0, 1], [1, 1], [2, 1]], + ], + }, +}; +// SRS wall-kick data (non-I pieces) +const WALL_KICKS = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// I-piece wall-kick data +const WALL_KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +const PIECE_KEYS = Object.keys(TETROMINOES); +// ────────────────────────────────────────────── +// Piece class +// ────────────────────────────────────────────── +class Piece { + constructor(type) { + this.type = type; + this.rotation = 0; + // Spawn centred at the top + this.pos = { x: Math.floor(COLS / 2) - 1, y: 0 }; + } + get data() { + return TETROMINOES[this.type]; + } + get cells() { + return this.data.rotations[this.rotation]; + } + get color() { + return this.data.color; + } +} +// ────────────────────────────────────────────── +// Game class +// ────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.current = null; + this.next = null; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.bag = []; + this.dropInterval = 1000; // ms + this.lastDrop = 0; + this.lockTimer = null; + this.animationId = 0; + // DAS / auto-repeat + this.keysDown = new Set(); + this.dasTimer = {}; + this.DAS = 170; // ms before auto-repeat starts + this.ARR = 50; // ms between auto-repeats + // ── Game loop ────────────────────────────── + this.loop = (now) => { + this.animationId = requestAnimationFrame(this.loop); + if (this.gameOver || this.paused) { + this.draw(); + return; + } + if (now - this.lastDrop > this.dropInterval) { + if (!this.moveDown()) { + // piece is on the ground — start lock timer if not already + this.startLockTimer(); + } + this.lastDrop = now; + } + this.draw(); + }; + const gameCanvas = document.getElementById("game-canvas"); + const previewCanvas = document.getElementById("preview-canvas"); + gameCanvas.width = COLS * CELL_SIZE; + gameCanvas.height = ROWS * CELL_SIZE; + previewCanvas.width = PREVIEW_CELLS * CELL_SIZE; + previewCanvas.height = PREVIEW_CELLS * CELL_SIZE; + this.ctx = gameCanvas.getContext("2d"); + this.previewCtx = previewCanvas.getContext("2d"); + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.overlayEl = document.getElementById("overlay"); + this.overlayMsg = document.getElementById("overlay-msg"); + this.board = this.createBoard(); + this.bindKeys(); + } + // ── Board helpers ────────────────────────── + createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); + } + isInsideBoard(x, y) { + return x >= 0 && x < COLS && y >= 0 && y < ROWS; + } + isOccupied(x, y) { + return !this.isInsideBoard(x, y) || this.board[y][x] !== null; + } + canPlace(piece, offsetX = 0, offsetY = 0, rotationOverride) { + const cells = rotationOverride !== undefined + ? piece.data.rotations[rotationOverride] + : piece.cells; + for (const [r, c] of cells) { + const nx = piece.pos.x + c + offsetX; + const ny = piece.pos.y + r + offsetY; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return false; + if (ny < 0) + continue; // allow above board + if (this.board[ny][nx] !== null) + return false; + } + return true; + } + // ── Bag randomiser (7-bag) ───────────────── + refillBag() { + const bag = [...PIECE_KEYS]; + for (let i = bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [bag[i], bag[j]] = [bag[j], bag[i]]; + } + this.bag = bag; + } + nextPieceType() { + if (this.bag.length === 0) + this.refillBag(); + return this.bag.pop(); + } + // ── Piece spawning ───────────────────────── + spawnPiece() { + if (this.next === null) { + this.next = new Piece(this.nextPieceType()); + } + this.current = this.next; + this.next = new Piece(this.nextPieceType()); + // Reset position for the new current piece + this.current.pos = { x: Math.floor(COLS / 2) - 1, y: 0 }; + this.current.rotation = 0; + if (!this.canPlace(this.current)) { + this.gameOver = true; + this.showOverlay("GAME OVER<br><small>Press R to restart</small>"); + } + } + // ── Movement ─────────────────────────────── + moveLeft() { + if (!this.current || this.gameOver || this.paused) + return; + if (this.canPlace(this.current, -1, 0)) { + this.current.pos.x -= 1; + this.resetLockTimer(); + } + } + moveRight() { + if (!this.current || this.gameOver || this.paused) + return; + if (this.canPlace(this.current, 1, 0)) { + this.current.pos.x += 1; + this.resetLockTimer(); + } + } + moveDown() { + if (!this.current || this.gameOver || this.paused) + return false; + if (this.canPlace(this.current, 0, 1)) { + this.current.pos.y += 1; + return true; + } + return false; + } + softDrop() { + if (this.moveDown()) { + this.score += 1; + this.scoreEl.textContent = String(this.score); + } + } + hardDrop() { + if (!this.current || this.gameOver || this.paused) + return; + let distance = 0; + while (this.canPlace(this.current, 0, distance + 1)) { + distance++; + } + this.current.pos.y += distance; + this.score += distance * 2; + this.scoreEl.textContent = String(this.score); + this.lockPiece(); + } + // ── Rotation with SRS wall kicks ────────── + rotate(dir) { + if (!this.current || this.gameOver || this.paused) + return; + const oldR = this.current.rotation; + const newR = (oldR + dir + 4) % 4; + const kickTable = this.current.type === "I" ? WALL_KICKS_I : WALL_KICKS; + const key = `${oldR}>${newR}`; + const kicks = kickTable[key] || [[0, 0]]; + for (const [dx, dy] of kicks) { + if (this.canPlace(this.current, dx, -dy, newR)) { + this.current.pos.x += dx; + this.current.pos.y -= dy; + this.current.rotation = newR; + this.resetLockTimer(); + return; + } + } + } + // ── Locking & line clearing ──────────────── + lockPiece() { + if (!this.current) + return; + this.clearLockTimer(); + for (const [r, c] of this.current.cells) { + const bx = this.current.pos.x + c; + const by = this.current.pos.y + r; + if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) { + this.board[by][bx] = this.current.color; + } + } + const cleared = this.clearLines(); + this.updateScore(cleared); + this.spawnPiece(); + this.lastDrop = performance.now(); + } + clearLines() { + let cleared = 0; + for (let y = ROWS - 1; y >= 0; y--) { + if (this.board[y].every((c) => c !== null)) { + this.board.splice(y, 1); + this.board.unshift(Array(COLS).fill(null)); + cleared++; + y++; // recheck this row + } + } + return cleared; + } + updateScore(linesCleared) { + const points = [0, 100, 300, 500, 800]; + this.score += (points[linesCleared] || 0) * this.level; + this.lines += linesCleared; + this.level = Math.floor(this.lines / 10) + 1; + this.dropInterval = Math.max(50, 1000 - (this.level - 1) * 75); + this.scoreEl.textContent = String(this.score); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + } + // ── Lock delay ───────────────────────────── + startLockTimer() { + if (this.lockTimer !== null) + return; + this.lockTimer = window.setTimeout(() => { + this.lockPiece(); + this.lockTimer = null; + }, LOCK_DELAY_MS); + } + clearLockTimer() { + if (this.lockTimer !== null) { + clearTimeout(this.lockTimer); + this.lockTimer = null; + } + } + resetLockTimer() { + // If the piece is on the ground, restart lock timer on successful move + if (this.current && !this.canPlace(this.current, 0, 1)) { + this.clearLockTimer(); + this.startLockTimer(); + } + } + // ── Ghost piece ──────────────────────────── + getGhostY() { + if (!this.current) + return 0; + let ghostDy = 0; + while (this.canPlace(this.current, 0, ghostDy + 1)) { + ghostDy++; + } + return this.current.pos.y + ghostDy; + } + // ── Drawing ──────────────────────────────── + drawCell(ctx, x, y, color, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * CELL_SIZE + 1, y * CELL_SIZE + 1, CELL_SIZE - 2, CELL_SIZE - 2); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x * CELL_SIZE + 1, y * CELL_SIZE + 1, CELL_SIZE - 2, 4); + ctx.fillRect(x * CELL_SIZE + 1, y * CELL_SIZE + 1, 4, CELL_SIZE - 2); + // Shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x * CELL_SIZE + 1, y * CELL_SIZE + CELL_SIZE - 5, CELL_SIZE - 2, 4); + ctx.fillRect(x * CELL_SIZE + CELL_SIZE - 5, y * CELL_SIZE + 1, 4, CELL_SIZE - 2); + ctx.globalAlpha = 1; + } + drawBoard() { + const { ctx } = this; + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, COLS * CELL_SIZE, ROWS * CELL_SIZE); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let x = 0; x <= COLS; x++) { + ctx.beginPath(); + ctx.moveTo(x * CELL_SIZE, 0); + ctx.lineTo(x * CELL_SIZE, ROWS * CELL_SIZE); + ctx.stroke(); + } + for (let y = 0; y <= ROWS; y++) { + ctx.beginPath(); + ctx.moveTo(0, y * CELL_SIZE); + ctx.lineTo(COLS * CELL_SIZE, y * CELL_SIZE); + ctx.stroke(); + } + // Locked cells + for (let y = 0; y < ROWS; y++) { + for (let x = 0; x < COLS; x++) { + if (this.board[y][x]) { + this.drawCell(ctx, x, y, this.board[y][x]); + } + } + } + } + drawGhost() { + if (!this.current) + return; + const ghostY = this.getGhostY(); + for (const [r, c] of this.current.cells) { + const gx = this.current.pos.x + c; + const gy = ghostY + r; + if (gy >= 0) { + this.drawCell(this.ctx, gx, gy, this.current.color, 0.2); + } + } + } + drawCurrent() { + if (!this.current) + return; + for (const [r, c] of this.current.cells) { + const px = this.current.pos.x + c; + const py = this.current.pos.y + r; + if (py >= 0) { + this.drawCell(this.ctx, px, py, this.current.color); + } + } + } + drawPreview() { + const { previewCtx: ctx } = this; + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, PREVIEW_CELLS * CELL_SIZE, PREVIEW_CELLS * CELL_SIZE); + if (!this.next) + return; + const cells = this.next.data.rotations[0]; + // Centre the preview + let minC = 4, maxC = 0, minR = 4, maxR = 0; + for (const [r, c] of cells) { + minC = Math.min(minC, c); + maxC = Math.max(maxC, c); + minR = Math.min(minR, r); + maxR = Math.max(maxR, r); + } + const pw = maxC - minC + 1; + const ph = maxR - minR + 1; + const ox = (PREVIEW_CELLS - pw) / 2 - minC; + const oy = (PREVIEW_CELLS - ph) / 2 - minR; + for (const [r, c] of cells) { + this.drawCell(ctx, c + ox, r + oy, this.next.data.color); + } + } + draw() { + this.drawBoard(); + this.drawGhost(); + this.drawCurrent(); + this.drawPreview(); + } + // ── Overlay ──────────────────────────────── + showOverlay(msg) { + this.overlayMsg.innerHTML = msg; + this.overlayEl.style.display = "flex"; + } + hideOverlay() { + this.overlayEl.style.display = "none"; + } + // ── Input handling ───────────────────────── + bindKeys() { + document.addEventListener("keydown", (e) => { + if (e.repeat) + return; // we handle repeat ourselves via DAS + switch (e.code) { + case "ArrowLeft": + case "KeyA": + e.preventDefault(); + this.moveLeft(); + this.keysDown.add("left"); + this.dasTimer["left"] = window.setTimeout(() => { + this.dasTimer["left_repeat"] = window.setInterval(() => this.moveLeft(), this.ARR); + }, this.DAS); + break; + case "ArrowRight": + case "KeyD": + e.preventDefault(); + this.moveRight(); + this.keysDown.add("right"); + this.dasTimer["right"] = window.setTimeout(() => { + this.dasTimer["right_repeat"] = window.setInterval(() => this.moveRight(), this.ARR); + }, this.DAS); + break; + case "ArrowDown": + case "KeyS": + e.preventDefault(); + this.softDrop(); + this.keysDown.add("down"); + this.dasTimer["down"] = window.setTimeout(() => { + this.dasTimer["down_repeat"] = window.setInterval(() => this.softDrop(), this.ARR); + }, this.DAS); + break; + case "ArrowUp": + case "KeyX": + e.preventDefault(); + this.rotate(1); + break; + case "KeyZ": + case "ControlLeft": + case "ControlRight": + e.preventDefault(); + this.rotate(-1); + break; + case "Space": + e.preventDefault(); + this.hardDrop(); + break; + case "KeyP": + case "Escape": + e.preventDefault(); + this.togglePause(); + break; + case "KeyR": + e.preventDefault(); + if (this.gameOver || this.paused) { + this.restart(); + } + break; + } + }); + document.addEventListener("keyup", (e) => { + switch (e.code) { + case "ArrowLeft": + case "KeyA": + this.keysDown.delete("left"); + clearTimeout(this.dasTimer["left"]); + clearInterval(this.dasTimer["left_repeat"]); + break; + case "ArrowRight": + case "KeyD": + this.keysDown.delete("right"); + clearTimeout(this.dasTimer["right"]); + clearInterval(this.dasTimer["right_repeat"]); + break; + case "ArrowDown": + case "KeyS": + this.keysDown.delete("down"); + clearTimeout(this.dasTimer["down"]); + clearInterval(this.dasTimer["down_repeat"]); + break; + } + }); + } + togglePause() { + if (this.gameOver) + return; + this.paused = !this.paused; + if (this.paused) { + this.showOverlay("PAUSED<br><small>Press P to resume</small>"); + } + else { + this.hideOverlay(); + this.lastDrop = performance.now(); + } + } + // ── Public API ───────────────────────────── + start() { + this.restart(); + } + restart() { + this.board = this.createBoard(); + this.bag = []; + this.score = 0; + this.lines = 0; + this.level = 1; + this.dropInterval = 1000; + this.gameOver = false; + this.paused = false; + this.current = null; + this.next = null; + this.clearLockTimer(); + this.scoreEl.textContent = "0"; + this.linesEl.textContent = "0"; + this.levelEl.textContent = "1"; + this.hideOverlay(); + this.spawnPiece(); + this.lastDrop = performance.now(); + cancelAnimationFrame(this.animationId); + this.animationId = requestAnimationFrame(this.loop); + } +} +// ────────────────────────────────────────────── +// Bootstrap +// ────────────────────────────────────────────── +document.addEventListener("DOMContentLoaded", () => { + const game = new TetrisGame(); + game.start(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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AE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,C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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,440 @@ +"use strict"; +// ─── Types & Constants ─────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 30; +const PREVIEW_BLOCK = 20; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const PIECES = { + I: { shape: [[1, 1, 1, 1]], color: COLORS.I }, + O: { + shape: [ + [1, 1], + [1, 1], + ], + color: COLORS.O, + }, + T: { + shape: [ + [0, 1, 0], + [1, 1, 1], + ], + color: COLORS.T, + }, + S: { + shape: [ + [0, 1, 1], + [1, 1, 0], + ], + color: COLORS.S, + }, + Z: { + shape: [ + [1, 1, 0], + [0, 1, 1], + ], + color: COLORS.Z, + }, + J: { + shape: [ + [1, 0, 0], + [1, 1, 1], + ], + color: COLORS.J, + }, + L: { + shape: [ + [0, 0, 1], + [1, 1, 1], + ], + color: COLORS.L, + }, +}; +const PIECE_NAMES = Object.keys(PIECES); +// Wall-kick offsets for SRS (Super Rotation System) – simplified +const WALL_KICKS = [ + [0, 0], + [-1, 0], + [1, 0], + [-2, 0], + [2, 0], + [0, -1], + [0, -2], +]; +// Scoring per lines cleared at once (original Nintendo scoring × level) +const LINE_POINTS = [0, 100, 300, 500, 800]; +let board = []; +let currentPiece = null; +let nextPieceKey = ""; +let score = 0; +let level = 1; +let lines = 0; +let gameOver = false; +let paused = false; +let dropInterval = 1000; // ms +let lastDrop = 0; +let animationId = 0; +// ─── Canvas Setup ──────────────────────────────────────────────────── +const canvas = document.getElementById("game-canvas"); +const ctx = canvas.getContext("2d"); +canvas.width = COLS * BLOCK_SIZE; +canvas.height = ROWS * BLOCK_SIZE; +const previewCanvas = document.getElementById("preview-canvas"); +const previewCtx = previewCanvas.getContext("2d"); +previewCanvas.width = 4 * PREVIEW_BLOCK; +previewCanvas.height = 4 * PREVIEW_BLOCK; +const scoreEl = document.getElementById("score"); +const levelEl = document.getElementById("level"); +const linesEl = document.getElementById("lines"); +const messageEl = document.getElementById("message"); +// ─── Helpers ───────────────────────────────────────────────────────── +function randomPiece() { + return PIECE_NAMES[Math.floor(Math.random() * PIECE_NAMES.length)]; +} +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function cloneShape(shape) { + return shape.map((row) => [...row]); +} +function rotateShape(shape) { + const rows = shape.length; + const cols = shape[0].length; + const rotated = Array.from({ length: cols }, () => Array(rows).fill(0)); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + rotated[c][rows - 1 - r] = shape[r][c]; + } + } + return rotated; +} +function collides(shape, offX, offY) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const newX = offX + c; + const newY = offY + r; + if (newX < 0 || newX >= COLS || newY >= ROWS) + return true; + if (newY >= 0 && board[newY][newX] !== null) + return true; + } + } + return false; +} +// ─── Piece Management ──────────────────────────────────────────────── +function spawnPiece() { + const key = nextPieceKey || randomPiece(); + nextPieceKey = randomPiece(); + const def = PIECES[key]; + const shape = cloneShape(def.shape); + const x = Math.floor((COLS - shape[0].length) / 2); + const y = -shape.length; // start above the visible board + currentPiece = { shape, color: def.color, x, y }; + // If the piece immediately collides once it enters the top row, game over + if (collides(shape, x, y + 1) && y + 1 >= 0) { + lockPiece(); + gameOver = true; + } + drawPreview(); +} +function lockPiece() { + if (!currentPiece) + return; + const { shape, color, x, y } = currentPiece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const boardY = y + r; + const boardX = x + c; + if (boardY >= 0 && boardY < ROWS && boardX >= 0 && boardX < COLS) { + board[boardY][boardX] = color; + } + } + } + currentPiece = null; +} +function clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every((cell) => cell !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check this row index since rows shifted down + } + } + return cleared; +} +function ghostY() { + if (!currentPiece) + return 0; + let gy = currentPiece.y; + while (!collides(currentPiece.shape, currentPiece.x, gy + 1)) { + gy++; + } + return gy; +} +// ─── Drawing ───────────────────────────────────────────────────────── +function drawBlock(context, x, y, color, size, alpha = 1) { + context.globalAlpha = alpha; + context.fillStyle = color; + context.fillRect(x * size, y * size, size, size); + // Highlight (top-left bevel) + context.fillStyle = "rgba(255,255,255,0.3)"; + context.fillRect(x * size, y * size, size, 2); + context.fillRect(x * size, y * size, 2, size); + // Shadow (bottom-right bevel) + context.fillStyle = "rgba(0,0,0,0.3)"; + context.fillRect(x * size, (y + 1) * size - 2, size, 2); + context.fillRect((x + 1) * size - 2, y * size, 2, size); + // Grid line + context.strokeStyle = "rgba(0,0,0,0.15)"; + context.strokeRect(x * size, y * size, size, size); + context.globalAlpha = 1; +} +function draw() { + // Clear + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Draw grid lines + ctx.strokeStyle = "rgba(255,255,255,0.03)"; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(canvas.width, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, canvas.height); + ctx.stroke(); + } + // Board + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c]) { + drawBlock(ctx, c, r, board[r][c], BLOCK_SIZE); + } + } + } + // Ghost piece + if (currentPiece && !gameOver) { + const gy = ghostY(); + for (let r = 0; r < currentPiece.shape.length; r++) { + for (let c = 0; c < currentPiece.shape[r].length; c++) { + if (!currentPiece.shape[r][c]) + continue; + const drawY = gy + r; + if (drawY >= 0) { + drawBlock(ctx, currentPiece.x + c, drawY, currentPiece.color, BLOCK_SIZE, 0.2); + } + } + } + } + // Current piece + if (currentPiece) { + for (let r = 0; r < currentPiece.shape.length; r++) { + for (let c = 0; c < currentPiece.shape[r].length; c++) { + if (!currentPiece.shape[r][c]) + continue; + const drawY = currentPiece.y + r; + if (drawY >= 0) { + drawBlock(ctx, currentPiece.x + c, drawY, currentPiece.color, BLOCK_SIZE); + } + } + } + } +} +function drawPreview() { + previewCtx.fillStyle = "#1a1a2e"; + previewCtx.fillRect(0, 0, previewCanvas.width, previewCanvas.height); + const def = PIECES[nextPieceKey]; + if (!def) + return; + const shape = def.shape; + const offX = (4 - shape[0].length) / 2; + const offY = (4 - shape.length) / 2; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + drawBlock(previewCtx, offX + c, offY + r, def.color, PREVIEW_BLOCK); + } + } + } +} +function updateHUD() { + scoreEl.textContent = score.toString(); + levelEl.textContent = level.toString(); + linesEl.textContent = lines.toString(); +} +// ─── Game Logic ────────────────────────────────────────────────────── +function moveLeft() { + if (!currentPiece || gameOver || paused) + return; + if (!collides(currentPiece.shape, currentPiece.x - 1, currentPiece.y)) { + currentPiece.x--; + } +} +function moveRight() { + if (!currentPiece || gameOver || paused) + return; + if (!collides(currentPiece.shape, currentPiece.x + 1, currentPiece.y)) { + currentPiece.x++; + } +} +function moveDown() { + if (!currentPiece || gameOver || paused) + return false; + if (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) { + currentPiece.y++; + return true; + } + // Lock + lockPiece(); + const cleared = clearLines(); + if (cleared > 0) { + lines += cleared; + score += LINE_POINTS[cleared] * level; + // Level up every 10 lines + const newLevel = Math.floor(lines / 10) + 1; + if (newLevel > level) { + level = newLevel; + dropInterval = Math.max(100, 1000 - (level - 1) * 80); + } + } + updateHUD(); + spawnPiece(); + return false; +} +function hardDrop() { + if (!currentPiece || gameOver || paused) + return; + let dropCount = 0; + while (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) { + currentPiece.y++; + dropCount++; + } + score += dropCount * 2; + moveDown(); // lock +} +function rotatePiece() { + if (!currentPiece || gameOver || paused) + return; + const rotated = rotateShape(currentPiece.shape); + // Try wall-kick offsets + for (const [dx, dy] of WALL_KICKS) { + if (!collides(rotated, currentPiece.x + dx, currentPiece.y + dy)) { + currentPiece.shape = rotated; + currentPiece.x += dx; + currentPiece.y += dy; + return; + } + } +} +// ─── Input ─────────────────────────────────────────────────────────── +document.addEventListener("keydown", (e) => { + switch (e.key) { + case "ArrowLeft": + case "a": + e.preventDefault(); + moveLeft(); + break; + case "ArrowRight": + case "d": + e.preventDefault(); + moveRight(); + break; + case "ArrowDown": + case "s": + e.preventDefault(); + if (moveDown()) { + score += 1; // soft drop bonus + updateHUD(); + } + break; + case "ArrowUp": + case "w": + e.preventDefault(); + rotatePiece(); + break; + case " ": + e.preventDefault(); + hardDrop(); + break; + case "p": + case "Escape": + e.preventDefault(); + togglePause(); + break; + case "r": + if (gameOver) { + e.preventDefault(); + resetGame(); + } + break; + } +}); +// ─── Game Loop ─────────────────────────────────────────────────────── +function togglePause() { + if (gameOver) + return; + paused = !paused; + if (paused) { + messageEl.textContent = "PAUSED"; + messageEl.style.display = "block"; + } + else { + messageEl.style.display = "none"; + lastDrop = performance.now(); + animationId = requestAnimationFrame(gameLoop); + } +} +function gameLoop(timestamp) { + if (gameOver) { + messageEl.innerHTML = "GAME OVER<br><small>Press R to restart</small>"; + messageEl.style.display = "block"; + draw(); + return; + } + if (paused) { + return; + } + if (timestamp - lastDrop > dropInterval) { + moveDown(); + lastDrop = timestamp; + } + draw(); + animationId = requestAnimationFrame(gameLoop); +} +function resetGame() { + board = createBoard(); + score = 0; + level = 1; + lines = 0; + gameOver = false; + paused = false; + dropInterval = 1000; + lastDrop = performance.now(); + currentPiece = null; + nextPieceKey = ""; + messageEl.style.display = "none"; + updateHUD(); + spawnPiece(); + cancelAnimationFrame(animationId); + animationId = requestAnimationFrame(gameLoop); +} +// ─── Start ─────────────────────────────────────────────────────────── +resetGame(); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,598 @@ +"use strict"; +// ── Types ────────────────────────────────────────────────────────────────── +// ── Constants ────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 32; +const PREVIEW_BLOCK = 20; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const GHOST_ALPHA = 0.25; +const SHAPES = { + I: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + O: [ + [1, 1], + [1, 1], + ], + T: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + S: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + Z: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + J: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + L: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], +}; +// SRS wall-kick data (non-I pieces) +const WALL_KICKS = { + "0>1": [{ x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "1>0": [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], + "1>2": [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], + "2>1": [{ x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "2>3": [{ x: 1, y: 0 }, { x: 1, y: -1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], + "3>2": [{ x: -1, y: 0 }, { x: -1, y: 1 }, { x: 0, y: -2 }, { x: -1, y: -2 }], + "3>0": [{ x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "0>3": [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], +}; +// SRS wall-kick data for I-piece +const WALL_KICKS_I = { + "0>1": [{ x: -2, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 1 }, { x: 1, y: -2 }], + "1>0": [{ x: 2, y: 0 }, { x: -1, y: 0 }, { x: 2, y: -1 }, { x: -1, y: 2 }], + "1>2": [{ x: -1, y: 0 }, { x: 2, y: 0 }, { x: -1, y: -2 }, { x: 2, y: 1 }], + "2>1": [{ x: 1, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 2 }, { x: -2, y: -1 }], + "2>3": [{ x: 2, y: 0 }, { x: -1, y: 0 }, { x: 2, y: -1 }, { x: -1, y: 2 }], + "3>2": [{ x: -2, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 1 }, { x: 1, y: -2 }], + "3>0": [{ x: 1, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 2 }, { x: -2, y: -1 }], + "0>3": [{ x: -1, y: 0 }, { x: 2, y: 0 }, { x: -1, y: -2 }, { x: 2, y: 1 }], +}; +const LINE_SCORES = [0, 100, 300, 500, 800]; +const LINES_PER_LEVEL = 10; +// ── Helpers ──────────────────────────────────────────────────────────────── +function createGrid() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function rotateMatrix(matrix) { + const n = matrix.length; + const result = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + result[c][n - 1 - r] = matrix[r][c]; + } + } + return result; +} +function rotateMatrixCCW(matrix) { + const n = matrix.length; + const result = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + result[n - 1 - c][r] = matrix[r][c]; + } + } + return result; +} +// ── Game Class ───────────────────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.grid = createGrid(); + this.currentRotation = 0; + this.nextTypes = []; + this.heldType = null; + this.holdUsed = false; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.dropInterval = 1000; + this.lastDrop = 0; + this.lockDelay = 500; + this.lockTimer = 0; + this.isLocking = false; + this.animatingRows = []; + this.animationStart = 0; + this.ANIM_DURATION = 300; + this.bag = []; + this.canvas = document.getElementById("game-canvas"); + this.ctx = this.canvas.getContext("2d"); + this.canvas.width = COLS * BLOCK_SIZE; + this.canvas.height = ROWS * BLOCK_SIZE; + this.previewCanvas = document.getElementById("preview-canvas"); + this.previewCtx = this.previewCanvas.getContext("2d"); + this.previewCanvas.width = 6 * PREVIEW_BLOCK; + this.previewCanvas.height = 18 * PREVIEW_BLOCK; + this.holdCanvas = document.getElementById("hold-canvas"); + this.holdCtx = this.holdCanvas.getContext("2d"); + this.holdCanvas.width = 5 * PREVIEW_BLOCK; + this.holdCanvas.height = 4 * PREVIEW_BLOCK; + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.messageEl = document.getElementById("message"); + this.fillBag(); + this.nextTypes = [this.pullFromBag(), this.pullFromBag(), this.pullFromBag()]; + this.spawnPiece(); + this.bindControls(); + this.lastDrop = performance.now(); + requestAnimationFrame((t) => this.loop(t)); + } + // ── Bag randomiser ───────────────────────────────────────────────────── + fillBag() { + const types = Object.keys(SHAPES); + // Fisher–Yates shuffle + for (let i = types.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [types[i], types[j]] = [types[j], types[i]]; + } + this.bag = types; + } + pullFromBag() { + if (this.bag.length === 0) + this.fillBag(); + return this.bag.pop(); + } + // ── Piece spawning ───────────────────────────────────────────────────── + spawnPiece() { + const type = this.nextTypes.shift(); + this.nextTypes.push(this.pullFromBag()); + const shape = SHAPES[type]; + this.currentType = type; + this.currentRotation = 0; + this.current = { + shape: shape.map((r) => [...r]), + color: COLORS[type], + pos: { + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + }, + }; + // Move the piece up if it collides at spawn (allows two hidden rows) + if (this.collides(this.current.shape, this.current.pos)) { + this.current.pos.y = -1; + if (this.collides(this.current.shape, this.current.pos)) { + this.current.pos.y = -2; + if (this.collides(this.current.shape, this.current.pos)) { + this.gameOver = true; + this.messageEl.textContent = "GAME OVER – press R to restart"; + } + } + } + this.isLocking = false; + this.holdUsed = false; + } + // ── Collision detection ──────────────────────────────────────────────── + collides(shape, pos) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = pos.x + c; + const ny = pos.y + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && this.grid[ny][nx] !== null) + return true; + } + } + return false; + } + // ── Movement ─────────────────────────────────────────────────────────── + move(dx, dy) { + const newPos = { x: this.current.pos.x + dx, y: this.current.pos.y + dy }; + if (!this.collides(this.current.shape, newPos)) { + this.current.pos = newPos; + if (this.isLocking && dy === 0) { + // Reset lock timer on successful horizontal move + this.lockTimer = performance.now(); + } + return true; + } + return false; + } + rotate(dir) { + const oldShape = this.current.shape; + const oldRotation = this.currentRotation; + const newShape = dir === 1 ? rotateMatrix(oldShape) : rotateMatrixCCW(oldShape); + const newRotation = ((oldRotation + dir) % 4 + 4) % 4; + const kickKey = `${oldRotation}>${newRotation}`; + const isI = this.currentType === "I"; + const kicks = isI ? WALL_KICKS_I[kickKey] : WALL_KICKS[kickKey]; + // Test 0: no offset + if (!this.collides(newShape, this.current.pos)) { + this.current.shape = newShape; + this.currentRotation = newRotation; + if (this.isLocking) + this.lockTimer = performance.now(); + return; + } + // Tests 1–4: wall kicks + if (kicks) { + for (const kick of kicks) { + const testPos = { + x: this.current.pos.x + kick.x, + y: this.current.pos.y - kick.y, // SRS y is inverted + }; + if (!this.collides(newShape, testPos)) { + this.current.shape = newShape; + this.current.pos = testPos; + this.currentRotation = newRotation; + if (this.isLocking) + this.lockTimer = performance.now(); + return; + } + } + } + } + hardDrop() { + let rows = 0; + while (this.move(0, 1)) + rows++; + this.score += rows * 2; + this.lock(); + } + softDrop() { + if (this.move(0, 1)) { + this.score += 1; + return true; + } + return false; + } + // ── Ghost piece ──────────────────────────────────────────────────────── + ghostY() { + let gy = this.current.pos.y; + while (!this.collides(this.current.shape, { x: this.current.pos.x, y: gy + 1 })) { + gy++; + } + return gy; + } + // ── Lock & clear ────────────────────────────────────────────────────── + lock() { + const { shape, color, pos } = this.current; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const ny = pos.y + r; + const nx = pos.x + c; + if (ny < 0) { + this.gameOver = true; + this.messageEl.textContent = "GAME OVER – press R to restart"; + return; + } + this.grid[ny][nx] = color; + } + } + this.clearLines(); + } + clearLines() { + const full = []; + for (let r = 0; r < ROWS; r++) { + if (this.grid[r].every((c) => c !== null)) + full.push(r); + } + if (full.length > 0) { + this.animatingRows = full; + this.animationStart = performance.now(); + } + else { + this.spawnPiece(); + } + } + finishClear() { + const count = this.animatingRows.length; + // Remove rows top-to-bottom (highest index first) + for (const row of [...this.animatingRows].sort((a, b) => b - a)) { + this.grid.splice(row, 1); + this.grid.unshift(Array(COLS).fill(null)); + } + this.lines += count; + this.score += LINE_SCORES[count] * this.level; + this.level = Math.floor(this.lines / LINES_PER_LEVEL) + 1; + this.dropInterval = Math.max(50, 1000 - (this.level - 1) * 80); + this.animatingRows = []; + this.spawnPiece(); + } + // ── Hold ─────────────────────────────────────────────────────────────── + hold() { + if (this.holdUsed) + return; + this.holdUsed = true; + const prev = this.heldType; + this.heldType = this.currentType; + if (prev) { + const shape = SHAPES[prev]; + this.currentType = prev; + this.currentRotation = 0; + this.current = { + shape: shape.map((r) => [...r]), + color: COLORS[prev], + pos: { x: Math.floor((COLS - shape[0].length) / 2), y: 0 }, + }; + this.isLocking = false; + } + else { + this.spawnPiece(); + } + } + // ── Controls ─────────────────────────────────────────────────────────── + bindControls() { + document.addEventListener("keydown", (e) => { + if (e.key === "r" || e.key === "R") { + this.restart(); + return; + } + if (this.gameOver) + return; + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.paused = !this.paused; + this.messageEl.textContent = this.paused ? "PAUSED" : ""; + if (!this.paused) + this.lastDrop = performance.now(); + return; + } + if (this.paused) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + e.preventDefault(); + this.move(-1, 0); + break; + case "ArrowRight": + case "d": + e.preventDefault(); + this.move(1, 0); + break; + case "ArrowDown": + case "s": + e.preventDefault(); + this.softDrop(); + break; + case "ArrowUp": + case "x": + e.preventDefault(); + this.rotate(1); + break; + case "z": + case "Control": + e.preventDefault(); + this.rotate(-1); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + case "Shift": + case "c": + e.preventDefault(); + this.hold(); + break; + } + }); + } + // ── Restart ──────────────────────────────────────────────────────────── + restart() { + this.grid = createGrid(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.dropInterval = 1000; + this.gameOver = false; + this.paused = false; + this.heldType = null; + this.holdUsed = false; + this.animatingRows = []; + this.bag = []; + this.fillBag(); + this.nextTypes = [this.pullFromBag(), this.pullFromBag(), this.pullFromBag()]; + this.messageEl.textContent = ""; + this.spawnPiece(); + this.lastDrop = performance.now(); + } + // ── Game loop ────────────────────────────────────────────────────────── + loop(time) { + // Line-clear animation in progress + if (this.animatingRows.length > 0) { + if (time - this.animationStart >= this.ANIM_DURATION) { + this.finishClear(); + } + } + if (!this.gameOver && !this.paused && this.animatingRows.length === 0) { + // Auto-drop + if (time - this.lastDrop > this.dropInterval) { + if (!this.move(0, 1)) { + if (!this.isLocking) { + this.isLocking = true; + this.lockTimer = time; + } + } + else { + this.isLocking = false; + } + this.lastDrop = time; + } + // Lock delay + if (this.isLocking) { + // Check if still touching ground + if (!this.collides(this.current.shape, { + x: this.current.pos.x, + y: this.current.pos.y + 1, + })) { + this.isLocking = false; + } + else if (time - this.lockTimer >= this.lockDelay) { + this.lock(); + this.isLocking = false; + } + } + } + this.draw(time); + this.updateHUD(); + requestAnimationFrame((t) => this.loop(t)); + } + // ── Drawing ──────────────────────────────────────────────────────────── + draw(time) { + const ctx = this.ctx; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(COLS * BLOCK_SIZE, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.stroke(); + } + // Placed blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.grid[r][c]) { + // Flash animation for clearing rows + if (this.animatingRows.includes(r)) { + const progress = (time - this.animationStart) / this.ANIM_DURATION; + const flash = Math.sin(progress * Math.PI * 3); + ctx.fillStyle = flash > 0 ? "#fff" : this.grid[r][c]; + ctx.globalAlpha = 1 - progress * 0.5; + } + else { + ctx.fillStyle = this.grid[r][c]; + ctx.globalAlpha = 1; + } + this.drawBlock(ctx, c, r, BLOCK_SIZE); + ctx.globalAlpha = 1; + } + } + } + if (!this.gameOver && this.animatingRows.length === 0) { + // Ghost piece + const gy = this.ghostY(); + ctx.globalAlpha = GHOST_ALPHA; + for (let r = 0; r < this.current.shape.length; r++) { + for (let c = 0; c < this.current.shape[r].length; c++) { + if (!this.current.shape[r][c]) + continue; + const dr = gy + r; + if (dr < 0) + continue; + ctx.fillStyle = this.current.color; + this.drawBlock(ctx, this.current.pos.x + c, dr, BLOCK_SIZE); + } + } + ctx.globalAlpha = 1; + // Current piece + for (let r = 0; r < this.current.shape.length; r++) { + for (let c = 0; c < this.current.shape[r].length; c++) { + if (!this.current.shape[r][c]) + continue; + const dr = this.current.pos.y + r; + if (dr < 0) + continue; + ctx.fillStyle = this.current.color; + this.drawBlock(ctx, this.current.pos.x + c, dr, BLOCK_SIZE); + } + } + } + // Preview (next 3) + this.drawPreview(); + // Hold + this.drawHold(); + } + drawBlock(ctx, x, y, size, offsetX = 0, offsetY = 0) { + const px = offsetX + x * size; + const py = offsetY + y * size; + ctx.fillRect(px + 1, py + 1, size - 2, size - 2); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.18)"; + ctx.fillRect(px + 1, py + 1, size - 2, 4); + ctx.fillRect(px + 1, py + 1, 4, size - 2); + // Shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(px + size - 4, py + 1, 3, size - 2); + ctx.fillRect(px + 1, py + size - 4, size - 2, 3); + } + drawSmallPiece(ctx, type, offsetX, offsetY) { + const shape = SHAPES[type]; + ctx.fillStyle = COLORS[type]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + this.drawBlock(ctx, c, r, PREVIEW_BLOCK, offsetX, offsetY); + ctx.fillStyle = COLORS[type]; // reset after drawBlock changes it + } + } + } + } + drawPreview() { + const ctx = this.previewCtx; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, this.previewCanvas.width, this.previewCanvas.height); + for (let i = 0; i < this.nextTypes.length; i++) { + const type = this.nextTypes[i]; + const shape = SHAPES[type]; + const xOff = (this.previewCanvas.width - shape[0].length * PREVIEW_BLOCK) / 2; + const yOff = i * 6 * PREVIEW_BLOCK + (6 * PREVIEW_BLOCK - shape.length * PREVIEW_BLOCK) / 2; + this.drawSmallPiece(ctx, type, xOff, yOff); + } + } + drawHold() { + const ctx = this.holdCtx; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, this.holdCanvas.width, this.holdCanvas.height); + if (this.heldType) { + const shape = SHAPES[this.heldType]; + const xOff = (this.holdCanvas.width - shape[0].length * PREVIEW_BLOCK) / 2; + const yOff = (this.holdCanvas.height - shape.length * PREVIEW_BLOCK) / 2; + if (this.holdUsed) + ctx.globalAlpha = 0.4; + this.drawSmallPiece(ctx, this.heldType, xOff, yOff); + ctx.globalAlpha = 1; + } + } + updateHUD() { + this.scoreEl.textContent = this.score.toString(); + this.linesEl.textContent = this.lines.toString(); + this.levelEl.textContent = this.level.toString(); + } +} +// ── Bootstrap ────────────────────────────────────────────────────────────── +window.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,564 @@ +"use strict"; +// ── Types & Constants ────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 32; +const PREVIEW_BLOCK = 20; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const SHAPES = { + I: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + O: [ + [1, 1], + [1, 1], + ], + T: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + S: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + Z: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + J: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + L: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], +}; +// SRS wall-kick data (non-I pieces) +const WALL_KICKS = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// SRS wall-kick data (I piece) +const I_WALL_KICKS = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +const PIECE_NAMES = Object.keys(SHAPES); +const LINES_PER_LEVEL = 10; +const POINTS = [0, 100, 300, 500, 800]; // 0,1,2,3,4 lines +// ── Helpers ──────────────────────────────────────────────────────── +function rotateMatrix(matrix) { + const n = matrix.length; + const result = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + result[c][n - 1 - r] = matrix[r][c]; + } + } + return result; +} +function rotateMatrixCCW(matrix) { + const n = matrix.length; + const result = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + result[n - 1 - c][r] = matrix[r][c]; + } + } + return result; +} +// ── Game Class ───────────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.nextPieces = []; + this.heldPiece = null; + this.canHold = true; + this.bag = []; + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameOver = false; + this.paused = false; + this.started = false; + this.dropInterval = 1000; + this.lastDrop = 0; + this.animationId = 0; + this.lockDelay = 500; + this.lockTimer = null; + // ── Game loop ───────────────────────────────────────────────── + this.loop = (time) => { + if (this.gameOver || this.paused) + return; + // Gravity + if (time - this.lastDrop > this.dropInterval) { + if (!this.move(0, 1)) { + // Piece can't move down; start or check lock timer + if (this.lockTimer === null) { + this.lockTimer = time; + } + else if (time - this.lockTimer > this.lockDelay) { + this.lock(); + if (this.gameOver) + return; + } + } + else { + this.lockTimer = null; + } + this.lastDrop = time; + } + // Also check lock if piece is already sitting + if (this.lockTimer !== null && + this.collides(this.current.shape, this.current.x, this.current.y + 1)) { + if (time - this.lockTimer > this.lockDelay) { + this.lock(); + if (this.gameOver) + return; + } + } + this.drawBoard(); + this.drawPreview(); + this.drawHold(); + this.animationId = requestAnimationFrame(this.loop); + }; + this.canvas = document.getElementById("game-canvas"); + this.ctx = this.canvas.getContext("2d"); + this.canvas.width = COLS * BLOCK_SIZE; + this.canvas.height = ROWS * BLOCK_SIZE; + this.previewCanvas = document.getElementById("preview-canvas"); + this.previewCtx = this.previewCanvas.getContext("2d"); + this.previewCanvas.width = 6 * PREVIEW_BLOCK; + this.previewCanvas.height = 15 * PREVIEW_BLOCK; + this.holdCanvas = document.getElementById("hold-canvas"); + this.holdCtx = this.holdCanvas.getContext("2d"); + this.holdCanvas.width = 6 * PREVIEW_BLOCK; + this.holdCanvas.height = 4 * PREVIEW_BLOCK; + this.scoreEl = document.getElementById("score"); + this.levelEl = document.getElementById("level"); + this.linesEl = document.getElementById("lines"); + this.messageEl = document.getElementById("message"); + this.board = this.createBoard(); + document.addEventListener("keydown", (e) => this.handleKey(e)); + this.messageEl.textContent = "Press ENTER to start"; + this.drawBoard(); + } + // ── Board ───────────────────────────────────────────────────── + createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); + } + // ── Bag randomizer (7-bag) ──────────────────────────────────── + fillBag() { + const pieces = [...PIECE_NAMES]; + for (let i = pieces.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [pieces[i], pieces[j]] = [pieces[j], pieces[i]]; + } + this.bag = pieces; + } + nextFromBag() { + if (this.bag.length === 0) + this.fillBag(); + return this.bag.pop(); + } + // ── Piece spawning ──────────────────────────────────────────── + spawnPiece(name) { + // Fill next queue + while (this.nextPieces.length < 3) { + this.nextPieces.push(this.nextFromBag()); + } + const pieceName = name ?? this.nextPieces.shift(); + if (!name) { + this.nextPieces.push(this.nextFromBag()); + } + this.currentName = pieceName; + this.currentRotation = 0; + const shape = SHAPES[pieceName]; + this.current = { + shape: shape.map((row) => [...row]), + color: COLORS[pieceName], + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + }; + if (this.collides(this.current.shape, this.current.x, this.current.y)) { + this.gameOver = true; + this.messageEl.textContent = "GAME OVER – Press ENTER to restart"; + cancelAnimationFrame(this.animationId); + } + this.canHold = true; + this.lockTimer = null; + } + // ── Collision detection ─────────────────────────────────────── + collides(shape, px, py) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const nx = px + c; + const ny = py + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && this.board[ny][nx] !== null) + return true; + } + } + } + return false; + } + // ── Movement ────────────────────────────────────────────────── + move(dx, dy) { + const nx = this.current.x + dx; + const ny = this.current.y + dy; + if (!this.collides(this.current.shape, nx, ny)) { + this.current.x = nx; + this.current.y = ny; + // Reset lock timer on successful move if piece is on ground + if (dy === 0 && this.lockTimer !== null) { + this.lockTimer = performance.now(); + } + return true; + } + return false; + } + rotate(clockwise) { + const oldRotation = this.currentRotation; + const newRotation = clockwise + ? (this.currentRotation + 1) % 4 + : (this.currentRotation + 3) % 4; + const newShape = clockwise + ? rotateMatrix(this.current.shape) + : rotateMatrixCCW(this.current.shape); + const kickKey = `${oldRotation}>${newRotation}`; + const kicks = this.currentName === "I" + ? I_WALL_KICKS[kickKey] ?? [[0, 0]] + : WALL_KICKS[kickKey] ?? [[0, 0]]; + for (const [kx, ky] of kicks) { + if (!this.collides(newShape, this.current.x + kx, this.current.y - ky)) { + this.current.shape = newShape; + this.current.x += kx; + this.current.y -= ky; + this.currentRotation = newRotation; + // Reset lock timer on successful rotation + if (this.lockTimer !== null) { + this.lockTimer = performance.now(); + } + return; + } + } + } + hardDrop() { + let dropDistance = 0; + while (!this.collides(this.current.shape, this.current.x, this.current.y + 1)) { + this.current.y++; + dropDistance++; + } + this.score += dropDistance * 2; + this.lock(); + } + getGhostY() { + let gy = this.current.y; + while (!this.collides(this.current.shape, this.current.x, gy + 1)) { + gy++; + } + return gy; + } + // ── Hold ────────────────────────────────────────────────────── + hold() { + if (!this.canHold) + return; + this.canHold = false; + const prev = this.heldPiece; + this.heldPiece = this.currentName; + if (prev) { + this.spawnPiece(prev); + } + else { + this.spawnPiece(); + } + } + // ── Locking & Line clearing ─────────────────────────────────── + lock() { + const { shape, x, y, color } = this.current; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const ny = y + r; + const nx = x + c; + if (ny >= 0 && ny < ROWS && nx >= 0 && nx < COLS) { + this.board[ny][nx] = color; + } + } + } + } + this.lockTimer = null; + this.clearLines(); + this.spawnPiece(); + } + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every((cell) => cell !== null)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // recheck this row + } + } + if (cleared > 0) { + this.lines += cleared; + this.score += POINTS[cleared] * this.level; + const newLevel = Math.floor(this.lines / LINES_PER_LEVEL) + 1; + if (newLevel > this.level) { + this.level = newLevel; + this.dropInterval = Math.max(50, 1000 - (this.level - 1) * 75); + } + this.updateHUD(); + } + } + // ── Drawing ─────────────────────────────────────────────────── + drawBlock(ctx, x, y, color, size, ghost = false) { + if (ghost) { + ctx.strokeStyle = color; + ctx.lineWidth = 2; + ctx.globalAlpha = 0.35; + ctx.strokeRect(x * size + 1, y * size + 1, size - 2, size - 2); + ctx.globalAlpha = 1; + return; + } + // Main fill + ctx.fillStyle = color; + ctx.fillRect(x * size, y * size, size, size); + // Highlight (top-left bevel) + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x * size, y * size, size, 3); + ctx.fillRect(x * size, y * size, 3, size); + // Shadow (bottom-right bevel) + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x * size, (y + 1) * size - 3, size, 3); + ctx.fillRect((x + 1) * size - 3, y * size, 3, size); + // Border + ctx.strokeStyle = "rgba(0,0,0,0.4)"; + ctx.lineWidth = 1; + ctx.strokeRect(x * size, y * size, size, size); + } + drawBoard() { + const { ctx } = this; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + ctx.lineWidth = 1; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(COLS * BLOCK_SIZE, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.stroke(); + } + // Locked blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.board[r][c]) { + this.drawBlock(ctx, c, r, this.board[r][c], BLOCK_SIZE); + } + } + } + if (!this.current || this.gameOver) + return; + // Ghost piece + const ghostY = this.getGhostY(); + for (let r = 0; r < this.current.shape.length; r++) { + for (let c = 0; c < this.current.shape[r].length; c++) { + if (this.current.shape[r][c]) { + const dy = ghostY + r; + if (dy >= 0) { + this.drawBlock(ctx, this.current.x + c, dy, this.current.color, BLOCK_SIZE, true); + } + } + } + } + // Current piece + for (let r = 0; r < this.current.shape.length; r++) { + for (let c = 0; c < this.current.shape[r].length; c++) { + if (this.current.shape[r][c]) { + const dy = this.current.y + r; + if (dy >= 0) { + this.drawBlock(ctx, this.current.x + c, dy, this.current.color, BLOCK_SIZE); + } + } + } + } + } + drawPreview() { + const { previewCtx: ctx, previewCanvas: canvas } = this; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + for (let i = 0; i < this.nextPieces.length; i++) { + const name = this.nextPieces[i]; + const shape = SHAPES[name]; + const color = COLORS[name]; + const offsetY = i * 5 * PREVIEW_BLOCK; + const offsetX = Math.floor((6 - shape[0].length) / 2); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + this.drawBlock(ctx, offsetX + c, r + (offsetY / PREVIEW_BLOCK), color, PREVIEW_BLOCK); + } + } + } + } + } + drawHold() { + const { holdCtx: ctx, holdCanvas: canvas } = this; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + if (!this.heldPiece) + return; + const shape = SHAPES[this.heldPiece]; + const color = COLORS[this.heldPiece]; + const offsetX = Math.floor((6 - shape[0].length) / 2); + const alpha = this.canHold ? 1 : 0.35; + ctx.globalAlpha = alpha; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + this.drawBlock(ctx, offsetX + c, r, color, PREVIEW_BLOCK); + } + } + } + ctx.globalAlpha = 1; + } + updateHUD() { + this.scoreEl.textContent = this.score.toString(); + this.levelEl.textContent = this.level.toString(); + this.linesEl.textContent = this.lines.toString(); + } + // ── Input ───────────────────────────────────────────────────── + handleKey(e) { + if (e.key === "Enter") { + if (!this.started || this.gameOver) { + this.restart(); + return; + } + } + if (!this.started) + return; + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.togglePause(); + return; + } + if (this.gameOver || this.paused) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + e.preventDefault(); + this.move(-1, 0); + break; + case "ArrowRight": + case "d": + e.preventDefault(); + this.move(1, 0); + break; + case "ArrowDown": + case "s": + e.preventDefault(); + if (this.move(0, 1)) { + this.score += 1; // soft drop bonus + this.lastDrop = performance.now(); + } + break; + case "ArrowUp": + case "w": + e.preventDefault(); + this.rotate(true); + break; + case "z": + case "Z": + e.preventDefault(); + this.rotate(false); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + case "c": + case "C": + case "Shift": + e.preventDefault(); + this.hold(); + break; + } + } + togglePause() { + this.paused = !this.paused; + if (this.paused) { + this.messageEl.textContent = "PAUSED – Press P to resume"; + cancelAnimationFrame(this.animationId); + } + else { + this.messageEl.textContent = ""; + this.lastDrop = performance.now(); + this.animationId = requestAnimationFrame(this.loop); + } + } + restart() { + this.board = this.createBoard(); + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameOver = false; + this.paused = false; + this.started = true; + this.dropInterval = 1000; + this.heldPiece = null; + this.canHold = true; + this.nextPieces = []; + this.bag = []; + this.lockTimer = null; + this.messageEl.textContent = ""; + this.updateHUD(); + this.spawnPiece(); + this.lastDrop = performance.now(); + cancelAnimationFrame(this.animationId); + this.animationId = requestAnimationFrame(this.loop); + } +} +// ── Bootstrap ────────────────────────────────────────────────────── +document.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,561 @@ +"use strict"; +// ── Types & Constants ─────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const CELL = 32; // pixels per cell +const PREVIEW_CELLS = 4; +const LINES_PER_LEVEL = 10; +const LOCK_DELAY = 500; // ms before a landed piece locks +// SRS tetromino definitions: each has 4 rotation states +// Offsets are [row, col] relative to piece origin +const TETROMINOES = [ + { + shape: [ + [[0, 0], [0, 1], [0, 2], [0, 3]], + [[0, 2], [1, 2], [2, 2], [3, 2]], + [[2, 0], [2, 1], [2, 2], [2, 3]], + [[0, 1], [1, 1], [2, 1], [3, 1]], + ], + color: "#00f0f0", + }, + { + shape: [ + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + ], + color: "#f0f000", + }, + { + shape: [ + [[0, 1], [1, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [1, 2], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 1]], + [[0, 1], [1, 0], [1, 1], [2, 1]], + ], + color: "#a000f0", + }, + { + shape: [ + [[0, 1], [0, 2], [1, 0], [1, 1]], + [[0, 0], [1, 0], [1, 1], [2, 1]], + [[1, 1], [1, 2], [2, 0], [2, 1]], + [[0, 0], [1, 0], [1, 1], [2, 1]], + ], + color: "#00f000", + }, + { + shape: [ + [[0, 0], [0, 1], [1, 1], [1, 2]], + [[0, 2], [1, 1], [1, 2], [2, 1]], + [[1, 0], [1, 1], [2, 1], [2, 2]], + [[0, 1], [1, 0], [1, 1], [2, 0]], + ], + color: "#f00000", + }, + { + shape: [ + [[0, 0], [1, 0], [1, 1], [1, 2]], + [[0, 1], [0, 2], [1, 1], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 2]], + [[0, 1], [1, 1], [2, 0], [2, 1]], + ], + color: "#0000f0", + }, + { + shape: [ + [[0, 2], [1, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [2, 1], [2, 2]], + [[1, 0], [1, 1], [1, 2], [2, 0]], + [[0, 0], [0, 1], [1, 1], [2, 1]], + ], + color: "#f0a000", + }, +]; +// SRS wall kick data (non-I pieces) +const WALL_KICKS = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// SRS wall kick data for I piece +const WALL_KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// Scoring (original BPS scoring) +const SCORE_TABLE = [0, 100, 300, 500, 800]; +// ── Helpers ───────────────────────────────────────────────────────── +function createGrid() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function randomBag() { + const bag = [0, 1, 2, 3, 4, 5, 6]; + for (let i = bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [bag[i], bag[j]] = [bag[j], bag[i]]; + } + return bag; +} +// ── Game State ────────────────────────────────────────────────────── +class TetrisGame { + // ── Initialisation ─────────────────────────────────────────────── + constructor() { + this.grid = createGrid(); + this.bag = []; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.dropInterval = 1000; // ms + this.lastDrop = 0; + this.lockTimer = null; + this.animatingRows = []; + this.animationStart = 0; + this.ANIM_DURATION = 300; // ms for line-clear flash + this.frameId = 0; + // ── DAS (Delayed Auto Shift) state ─────────────────────────────── + this.heldKey = null; + this.dasTimer = 0; + this.dasDelay = 170; // ms before auto-repeat starts + this.dasInterval = 50; // ms between repeats + this.lastDasRepeat = 0; + this.softDropping = false; + // ── Game loop ──────────────────────────────────────────────────── + this.loop = (now) => { + this.frameId = requestAnimationFrame(this.loop); + if (this.gameOver) { + this.draw(now); + this.updateUI(); + return; + } + if (this.paused) { + this.draw(now); + return; + } + // Handle line-clear animation + if (this.animatingRows.length > 0) { + if (now - this.animationStart > this.ANIM_DURATION) { + this.finishClear(); + } + this.draw(now); + this.updateUI(); + return; + } + // DAS (auto-repeat) + this.handleDAS(now); + // Soft drop + const effectiveInterval = this.softDropping ? 50 : this.dropInterval; + // Gravity + if (now - this.lastDrop > effectiveInterval) { + if (this.move(0, 1)) { + if (this.softDropping) + this.score += 1; + this.lastDrop = now; + // If the piece is no longer sitting on something, cancel lock timer + if (this.isValid(this.current.shape, { x: this.current.pos.x, y: this.current.pos.y + 1 })) { + this.lockTimer = null; + } + } + else { + // Piece can't move down — start or check lock timer + if (this.lockTimer === null) { + this.lockTimer = now; + } + this.lastDrop = now; + } + } + // Lock timer + if (this.lockTimer !== null && now - this.lockTimer >= LOCK_DELAY) { + // Confirm still can't move down + if (!this.isValid(this.current.shape, { x: this.current.pos.x, y: this.current.pos.y + 1 })) { + this.lock(); + } + else { + this.lockTimer = null; + } + } + this.draw(now); + this.updateUI(); + }; + this.setupCanvas(); + this.refillBag(); + this.spawnPiece(); + this.setupInput(); + this.lastDrop = performance.now(); + this.loop(performance.now()); + } + setupCanvas() { + const gameCanvas = document.getElementById("game-canvas"); + const previewCanvas = document.getElementById("preview-canvas"); + gameCanvas.width = COLS * CELL; + gameCanvas.height = ROWS * CELL; + previewCanvas.width = PREVIEW_CELLS * CELL; + previewCanvas.height = PREVIEW_CELLS * CELL; + this.ctx = gameCanvas.getContext("2d"); + this.previewCtx = previewCanvas.getContext("2d"); + } + // ── Bag / spawn ────────────────────────────────────────────────── + refillBag() { + if (this.bag.length <= 7) { + this.bag = this.bag.concat(randomBag()); + } + } + spawnPiece() { + this.refillBag(); + const idx = this.bag.shift(); + this.nextIndex = this.bag[0]; + const tmpl = TETROMINOES[idx]; + this.current = { + shape: tmpl.shape[0], + color: tmpl.color, + pos: { x: 3, y: 0 }, + rotation: 0, + }; + // Store the index on the piece so we can look up kick tables + this.current._idx = idx; + if (!this.isValid(this.current.shape, this.current.pos)) { + this.gameOver = true; + } + this.lockTimer = null; + } + // ── Collision ──────────────────────────────────────────────────── + isValid(shape, pos) { + for (const [r, c] of shape) { + const x = pos.x + c; + const y = pos.y + r; + if (x < 0 || x >= COLS || y >= ROWS) + return false; + if (y >= 0 && this.grid[y][x] !== null) + return false; + } + return true; + } + // ── Movement ───────────────────────────────────────────────────── + move(dx, dy) { + const newPos = { x: this.current.pos.x + dx, y: this.current.pos.y + dy }; + if (this.isValid(this.current.shape, newPos)) { + this.current.pos = newPos; + // Reset lock timer if moving horizontally while on ground + if (dx !== 0 && this.lockTimer !== null) { + this.lockTimer = performance.now(); + } + return true; + } + return false; + } + rotate(dir) { + const idx = this.current._idx; + const tmpl = TETROMINOES[idx]; + const oldRot = this.current.rotation; + const newRot = (oldRot + dir + 4) % 4; + const newShape = tmpl.shape[newRot]; + // Select kick table + const kickKey = `${oldRot}>${newRot}`; + const kickTable = idx === 0 ? WALL_KICKS_I : WALL_KICKS; + const kicks = kickTable[kickKey] || [[0, 0]]; + for (const [kx, ky] of kicks) { + const testPos = { x: this.current.pos.x + kx, y: this.current.pos.y - ky }; + if (this.isValid(newShape, testPos)) { + this.current.shape = newShape; + this.current.rotation = newRot; + this.current.pos = testPos; + if (this.lockTimer !== null) { + this.lockTimer = performance.now(); + } + return; + } + } + } + hardDrop() { + let rows = 0; + while (this.move(0, 1)) + rows++; + this.score += rows * 2; + this.lock(); + } + // ── Lock & line clear ──────────────────────────────────────────── + lock() { + for (const [r, c] of this.current.shape) { + const x = this.current.pos.x + c; + const y = this.current.pos.y + r; + if (y >= 0) + this.grid[y][x] = this.current.color; + } + this.lockTimer = null; + this.clearLines(); + } + clearLines() { + const fullRows = []; + for (let r = 0; r < ROWS; r++) { + if (this.grid[r].every(cell => cell !== null)) { + fullRows.push(r); + } + } + if (fullRows.length > 0) { + this.animatingRows = fullRows; + this.animationStart = performance.now(); + } + else { + this.spawnPiece(); + } + } + finishClear() { + const fullRows = this.animatingRows; + // Remove full rows and add empty rows on top + for (const r of fullRows.sort((a, b) => b - a)) { + this.grid.splice(r, 1); + this.grid.unshift(Array(COLS).fill(null)); + } + const count = fullRows.length; + this.lines += count; + this.score += SCORE_TABLE[count] * this.level; + this.level = Math.floor(this.lines / LINES_PER_LEVEL) + 1; + this.dropInterval = Math.max(50, 1000 - (this.level - 1) * 75); + this.animatingRows = []; + this.spawnPiece(); + } + // ── Ghost piece (drop shadow) ──────────────────────────────────── + ghostY() { + let gy = this.current.pos.y; + while (true) { + const next = gy + 1; + if (!this.isValid(this.current.shape, { x: this.current.pos.x, y: next })) + break; + gy = next; + } + return gy; + } + // ── Input ──────────────────────────────────────────────────────── + setupInput() { + document.addEventListener("keydown", (e) => { + if (this.gameOver) { + if (e.key === "r" || e.key === "R") + this.restart(); + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.paused = !this.paused; + if (!this.paused) + this.lastDrop = performance.now(); + this.updateUI(); + return; + } + if (this.paused) + return; + if (this.animatingRows.length > 0) + return; + switch (e.key) { + case "ArrowLeft": + e.preventDefault(); + if (this.heldKey !== "ArrowLeft") { + this.move(-1, 0); + this.heldKey = "ArrowLeft"; + this.dasTimer = performance.now(); + this.lastDasRepeat = 0; + } + break; + case "ArrowRight": + e.preventDefault(); + if (this.heldKey !== "ArrowRight") { + this.move(1, 0); + this.heldKey = "ArrowRight"; + this.dasTimer = performance.now(); + this.lastDasRepeat = 0; + } + break; + case "ArrowDown": + e.preventDefault(); + this.softDropping = true; + break; + case "ArrowUp": + e.preventDefault(); + this.rotate(1); + break; + case "z": + case "Z": + this.rotate(-1); + break; + case "x": + case "X": + this.rotate(1); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + } + }); + document.addEventListener("keyup", (e) => { + if (e.key === "ArrowLeft" && this.heldKey === "ArrowLeft") + this.heldKey = null; + if (e.key === "ArrowRight" && this.heldKey === "ArrowRight") + this.heldKey = null; + if (e.key === "ArrowDown") + this.softDropping = false; + }); + } + handleDAS(now) { + if (!this.heldKey) + return; + const elapsed = now - this.dasTimer; + if (elapsed < this.dasDelay) + return; + const sinceLast = now - this.lastDasRepeat; + if (sinceLast >= this.dasInterval) { + this.lastDasRepeat = now; + const dx = this.heldKey === "ArrowLeft" ? -1 : 1; + this.move(dx, 0); + } + } + // ── Restart ────────────────────────────────────────────────────── + restart() { + this.grid = createGrid(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.dropInterval = 1000; + this.gameOver = false; + this.paused = false; + this.bag = []; + this.animatingRows = []; + this.heldKey = null; + this.softDropping = false; + this.refillBag(); + this.spawnPiece(); + this.lastDrop = performance.now(); + this.updateUI(); + } + // ── Rendering ──────────────────────────────────────────────────── + drawCell(ctx, x, y, color, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * CELL, y * CELL, CELL, CELL); + // Highlight (top-left bevel) + ctx.fillStyle = "rgba(255,255,255,0.3)"; + ctx.fillRect(x * CELL, y * CELL, CELL, 2); + ctx.fillRect(x * CELL, y * CELL, 2, CELL); + // Shadow (bottom-right bevel) + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(x * CELL, (y + 1) * CELL - 2, CELL, 2); + ctx.fillRect((x + 1) * CELL - 2, y * CELL, 2, CELL); + ctx.globalAlpha = 1; + } + draw(now) { + const { ctx } = this; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, COLS * CELL, ROWS * CELL); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(COLS * CELL, r * CELL); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, ROWS * CELL); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const cell = this.grid[r][c]; + if (cell) { + // Flash animation for clearing rows + if (this.animatingRows.includes(r)) { + const t = (now - this.animationStart) / this.ANIM_DURATION; + const flash = Math.abs(Math.sin(t * Math.PI * 3)); + this.drawCell(ctx, c, r, "#fff", flash); + } + else { + this.drawCell(ctx, c, r, cell); + } + } + } + } + if (this.gameOver || this.paused || this.animatingRows.length > 0) { + this.drawPreview(); + if (this.gameOver) + this.drawOverlay("GAME OVER", "Press R to restart"); + if (this.paused) + this.drawOverlay("PAUSED", "Press P to resume"); + return; + } + // Ghost piece + const gy = this.ghostY(); + for (const [r, c] of this.current.shape) { + const x = this.current.pos.x + c; + const y = gy + r; + if (y >= 0) + this.drawCell(ctx, x, y, this.current.color, 0.2); + } + // Current piece + for (const [r, c] of this.current.shape) { + const x = this.current.pos.x + c; + const y = this.current.pos.y + r; + if (y >= 0) + this.drawCell(ctx, x, y, this.current.color); + } + this.drawPreview(); + } + drawPreview() { + const { previewCtx: ctx } = this; + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, PREVIEW_CELLS * CELL, PREVIEW_CELLS * CELL); + if (this.nextIndex === undefined) + return; + const tmpl = TETROMINOES[this.nextIndex]; + const shape = tmpl.shape[0]; + // Center in preview box + const minC = Math.min(...shape.map(([, c]) => c)); + const maxC = Math.max(...shape.map(([, c]) => c)); + const minR = Math.min(...shape.map(([r]) => r)); + const maxR = Math.max(...shape.map(([r]) => r)); + const offX = (PREVIEW_CELLS - (maxC - minC + 1)) / 2 - minC; + const offY = (PREVIEW_CELLS - (maxR - minR + 1)) / 2 - minR; + for (const [r, c] of shape) { + this.drawCell(ctx, c + offX, r + offY, tmpl.color); + } + } + drawOverlay(title, subtitle) { + const { ctx } = this; + ctx.fillStyle = "rgba(0,0,0,0.6)"; + ctx.fillRect(0, 0, COLS * CELL, ROWS * CELL); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px 'Courier New', monospace"; + ctx.textAlign = "center"; + ctx.fillText(title, (COLS * CELL) / 2, (ROWS * CELL) / 2 - 10); + ctx.font = "16px 'Courier New', monospace"; + ctx.fillText(subtitle, (COLS * CELL) / 2, (ROWS * CELL) / 2 + 20); + } + // ── UI ─────────────────────────────────────────────────────────── + updateUI() { + const el = (id) => document.getElementById(id); + el("score-val").textContent = String(this.score); + el("lines-val").textContent = String(this.lines); + el("level-val").textContent = String(this.level); + } +} +// ── Bootstrap ────────────────────────────────────────────────────── +document.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":";AAAA,uEAAuE;AAEvE,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,IAAI,GAAG,EAAE,CAAC,CAAmB,kBAAkB;AACrD,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,UAAU,GAAG,GAAG,CAAC,CAAY,iCAAiC;AAapE,wDAAwD;AACxD,kDAAkD;AAClD,MAAM,WAAW,GAA6C;IAC5D;QACE,KAAK,EAAE;YACL,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;SAC1B;QACD,KAAK,EAAE,SAAS;KACjB;IACD;QACE,KAAK,EAAE;YACL,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;SAC1B;QACD,KAAK,EAAE,SAAS;KACjB;IACD;QACE,KAAK,EAAE;YACL,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;SAC1B;QACD,KAAK,EAAE,SAAS;KACjB;IACD;QACE,KAAK,EAAE;YACL,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;SAC1B;QACD,KAAK,EAAE,SAAS;KACjB;IACD;QACE,KAAK,EAAE;YACL,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;SAC1B;QACD,KAAK,EAAE,SAAS;KACjB;IACD;QACE,KAAK,EAAE;YACL,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;SAC1B;QACD,KAAK,EAAE,SAAS;KACjB;IACD;QACE,KAAK,EAAE;YACL,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;SAC1B;QACD,KAAK,EAAE,SAAS;KACjB;CACF,CAAC;AAEF,oCAAoC;AACpC,MAAM,UAAU,GAA+B;IAC7C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACvC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACvC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACxC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IAC1C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IAC1C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;CACzC,CAAC;AAEF,iCAAiC;AACjC,MAAM,YAAY,GAA+B;IAC/C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CA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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,507 @@ +"use strict"; +// ============================================================ +// Tetris – Full browser game in TypeScript +// ============================================================ +// ----- Constants -------------------------------------------- +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 30; +const PREVIEW_BLOCK = 20; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +// Shapes defined as 4×4 matrices (row-major). Each tetromino has +// one canonical shape; rotations are computed on the fly. +const SHAPES = { + I: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + O: [ + [1, 1], + [1, 1], + ], + T: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + S: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + Z: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + J: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + L: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], +}; +// SRS wall-kick data (non-I pieces) +const WALL_KICKS = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// SRS wall-kick data for I piece +const WALL_KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// Gravity speeds per level (ms per drop). Index = level (0-29). +function getDropInterval(level) { + // Approximate NES Tetris curve, clamped at level 29 + const speeds = [ + 800, 720, 630, 550, 470, 380, 300, 220, 150, 100, + 80, 80, 80, 70, 70, 70, 50, 50, 50, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 20, + ]; + return speeds[Math.min(level, speeds.length - 1)]; +} +// ----- Helpers ---------------------------------------------- +function rotateMatrix(matrix) { + const N = matrix.length; + const result = Array.from({ length: N }, () => Array(N).fill(0)); + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + result[c][N - 1 - r] = matrix[r][c]; + } + } + return result; +} +function getRotation(shape, times) { + let m = shape; + for (let i = 0; i < ((times % 4) + 4) % 4; i++) { + m = rotateMatrix(m); + } + return m; +} +function createPiece(type) { + const shape = SHAPES[type]; + return { + type, + rotation: 0, + shape, + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + }; +} +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function collides(board, piece, offsetX, offsetY, shape) { + const s = shape ?? piece.shape; + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const nx = piece.x + c + offsetX; + const ny = piece.y + r + offsetY; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny < 0) + continue; // above the board is okay + if (board[ny][nx]) + return true; + } + } + return false; +} +function lockPiece(board, piece) { + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + const ny = piece.y + r; + const nx = piece.x + c; + if (ny >= 0 && ny < ROWS && nx >= 0 && nx < COLS) { + board[ny][nx] = piece.type; + } + } + } +} +function clearLines(board) { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every((cell) => cell !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check same index + } + } + return cleared; +} +// ----- Bag randomiser (7-bag) -------------------------------- +function createBag() { + const types = Object.keys(SHAPES); + for (let i = types.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [types[i], types[j]] = [types[j], types[i]]; + } + return types; +} +function nextFromBag(bag) { + if (bag.length === 0) { + bag.push(...createBag()); + } + return bag.pop(); +} +function initGame() { + const bag = createBag(); + const current = createPiece(nextFromBag(bag)); + const next = createPiece(nextFromBag(bag)); + return { + board: createBoard(), + current, + next, + bag, + score: 0, + lines: 0, + level: 0, + gameOver: false, + paused: false, + dropTimer: 0, + lastDrop: performance.now(), + lockDelay: 500, + lockTimer: 0, + }; +} +// ----- Scoring (original BPS) -------------------------------- +function scoreForLines(lines, level) { + const table = [0, 40, 100, 300, 1200]; + return table[lines] * (level + 1); +} +// ----- Game logic ------------------------------------------- +function tryMove(state, dx, dy) { + if (!collides(state.board, state.current, dx, dy)) { + state.current.x += dx; + state.current.y += dy; + return true; + } + return false; +} +function tryRotate(state, dir) { + const piece = state.current; + const fromRot = piece.rotation; + const toRot = ((fromRot + dir) % 4 + 4) % 4; + const newShape = getRotation(SHAPES[piece.type], toRot); + const kickTable = piece.type === "I" ? WALL_KICKS_I : WALL_KICKS; + const key = `${fromRot}>${toRot}`; + const kicks = kickTable[key] ?? [[0, 0]]; + for (const [kx, ky] of kicks) { + if (!collides(state.board, piece, kx, -ky, newShape)) { + piece.x += kx; + piece.y -= ky; + piece.shape = newShape; + piece.rotation = toRot; + return true; + } + } + return false; +} +function hardDrop(state) { + let dropDistance = 0; + while (!collides(state.board, state.current, 0, 1)) { + state.current.y++; + dropDistance++; + } + state.score += dropDistance * 2; + lock(state); +} +function lock(state) { + lockPiece(state.board, state.current); + const cleared = clearLines(state.board); + if (cleared > 0) { + state.lines += cleared; + state.score += scoreForLines(cleared, state.level); + state.level = Math.floor(state.lines / 10); + } + // Spawn next piece + state.current = state.next; + state.next = createPiece(nextFromBag(state.bag)); + state.lastDrop = performance.now(); + state.lockTimer = 0; + // Check game over + if (collides(state.board, state.current, 0, 0)) { + state.gameOver = true; + } +} +function getGhostY(state) { + let gy = 0; + while (!collides(state.board, state.current, 0, gy + 1)) { + gy++; + } + return state.current.y + gy; +} +// ----- Rendering -------------------------------------------- +function drawBlock(ctx, x, y, size, color, alpha = 1.0) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size, y * size, size, size); + // highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x * size, y * size, size, 2); + ctx.fillRect(x * size, y * size, 2, size); + // shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x * size + size - 2, y * size, 2, size); + ctx.fillRect(x * size, y * size + size - 2, size, 2); + // grid line + ctx.strokeStyle = "rgba(0,0,0,0.15)"; + ctx.strokeRect(x * size, y * size, size, size); + ctx.globalAlpha = 1; +} +function render(ctx, previewCtx, state, scoreEl, levelEl, linesEl) { + const W = COLS * BLOCK_SIZE; + const H = ROWS * BLOCK_SIZE; + // Clear + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, W, H); + // Draw grid lines + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(W, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, H); + ctx.stroke(); + } + // Draw locked board + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const cell = state.board[r][c]; + if (cell) { + drawBlock(ctx, c, r, BLOCK_SIZE, COLORS[cell]); + } + } + } + if (!state.gameOver) { + const piece = state.current; + const ghostY = getGhostY(state); + // Draw ghost piece (translucent) + if (ghostY !== piece.y) { + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + const gy = ghostY + r; + if (gy < 0) + continue; + drawBlock(ctx, piece.x + c, gy, BLOCK_SIZE, COLORS[piece.type], 0.2); + } + } + } + // Draw current piece + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + const py = piece.y + r; + if (py < 0) + continue; + drawBlock(ctx, piece.x + c, py, BLOCK_SIZE, COLORS[piece.type]); + } + } + } + // Preview + const PW = 6 * PREVIEW_BLOCK; + const PH = 6 * PREVIEW_BLOCK; + previewCtx.fillStyle = "#1a1a2e"; + previewCtx.fillRect(0, 0, PW, PH); + const ns = state.next.shape; + const offsetX = Math.floor((6 - ns[0].length) / 2); + const offsetY = Math.floor((6 - ns.length) / 2); + for (let r = 0; r < ns.length; r++) { + for (let c = 0; c < ns[r].length; c++) { + if (!ns[r][c]) + continue; + previewCtx.fillStyle = COLORS[state.next.type]; + previewCtx.fillRect((offsetX + c) * PREVIEW_BLOCK, (offsetY + r) * PREVIEW_BLOCK, PREVIEW_BLOCK, PREVIEW_BLOCK); + previewCtx.strokeStyle = "rgba(0,0,0,0.3)"; + previewCtx.strokeRect((offsetX + c) * PREVIEW_BLOCK, (offsetY + r) * PREVIEW_BLOCK, PREVIEW_BLOCK, PREVIEW_BLOCK); + } + } + // HUD + scoreEl.textContent = state.score.toString(); + levelEl.textContent = state.level.toString(); + linesEl.textContent = state.lines.toString(); + // Game Over overlay + if (state.gameOver) { + ctx.fillStyle = "rgba(0,0,0,0.65)"; + ctx.fillRect(0, 0, W, H); + ctx.fillStyle = "#fff"; + ctx.font = "bold 32px monospace"; + ctx.textAlign = "center"; + ctx.fillText("GAME OVER", W / 2, H / 2 - 20); + ctx.font = "18px monospace"; + ctx.fillText("Press R to restart", W / 2, H / 2 + 20); + } + // Paused overlay + if (state.paused && !state.gameOver) { + ctx.fillStyle = "rgba(0,0,0,0.55)"; + ctx.fillRect(0, 0, W, H); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px monospace"; + ctx.textAlign = "center"; + ctx.fillText("PAUSED", W / 2, H / 2); + } +} +// ----- Main loop -------------------------------------------- +(function main() { + const canvas = document.getElementById("game-canvas"); + const previewCanvas = document.getElementById("preview-canvas"); + const ctx = canvas.getContext("2d"); + const previewCtx = previewCanvas.getContext("2d"); + const scoreEl = document.getElementById("score"); + const levelEl = document.getElementById("level"); + const linesEl = document.getElementById("lines"); + canvas.width = COLS * BLOCK_SIZE; + canvas.height = ROWS * BLOCK_SIZE; + previewCanvas.width = 6 * PREVIEW_BLOCK; + previewCanvas.height = 6 * PREVIEW_BLOCK; + let state = initGame(); + // DAS (Delayed Auto Shift) + const DAS_DELAY = 170; + const DAS_REPEAT = 50; + const keysDown = {}; + const dasTimers = {}; + function handleDAS(key, action, now) { + if (!(key in keysDown)) + return; + if (!dasTimers[key]) { + dasTimers[key] = { delay: true, last: keysDown[key] }; + action(); + return; + } + const dt = dasTimers[key]; + const threshold = dt.delay ? DAS_DELAY : DAS_REPEAT; + if (now - dt.last >= threshold) { + action(); + dt.last = now; + dt.delay = false; + } + } + document.addEventListener("keydown", (e) => { + if (e.repeat) + return; + if (e.key === "r" || e.key === "R") { + state = initGame(); + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + if (!state.gameOver) + state.paused = !state.paused; + return; + } + if (state.gameOver || state.paused) + return; + if (e.key === "ArrowLeft" || e.key === "ArrowRight" || e.key === "ArrowDown") { + keysDown[e.key] = performance.now(); + dasTimers[e.key] = { delay: true, last: performance.now() }; + // Immediate action + if (e.key === "ArrowLeft") + tryMove(state, -1, 0); + else if (e.key === "ArrowRight") + tryMove(state, 1, 0); + else if (e.key === "ArrowDown") { + if (tryMove(state, 0, 1)) + state.score += 1; + } + e.preventDefault(); + return; + } + if (e.key === "ArrowUp" || e.key === "x" || e.key === "X") { + tryRotate(state, 1); + e.preventDefault(); + return; + } + if (e.key === "z" || e.key === "Z" || e.key === "Control") { + tryRotate(state, -1); + e.preventDefault(); + return; + } + if (e.key === " ") { + hardDrop(state); + e.preventDefault(); + return; + } + }); + document.addEventListener("keyup", (e) => { + delete keysDown[e.key]; + delete dasTimers[e.key]; + }); + function update(now) { + if (state.gameOver || state.paused) + return; + // DAS for held keys + if ("ArrowLeft" in keysDown) { + handleDAS("ArrowLeft", () => tryMove(state, -1, 0), now); + } + if ("ArrowRight" in keysDown) { + handleDAS("ArrowRight", () => tryMove(state, 1, 0), now); + } + if ("ArrowDown" in keysDown) { + handleDAS("ArrowDown", () => { + if (tryMove(state, 0, 1)) + state.score += 1; + }, now); + } + // Gravity + const interval = getDropInterval(state.level); + if (now - state.lastDrop >= interval) { + if (!tryMove(state, 0, 1)) { + // Piece can't move down — lock delay + state.lockTimer += now - state.lastDrop; + if (state.lockTimer >= state.lockDelay) { + lock(state); + } + } + else { + state.lockTimer = 0; + } + state.lastDrop = now; + } + } + function gameLoop(now) { + update(now); + render(ctx, previewCtx, state, scoreEl, levelEl, linesEl); + requestAnimationFrame(gameLoop); + } + requestAnimationFrame(gameLoop); +})(); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/board.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/board.js @@ -0,0 +1,61 @@ +import { COLS, ROWS } from "./types.js"; +export function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +export function collides(board, piece) { + const { shape, pos } = piece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const newX = pos.x + c; + const newY = pos.y + r; + if (newX < 0 || newX >= COLS || newY >= ROWS) { + return true; + } + if (newY >= 0 && board[newY][newX] !== null) { + return true; + } + } + } + } + return false; +} +export function lockPiece(board, piece) { + const { shape, pos, color } = piece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const boardY = pos.y + r; + const boardX = pos.x + c; + if (boardY >= 0 && boardY < ROWS && boardX >= 0 && boardX < COLS) { + board[boardY][boardX] = color; + } + } + } + } +} +export function clearLines(board) { + let linesCleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every((cell) => cell !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + linesCleared++; + r++; // re-check this row since rows shifted down + } + } + return linesCleared; +} +export function getGhostPosition(board, piece) { + let ghostY = piece.pos.y; + const ghost = { + shape: piece.shape, + color: piece.color, + pos: { x: piece.pos.x, y: ghostY }, + }; + while (!collides(board, ghost)) { + ghost.pos.y++; + } + return ghost.pos.y - 1; +} +//# sourceMappingURL=board.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/board.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/board.js.map @@ -0,0 +1 @@ +{"version":3,"file":"board.js","sourceRoot":"","sources":["../src/board.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js @@ -0,0 +1,262 @@ +import { randomPiece, rotateCW, rotateCCW } from "./pieces.js"; +import { createBoard, collides, lockPiece, clearLines } from "./board.js"; +import { Renderer } from "./renderer.js"; +// Wall kick offsets to try when rotation collides +const WALL_KICKS = [ + { x: 0, y: 0 }, + { x: -1, y: 0 }, + { x: 1, y: 0 }, + { x: -2, y: 0 }, + { x: 2, y: 0 }, + { x: 0, y: -1 }, + { x: -1, y: -1 }, + { x: 1, y: -1 }, +]; +const POINTS = [0, 100, 300, 500, 800]; // points per 0,1,2,3,4 lines +const LINES_PER_LEVEL = 10; +const BASE_SPEED = 800; // ms per drop at level 1 +const MIN_SPEED = 50; +const SPEED_FACTOR = 0.75; +const LOCK_DELAY = 500; // ms before piece locks after landing +const DAS_DELAY = 170; // ms before auto-repeat starts +const DAS_RATE = 50; // ms between auto-repeat moves +export class Game { + constructor(canvas, previewCanvas, scoreEl, levelEl, linesEl) { + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameOver = false; + this.paused = false; + this.dropInterval = BASE_SPEED; + this.lastDrop = 0; + this.lockTimer = 0; + this.isLocking = false; + // DAS (Delayed Auto Shift) state + this.heldKeys = new Map(); + this.animationFrameId = 0; + this.renderer = new Renderer(canvas, previewCanvas); + this.scoreEl = scoreEl; + this.levelEl = levelEl; + this.linesEl = linesEl; + this.board = createBoard(); + this.current = randomPiece(); + this.next = randomPiece(); + this.setupInput(); + this.updateUI(); + this.renderer.drawPreview(this.next); + } + setupInput() { + document.addEventListener("keydown", (e) => { + if (e.repeat) + return; // we handle repeat ourselves + if (e.key === "r" || e.key === "R") { + this.restart(); + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + if (!this.gameOver) + this.paused = !this.paused; + return; + } + if (this.gameOver || this.paused) + return; + switch (e.key) { + case "ArrowLeft": + case "ArrowRight": + case "ArrowDown": + e.preventDefault(); + this.handleMovement(e.key); + this.heldKeys.set(e.key, { since: performance.now(), lastRepeat: 0 }); + break; + case "ArrowUp": + e.preventDefault(); + this.rotate(true); + break; + case "z": + case "Z": + this.rotate(false); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + } + }); + document.addEventListener("keyup", (e) => { + this.heldKeys.delete(e.key); + }); + } + handleMovement(key) { + switch (key) { + case "ArrowLeft": + this.move(-1, 0); + break; + case "ArrowRight": + this.move(1, 0); + break; + case "ArrowDown": + this.softDrop(); + break; + } + } + processDAS(now) { + for (const [key, state] of this.heldKeys) { + const held = now - state.since; + if (held >= DAS_DELAY) { + const timeSinceRepeat = state.lastRepeat === 0 + ? held - DAS_DELAY + : now - state.lastRepeat; + if (timeSinceRepeat >= DAS_RATE) { + this.handleMovement(key); + state.lastRepeat = now; + } + } + } + } + move(dx, dy) { + const test = { + ...this.current, + pos: { x: this.current.pos.x + dx, y: this.current.pos.y + dy }, + }; + if (!collides(this.board, test)) { + this.current.pos = test.pos; + if (dy === 0 && this.isLocking) { + // Reset lock timer on horizontal movement + this.lockTimer = performance.now(); + } + return true; + } + return false; + } + rotate(clockwise) { + const rotated = clockwise + ? rotateCW(this.current.shape) + : rotateCCW(this.current.shape); + for (const kick of WALL_KICKS) { + const test = { + shape: rotated, + color: this.current.color, + pos: { + x: this.current.pos.x + kick.x, + y: this.current.pos.y + kick.y, + }, + }; + if (!collides(this.board, test)) { + this.current.shape = rotated; + this.current.pos = test.pos; + if (this.isLocking) { + this.lockTimer = performance.now(); + } + return; + } + } + } + softDrop() { + if (this.move(0, 1)) { + this.score += 1; + this.lastDrop = performance.now(); + this.updateUI(); + } + } + hardDrop() { + let rows = 0; + while (this.move(0, 1)) { + rows++; + } + this.score += rows * 2; + this.updateUI(); + this.lock(); + } + lock() { + lockPiece(this.board, this.current); + this.isLocking = false; + const cleared = clearLines(this.board); + if (cleared > 0) { + this.lines += cleared; + this.score += POINTS[cleared] * this.level; + const newLevel = Math.floor(this.lines / LINES_PER_LEVEL) + 1; + if (newLevel > this.level) { + this.level = newLevel; + this.dropInterval = Math.max(MIN_SPEED, BASE_SPEED * Math.pow(SPEED_FACTOR, this.level - 1)); + } + this.updateUI(); + } + this.spawnPiece(); + } + spawnPiece() { + this.current = this.next; + this.next = randomPiece(); + this.renderer.drawPreview(this.next); + this.lastDrop = performance.now(); + if (collides(this.board, this.current)) { + this.gameOver = true; + } + } + updateUI() { + this.scoreEl.textContent = this.score.toLocaleString(); + this.levelEl.textContent = String(this.level); + this.linesEl.textContent = String(this.lines); + } + start() { + this.lastDrop = performance.now(); + const loop = (now) => { + this.update(now); + this.draw(); + this.animationFrameId = requestAnimationFrame(loop); + }; + this.animationFrameId = requestAnimationFrame(loop); + } + update(now) { + if (this.gameOver || this.paused) + return; + this.processDAS(now); + // Gravity + if (now - this.lastDrop >= this.dropInterval) { + if (!this.move(0, 1)) { + // Piece can't move down — start or check lock delay + if (!this.isLocking) { + this.isLocking = true; + this.lockTimer = now; + } + else if (now - this.lockTimer >= LOCK_DELAY) { + this.lock(); + } + } + else { + this.isLocking = false; + } + this.lastDrop = now; + } + } + draw() { + this.renderer.drawBoard(this.board); + if (!this.gameOver) { + this.renderer.drawGhost(this.board, this.current); + this.renderer.drawPiece(this.current); + } + if (this.gameOver) { + this.renderer.drawPiece(this.current); + this.renderer.drawGameOver(); + } + else if (this.paused) { + this.renderer.drawPaused(); + } + } + restart() { + this.board = createBoard(); + this.current = randomPiece(); + this.next = randomPiece(); + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameOver = false; + this.paused = false; + this.dropInterval = BASE_SPEED; + this.isLocking = false; + this.heldKeys.clear(); + this.lastDrop = performance.now(); + this.updateUI(); + this.renderer.drawPreview(this.next); + } +} +//# sourceMappingURL=game.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js.map @@ -0,0 +1 @@ +{"version":3,"file":"game.js","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,kDAAkD;AAClD,MAAM,UAAU,GAAG;IACjB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;IACd,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;IACf,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;IACd,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;IACf,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;IACd,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE;IACf,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE;IAChB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE;CAChB,CAAC;AAEF,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,6BAA6B;AACrE,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,UAAU,GAAG,GAAG,CAAC,CAAC,yBAAyB;AACjD,MAAM,SAAS,GAAG,EAAE,CAAC;AACrB,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,UAAU,GAAG,GAAG,CAAC,CAAC,sCAAsC;AAC9D,MAAM,SAAS,GAAG,GAAG,CAAC,CAAC,+BAA+B;AACtD,MAAM,QAAQ,GAAG,EAAE,CAAC,CAAC,+BAA+B;AAEpD,MAAM,OAAO,IAAI;IA0Bf,YACE,MAAyB,EACzB,aAAgC,EAChC,OAAoB,EACpB,OAAoB,EACpB,OAAoB;QA3Bd,UAAK,GAAG,CAAC,CAAC;QACV,UAAK,GAAG,CAAC,CAAC;QACV,UAAK,GAAG,CAAC,CAAC;QACV,aAAQ,GAAG,KAAK,CAAC;QACjB,WAAM,GAAG,KAAK,CAAC;QAGf,iBAAY,GAAG,UAAU,CAAC;QAC1B,aAAQ,GAAG,CAAC,CAAC;QACb,cAAS,GAAG,CAAC,CAAC;QACd,cAAS,GAAG,KAAK,CAAC;QAE1B,iCAAiC;QACzB,aAAQ,GAAuD,IAAI,GAAG,EAAE,CAAC;QAOzE,qBAAgB,GAAG,CAAC,CAAC;QAS3B,IAAI,CAAC,QAAQ,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;QACpD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,WAAW,EAAE,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,WAAW,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,WAAW,EAAE,CAAC;QAE1B,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;IAEO,UAAU;QAChB,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;YACzC,IAAI,CAAC,CAAC,MAAM;gBAAE,OAAO,CAAC,6BAA6B;YAEnD,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;gBACnC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACf,OAAO;YACT,CAAC;YACD,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACzD,IAAI,CAAC,IAAI,CAAC,QAAQ;oBAAE,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;gBAC/C,OAAO;YACT,CAAC;YACD,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM;gBAAE,OAAO;YAEzC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC;gBACd,KAAK,WAAW,CAAC;gBACjB,KAAK,YAAY,CAAC;gBAClB,KAAK,WAAW;oBACd,CAAC,CAAC,cAAc,EAAE,CAAC;oBACnB,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;oBAC3B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;oBACtE,MAAM;gBACR,KAAK,SAAS;oBACZ,CAAC,CAAC,cAAc,EAAE,CAAC;oBACnB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;oBAClB,MAAM;gBACR,KAAK,GAAG,CAAC;gBACT,KAAK,GAAG;oBACN,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;oBACnB,MAAM;gBACR,KAAK,GAAG;oBACN,CAAC,CAAC,cAAc,EAAE,CAAC;oBACnB,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAChB,MAAM;YACV,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;YACvC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,cAAc,CAAC,GAAW;QAChC,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,WAAW;gBACd,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACjB,MAAM;YACR,KAAK,YAAY;gBACf,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAChB,MAAM;YACR,KAAK,WAAW;gBACd,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAChB,MAAM;QACV,CAAC;IACH,CAAC;IAEO,UAAU,CAAC,GAAW;QAC5B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACzC,MAAM,IAAI,GAAG,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC;YAC/B,IAAI,IAAI,IAAI,SAAS,EAAE,CAAC;gBACtB,MAAM,eAAe,GAAG,KAAK,CAAC,UAAU,KAAK,CAAC;oBAC5C,CAAC,CAAC,IAAI,GAAG,SAAS;oBAClB,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC;gBAC3B,IAAI,eAAe,IAAI,QAAQ,EAAE,CAAC;oBAChC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;oBACzB,KAAK,CAAC,UAAU,GAAG,GAAG,CAAC;gBACzB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAEO,IAAI,CAAC,EAAU,EAAE,EAAU;QACjC,MAAM,IAAI,GAAU;YAClB,GAAG,IAAI,CAAC,OAAO;YACf,GAAG,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;SAChE,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;YAChC,IAAI,CAAC,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;YAC5B,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC/B,0CAA0C;gBAC1C,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;YACrC,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,MAAM,CAAC,SAAkB;QAC/B,MAAM,OAAO,GAAG,SAAS;YACvB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;YAC9B,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAElC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAU;gBAClB,KAAK,EAAE,OAAO;gBACd,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK;gBACzB,GAAG,EAAE;oBACH,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;oBAC9B,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;iBAC/B;aACF,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;gBAChC,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC;gBAC7B,IAAI,CAAC,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;gBAC5B,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;oBACnB,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;gBACrC,CAAC;gBACD,OAAO;YACT,CAAC;QACH,CAAC;IACH,CAAC;IAEO,QAAQ;QACd,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;YAChB,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;YAClC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,CAAC;IACH,CAAC;IAEO,QAAQ;QACd,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACvB,IAAI,EAAE,CAAC;QACT,CAAC;QACD,IAAI,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAEO,IAAI;QACV,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QAEvB,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC;YACtB,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;YAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;YAC9D,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC1B,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;gBACtB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAC1B,SAAS,EACT,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CACpD,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,CAAC;QAED,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAEO,UAAU;QAChB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,WAAW,EAAE,CAAC;QAC1B,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAElC,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,CAAC;IACH,CAAC;IAEO,QAAQ;QACd,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;QACvD,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC;IAED,KAAK;QACH,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE;YAC3B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjB,IAAI,CAAC,IAAI,EAAE,CAAC;YACZ,IAAI,CAAC,gBAAgB,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QACtD,CAAC,CAAC;QACF,IAAI,CAAC,gBAAgB,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC;IAEO,MAAM,CAAC,GAAW;QACxB,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QAEzC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAErB,UAAU;QACV,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YAC7C,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACrB,oDAAoD;gBACpD,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;oBACpB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;oBACtB,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;gBACvB,CAAC;qBAAM,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,IAAI,UAAU,EAAE,CAAC;oBAC9C,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACzB,CAAC;YACD,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC;QACtB,CAAC;IACH,CAAC;IAEO,IAAI;QACV,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEpC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YAClD,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxC,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtC,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;QAC/B,CAAC;aAAM,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACvB,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;IAEO,OAAO;QACb,IAAI,CAAC,KAAK,GAAG,WAAW,EAAE,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,WAAW,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,WAAW,EAAE,CAAC;QAC1B,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,YAAY,GAAG,UAAU,CAAC;QAC/B,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAClC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;CACF"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/main.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/main.js @@ -0,0 +1,11 @@ +import { Game } from "./game.js"; +document.addEventListener("DOMContentLoaded", () => { + const canvas = document.getElementById("game-canvas"); + const previewCanvas = document.getElementById("preview-canvas"); + const scoreEl = document.getElementById("score"); + const levelEl = document.getElementById("level"); + const linesEl = document.getElementById("lines"); + const game = new Game(canvas, previewCanvas, scoreEl, levelEl, linesEl); + game.start(); +}); +//# sourceMappingURL=main.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/main.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/main.js.map @@ -0,0 +1 @@ +{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;IACjD,MAAM,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAsB,CAAC;IAC3E,MAAM,aAAa,GAAG,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAsB,CAAC;IACrF,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC;IAClD,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC;IAClD,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC;IAElD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACxE,IAAI,CAAC,KAAK,EAAE,CAAC;AACf,CAAC,CAAC,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/pieces.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/pieces.js @@ -0,0 +1,94 @@ +const TETROMINOES = [ + { + // I piece + shape: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + color: "#00f0f0", + }, + { + // O piece + shape: [ + [1, 1], + [1, 1], + ], + color: "#f0f000", + }, + { + // T piece + shape: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + color: "#a000f0", + }, + { + // S piece + shape: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + color: "#00f000", + }, + { + // Z piece + shape: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + color: "#f00000", + }, + { + // J piece + shape: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + color: "#0000f0", + }, + { + // L piece + shape: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], + color: "#f0a000", + }, +]; +export function randomPiece() { + const def = TETROMINOES[Math.floor(Math.random() * TETROMINOES.length)]; + return { + shape: def.shape.map((row) => [...row]), + color: def.color, + pos: { x: Math.floor((10 - def.shape[0].length) / 2), y: 0 }, + }; +} +export function rotateCW(shape) { + const size = shape.length; + const rotated = Array.from({ length: size }, () => Array(size).fill(0)); + for (let r = 0; r < size; r++) { + for (let c = 0; c < size; c++) { + rotated[c][size - 1 - r] = shape[r][c]; + } + } + return rotated; +} +export function rotateCCW(shape) { + const size = shape.length; + const rotated = Array.from({ length: size }, () => Array(size).fill(0)); + for (let r = 0; r < size; r++) { + for (let c = 0; c < size; c++) { + rotated[size - 1 - c][r] = shape[r][c]; + } + } + return rotated; +} +//# sourceMappingURL=pieces.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/pieces.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/pieces.js.map @@ -0,0 +1 @@ +{"version":3,"file":"pieces.js","sourceRoot":"","sources":["../src/pieces.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,GAAmB;IAClC;QACE,UAAU;QACV,KAAK,EAAE;YACL,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACb;QACD,KAAK,EAAE,SAAS;KACjB;IACD;QACE,UAAU;QACV,KAAK,EAAE;YACL,CAAC,CAAC,EAAE,CAAC,CAAC;YACN,CAAC,CAAC,EAAE,CAAC,CAAC;SACP;QACD,KAAK,EAAE,SAAS;KACjB;IACD;QACE,UAAU;QACV,KAAK,EAAE;YACL,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD,KAAK,EAAE,SAAS;KACjB;IACD;QACE,UAAU;QACV,KAAK,EAAE;YACL,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD,KAAK,EAAE,SAAS;KACjB;IACD;QACE,UAAU;QACV,KAAK,EAAE;YACL,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD,KAAK,EAAE,SAAS;KACjB;IACD;QACE,UAAU;QACV,KAAK,EAAE;YACL,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD,KAAK,EAAE,SAAS;KACjB;IACD;QACE,UAAU;QACV,KAAK,EAAE;YACL,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD,KAAK,EAAE,SAAS;KACjB;CACF,CAAC;AAEF,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IACxE,OAAO;QACL,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QACvC,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,GAAG,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;KAC7D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAiB;IACxC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC;IAC1B,MAAM,OAAO,GAAe,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAC5D,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACpB,CAAC;IACF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAiB;IACzC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC;IAC1B,MAAM,OAAO,GAAe,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAC5D,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACpB,CAAC;IACF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/renderer.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/renderer.js @@ -0,0 +1,112 @@ +import { COLS, ROWS, BLOCK_SIZE, PREVIEW_BLOCK_SIZE } from "./types.js"; +import { getGhostPosition } from "./board.js"; +export class Renderer { + constructor(canvas, previewCanvas) { + this.canvas = canvas; + this.previewCanvas = previewCanvas; + this.ctx = canvas.getContext("2d"); + this.previewCtx = previewCanvas.getContext("2d"); + canvas.width = COLS * BLOCK_SIZE; + canvas.height = ROWS * BLOCK_SIZE; + previewCanvas.width = 4 * PREVIEW_BLOCK_SIZE + 20; + previewCanvas.height = 4 * PREVIEW_BLOCK_SIZE + 20; + } + drawBlock(ctx, x, y, color, size, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size, y * size, size, size); + // Highlight (top-left) + ctx.fillStyle = "rgba(255,255,255,0.3)"; + ctx.fillRect(x * size, y * size, size, 2); + ctx.fillRect(x * size, y * size, 2, size); + // Shadow (bottom-right) + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(x * size, (y + 1) * size - 2, size, 2); + ctx.fillRect((x + 1) * size - 2, y * size, 2, size); + // Grid line + ctx.strokeStyle = "rgba(0,0,0,0.15)"; + ctx.strokeRect(x * size, y * size, size, size); + ctx.globalAlpha = 1; + } + drawBoard(board) { + const { ctx } = this; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.03)"; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK_SIZE, r * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); + } + } + // Locked blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c]) { + this.drawBlock(ctx, c, r, board[r][c], BLOCK_SIZE); + } + } + } + } + drawPiece(piece) { + const { shape, color, pos } = piece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c] && pos.y + r >= 0) { + this.drawBlock(this.ctx, pos.x + c, pos.y + r, color, BLOCK_SIZE); + } + } + } + } + drawGhost(board, piece) { + const ghostY = getGhostPosition(board, piece); + const { shape, color } = piece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c] && ghostY + r >= 0) { + this.drawBlock(this.ctx, piece.pos.x + c, ghostY + r, color, BLOCK_SIZE, 0.25); + } + } + } + } + drawPreview(piece) { + const { previewCtx, previewCanvas } = this; + previewCtx.fillStyle = "#1a1a2e"; + previewCtx.fillRect(0, 0, previewCanvas.width, previewCanvas.height); + const { shape, color } = piece; + const shapeW = shape[0].length; + const shapeH = shape.length; + const offsetX = (previewCanvas.width - shapeW * PREVIEW_BLOCK_SIZE) / 2 / PREVIEW_BLOCK_SIZE; + const offsetY = (previewCanvas.height - shapeH * PREVIEW_BLOCK_SIZE) / 2 / PREVIEW_BLOCK_SIZE; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + this.drawBlock(previewCtx, offsetX + c, offsetY + r, color, PREVIEW_BLOCK_SIZE); + } + } + } + } + drawGameOver() { + const { ctx } = this; + ctx.fillStyle = "rgba(0,0,0,0.7)"; + ctx.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.fillStyle = "#ff4444"; + ctx.font = "bold 36px 'Segoe UI', sans-serif"; + ctx.textAlign = "center"; + ctx.fillText("GAME OVER", (COLS * BLOCK_SIZE) / 2, (ROWS * BLOCK_SIZE) / 2 - 20); + ctx.fillStyle = "#ffffff"; + ctx.font = "18px 'Segoe UI', sans-serif"; + ctx.fillText("Press R to restart", (COLS * BLOCK_SIZE) / 2, (ROWS * BLOCK_SIZE) / 2 + 20); + } + drawPaused() { + const { ctx } = this; + ctx.fillStyle = "rgba(0,0,0,0.5)"; + ctx.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.fillStyle = "#ffffff"; + ctx.font = "bold 36px 'Segoe UI', sans-serif"; + ctx.textAlign = "center"; + ctx.fillText("PAUSED", (COLS * BLOCK_SIZE) / 2, (ROWS * BLOCK_SIZE) / 2); + } +} +//# sourceMappingURL=renderer.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/renderer.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/renderer.js.map @@ -0,0 +1 @@ +{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/types.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/types.js @@ -0,0 +1,5 @@ +export const COLS = 10; +export const ROWS = 20; +export const BLOCK_SIZE = 30; +export const PREVIEW_BLOCK_SIZE = 20; +//# sourceMappingURL=types.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/types.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAwBA,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;AACvB,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;AACvB,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,CAAC;AAC7B,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,595 @@ +"use strict"; +// ─── Types & Constants ─────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 30; +const PREVIEW_BLOCK = 20; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const GHOST_ALPHA = 0.25; +// Standard SRS piece definitions (spawn orientation) +const PIECES = { + I: { + shape: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + color: COLORS.I, + }, + O: { + shape: [ + [1, 1], + [1, 1], + ], + color: COLORS.O, + }, + T: { + shape: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + color: COLORS.T, + }, + S: { + shape: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + color: COLORS.S, + }, + Z: { + shape: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + color: COLORS.Z, + }, + J: { + shape: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + color: COLORS.J, + }, + L: { + shape: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], + color: COLORS.L, + }, +}; +// SRS wall-kick data (JLSTZ pieces) +const WALL_KICKS = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// I-piece wall-kick data +const I_WALL_KICKS = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// Scoring: line clear points per level (index = lines cleared - 1) +const LINE_POINTS = [100, 300, 500, 800]; +let board = []; +let currentPiece = null; +let nextPieceType = ""; +let score = 0; +let lines = 0; +let level = 1; +let gameOver = false; +let paused = false; +let dropInterval = 1000; // ms +let lastDrop = 0; +let animationId = 0; +let bag = []; +let lockDelay = 500; // ms +let lockTimer = 0; +let lockActive = false; +// DAS (Delayed Auto Shift) +const DAS_DELAY = 170; // ms before auto-repeat starts +const DAS_RATE = 50; // ms between repeated moves +let dasDirection = null; +let dasTimer = 0; +let dasRepeating = false; +let keysDown = new Set(); +// Soft drop +let softDropping = false; +// ─── Canvas Setup ──────────────────────────────────────────────────── +const canvas = document.getElementById("game-canvas"); +const ctx = canvas.getContext("2d"); +canvas.width = COLS * BLOCK_SIZE; +canvas.height = ROWS * BLOCK_SIZE; +const previewCanvas = document.getElementById("preview-canvas"); +const previewCtx = previewCanvas.getContext("2d"); +previewCanvas.width = 4 * PREVIEW_BLOCK; +previewCanvas.height = 4 * PREVIEW_BLOCK; +const scoreEl = document.getElementById("score"); +const linesEl = document.getElementById("lines"); +const levelEl = document.getElementById("level"); +const messageEl = document.getElementById("message"); +// ─── 7-Bag Randomizer ─────────────────────────────────────────────── +function shuffle(arr) { + for (let i = arr.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [arr[i], arr[j]] = [arr[j], arr[i]]; + } + return arr; +} +function nextFromBag() { + if (bag.length === 0) { + bag = shuffle(Object.keys(PIECES)); + } + return bag.pop(); +} +// ─── Board Helpers ─────────────────────────────────────────────────── +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function cloneShape(shape) { + return shape.map(row => [...row]); +} +function rotateShapeCW(shape) { + const n = shape.length; + const rotated = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + rotated[c][n - 1 - r] = shape[r][c]; + } + } + return rotated; +} +function rotateShapeCCW(shape) { + const n = shape.length; + const rotated = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + rotated[n - 1 - c][r] = shape[r][c]; + } + } + return rotated; +} +function collides(shape, px, py) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = px + c; + const by = py + r; + if (bx < 0 || bx >= COLS || by >= ROWS) + return true; + if (by >= 0 && board[by][bx] !== null) + return true; + } + } + return false; +} +// ─── Piece Spawn / Lock ───────────────────────────────────────────── +function spawnPiece(type) { + const def = PIECES[type]; + const shape = cloneShape(def.shape); + const x = Math.floor((COLS - shape[0].length) / 2); + const y = -1; // Spawn partially above the top + return { type, shape, rotation: 0, x, y }; +} +function lockPiece() { + if (!currentPiece) + return; + const { shape, x, y, type } = currentPiece; + const color = PIECES[type].color; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = x + c; + const by = y + r; + if (by < 0) { + triggerGameOver(); + return; + } + board[by][bx] = color; + } + } + clearLines(); + currentPiece = spawnPiece(nextPieceType); + nextPieceType = nextFromBag(); + lockActive = false; + lockTimer = 0; + // Check if new piece immediately collides → game over + if (collides(currentPiece.shape, currentPiece.x, currentPiece.y)) { + triggerGameOver(); + } +} +function clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every(cell => cell !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // recheck this row index + } + } + if (cleared > 0) { + lines += cleared; + score += (LINE_POINTS[Math.min(cleared, 4) - 1] ?? 800) * level; + const newLevel = Math.floor(lines / 10) + 1; + if (newLevel !== level) { + level = newLevel; + dropInterval = Math.max(50, 1000 - (level - 1) * 80); + } + updateHUD(); + } +} +function triggerGameOver() { + gameOver = true; + cancelAnimationFrame(animationId); + messageEl.textContent = "GAME OVER — Press R to restart"; + messageEl.style.display = "block"; +} +function updateHUD() { + scoreEl.textContent = score.toString(); + linesEl.textContent = lines.toString(); + levelEl.textContent = level.toString(); +} +// ─── Movement ──────────────────────────────────────────────────────── +function movePiece(dx, dy) { + if (!currentPiece) + return false; + if (!collides(currentPiece.shape, currentPiece.x + dx, currentPiece.y + dy)) { + currentPiece.x += dx; + currentPiece.y += dy; + // If we moved and we were in lock delay, reset lock timer + if (lockActive && dy === 0) { + lockTimer = performance.now(); + } + return true; + } + return false; +} +function rotatePieceCW() { + if (!currentPiece || currentPiece.type === "O") + return; + const oldRotation = currentPiece.rotation; + const newRotation = (oldRotation + 1) % 4; + const newShape = rotateShapeCW(currentPiece.shape); + const key = `${oldRotation}>${newRotation}`; + const kicks = currentPiece.type === "I" ? I_WALL_KICKS[key] : WALL_KICKS[key]; + for (const [kx, ky] of kicks) { + if (!collides(newShape, currentPiece.x + kx, currentPiece.y - ky)) { + currentPiece.shape = newShape; + currentPiece.rotation = newRotation; + currentPiece.x += kx; + currentPiece.y -= ky; + if (lockActive) + lockTimer = performance.now(); + return; + } + } +} +function rotatePieceCCW() { + if (!currentPiece || currentPiece.type === "O") + return; + const oldRotation = currentPiece.rotation; + const newRotation = (oldRotation + 3) % 4; + const newShape = rotateShapeCCW(currentPiece.shape); + const key = `${oldRotation}>${newRotation}`; + const kicks = currentPiece.type === "I" ? I_WALL_KICKS[key] : WALL_KICKS[key]; + for (const [kx, ky] of kicks) { + if (!collides(newShape, currentPiece.x + kx, currentPiece.y - ky)) { + currentPiece.shape = newShape; + currentPiece.rotation = newRotation; + currentPiece.x += kx; + currentPiece.y -= ky; + if (lockActive) + lockTimer = performance.now(); + return; + } + } +} +function hardDrop() { + if (!currentPiece) + return; + let dropped = 0; + while (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) { + currentPiece.y++; + dropped++; + } + score += dropped * 2; + updateHUD(); + lockPiece(); +} +function ghostY() { + if (!currentPiece) + return 0; + let gy = currentPiece.y; + while (!collides(currentPiece.shape, currentPiece.x, gy + 1)) { + gy++; + } + return gy; +} +// ─── Rendering ─────────────────────────────────────────────────────── +function drawBlock(context, x, y, size, color, alpha = 1) { + context.globalAlpha = alpha; + context.fillStyle = color; + context.fillRect(x * size, y * size, size, size); + // Highlight + context.fillStyle = "rgba(255,255,255,0.25)"; + context.fillRect(x * size, y * size, size, size * 0.15); + context.fillRect(x * size, y * size, size * 0.15, size); + // Shadow + context.fillStyle = "rgba(0,0,0,0.25)"; + context.fillRect(x * size, y * size + size * 0.85, size, size * 0.15); + context.fillRect(x * size + size * 0.85, y * size, size * 0.15, size); + // Border + context.globalAlpha = alpha * 0.6; + context.strokeStyle = "#000"; + context.lineWidth = 1; + context.strokeRect(x * size + 0.5, y * size + 0.5, size - 1, size - 1); + context.globalAlpha = 1; +} +function drawBoard() { + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(canvas.width, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, canvas.height); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c]) { + drawBlock(ctx, c, r, BLOCK_SIZE, board[r][c]); + } + } + } +} +function drawGhost() { + if (!currentPiece) + return; + const gy = ghostY(); + if (gy === currentPiece.y) + return; + const color = PIECES[currentPiece.type].color; + for (let r = 0; r < currentPiece.shape.length; r++) { + for (let c = 0; c < currentPiece.shape[r].length; c++) { + if (!currentPiece.shape[r][c]) + continue; + const bx = currentPiece.x + c; + const by = gy + r; + if (by >= 0) { + drawBlock(ctx, bx, by, BLOCK_SIZE, color, GHOST_ALPHA); + } + } + } +} +function drawCurrentPiece() { + if (!currentPiece) + return; + const color = PIECES[currentPiece.type].color; + for (let r = 0; r < currentPiece.shape.length; r++) { + for (let c = 0; c < currentPiece.shape[r].length; c++) { + if (!currentPiece.shape[r][c]) + continue; + const bx = currentPiece.x + c; + const by = currentPiece.y + r; + if (by >= 0) { + drawBlock(ctx, bx, by, BLOCK_SIZE, color); + } + } + } +} +function drawPreview() { + previewCtx.fillStyle = "#1a1a2e"; + previewCtx.fillRect(0, 0, previewCanvas.width, previewCanvas.height); + const def = PIECES[nextPieceType]; + if (!def) + return; + const shape = def.shape; + // Center the piece in the preview + const offsetX = (4 - shape[0].length) / 2; + const offsetY = (4 - shape.length) / 2; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + drawBlock(previewCtx, c + offsetX, r + offsetY, PREVIEW_BLOCK, def.color); + } + } + } +} +function render() { + drawBoard(); + drawGhost(); + drawCurrentPiece(); + drawPreview(); +} +// ─── Game Loop ─────────────────────────────────────────────────────── +function gameLoop(timestamp) { + if (gameOver || paused) + return; + // DAS (auto-repeat horizontal movement) + if (dasDirection !== null) { + const elapsed = timestamp - dasTimer; + if (!dasRepeating && elapsed >= DAS_DELAY) { + dasRepeating = true; + dasTimer = timestamp; + const dx = dasDirection === "left" ? -1 : 1; + movePiece(dx, 0); + } + else if (dasRepeating && elapsed >= DAS_RATE) { + dasTimer = timestamp; + const dx = dasDirection === "left" ? -1 : 1; + movePiece(dx, 0); + } + } + // Gravity + const effectiveInterval = softDropping ? Math.max(dropInterval / 20, 30) : dropInterval; + if (timestamp - lastDrop >= effectiveInterval) { + lastDrop = timestamp; + if (currentPiece) { + if (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) { + currentPiece.y++; + if (softDropping) { + score += 1; + updateHUD(); + } + lockActive = false; + } + else { + // Piece can't move down — start or continue lock delay + if (!lockActive) { + lockActive = true; + lockTimer = timestamp; + } + } + } + } + // Lock delay check + if (lockActive && currentPiece) { + if (timestamp - lockTimer >= lockDelay) { + lockPiece(); + } + } + render(); + animationId = requestAnimationFrame(gameLoop); +} +// ─── Input ─────────────────────────────────────────────────────────── +document.addEventListener("keydown", (e) => { + if (gameOver) { + if (e.key === "r" || e.key === "R") { + initGame(); + } + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + paused = !paused; + if (paused) { + messageEl.textContent = "PAUSED — Press P to resume"; + messageEl.style.display = "block"; + } + else { + messageEl.style.display = "none"; + lastDrop = performance.now(); + animationId = requestAnimationFrame(gameLoop); + } + return; + } + if (paused) + return; + // Prevent page scroll on arrow keys and space + if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", " "].includes(e.key)) { + e.preventDefault(); + } + if (keysDown.has(e.key)) + return; // ignore repeat events + keysDown.add(e.key); + switch (e.key) { + case "ArrowLeft": + movePiece(-1, 0); + dasDirection = "left"; + dasTimer = performance.now(); + dasRepeating = false; + break; + case "ArrowRight": + movePiece(1, 0); + dasDirection = "right"; + dasTimer = performance.now(); + dasRepeating = false; + break; + case "ArrowDown": + softDropping = true; + break; + case "ArrowUp": + rotatePieceCW(); + break; + case "z": + case "Z": + rotatePieceCCW(); + break; + case " ": + hardDrop(); + break; + } +}); +document.addEventListener("keyup", (e) => { + keysDown.delete(e.key); + if (e.key === "ArrowLeft") { + if (dasDirection === "left") { + dasDirection = keysDown.has("ArrowRight") ? "right" : null; + dasRepeating = false; + } + } + if (e.key === "ArrowRight") { + if (dasDirection === "right") { + dasDirection = keysDown.has("ArrowLeft") ? "left" : null; + dasRepeating = false; + } + } + if (e.key === "ArrowDown") { + softDropping = false; + } +}); +// ─── Init ──────────────────────────────────────────────────────────── +function initGame() { + board = createBoard(); + bag = []; + score = 0; + lines = 0; + level = 1; + dropInterval = 1000; + gameOver = false; + paused = false; + lockActive = false; + lockTimer = 0; + softDropping = false; + dasDirection = null; + keysDown.clear(); + nextPieceType = nextFromBag(); + currentPiece = spawnPiece(nextFromBag()); + nextPieceType = nextFromBag(); + updateHUD(); + messageEl.style.display = "none"; + cancelAnimationFrame(animationId); + lastDrop = performance.now(); + animationId = requestAnimationFrame(gameLoop); +} +initGame(); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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C,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;CA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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,540 @@ +"use strict"; +// ============================================================ +// Tetris – a fully playable browser game in TypeScript +// ============================================================ +// --------------- Constants & Types --------------- +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 30; +const PREVIEW_BLOCK = 20; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const GHOST_ALPHA = 0.25; +const SHAPES = { + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + O: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +// SRS wall-kick data (offsets for rotations) +const KICK_DATA_NORMAL = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +const KICK_DATA_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +function getMatrix(piece) { + return SHAPES[piece.type][piece.rotation]; +} +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +// --------------- Collision --------------- +function collides(board, piece) { + const matrix = getMatrix(piece); + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (matrix[r][c]) { + const newX = piece.x + c; + const newY = piece.y + r; + if (newX < 0 || newX >= COLS || newY >= ROWS) + return true; + if (newY >= 0 && board[newY][newX] !== null) + return true; + } + } + } + return false; +} +const PIECE_TYPES = Object.keys(SHAPES); +function shuffledBag() { + const bag = [...PIECE_TYPES]; + for (let i = bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [bag[i], bag[j]] = [bag[j], bag[i]]; + } + return bag; +} +function nextFromBag(state) { + if (state.bag.length === 0) { + state.bag = shuffledBag(); + } + return state.bag.pop(); +} +function spawnPiece(type) { + const matrix = SHAPES[type][0]; + const cols = matrix[0].length; + return { + type, + rotation: 0, + x: Math.floor((COLS - cols) / 2), + y: -1, + }; +} +function calcDropInterval(level) { + // NES-style speed curve (ms per drop) + return Math.max(50, 1000 - (level - 1) * 80); +} +function createGameState() { + const bag = shuffledBag(); + const firstType = bag.pop(); + const secondType = bag.pop(); + return { + board: createBoard(), + current: spawnPiece(firstType), + next: spawnPiece(secondType), + score: 0, + lines: 0, + level: 1, + gameOver: false, + paused: false, + dropInterval: calcDropInterval(1), + lastDrop: performance.now(), + bag, + lockDelay: 500, + lockTimer: 0, + holdPiece: null, + holdUsed: false, + }; +} +// --------------- Actions --------------- +function lockPiece(state) { + const matrix = getMatrix(state.current); + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (matrix[r][c]) { + const bx = state.current.x + c; + const by = state.current.y + r; + if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) { + state.board[by][bx] = COLORS[state.current.type]; + } + } + } + } +} +function clearLines(state) { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (state.board[r].every((cell) => cell !== null)) { + state.board.splice(r, 1); + state.board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check this row + } + } + return cleared; +} +const LINE_SCORES = [0, 100, 300, 500, 800]; +function addScore(state, linesCleared) { + state.score += (LINE_SCORES[linesCleared] || 0) * state.level; + state.lines += linesCleared; + const newLevel = Math.floor(state.lines / 10) + 1; + if (newLevel !== state.level) { + state.level = newLevel; + state.dropInterval = calcDropInterval(state.level); + } +} +function tryMove(state, dx, dy) { + const moved = { ...state.current, x: state.current.x + dx, y: state.current.y + dy }; + if (!collides(state.board, moved)) { + state.current = moved; + return true; + } + return false; +} +function tryRotate(state, dir) { + const oldRot = state.current.rotation; + let newRot = (oldRot + dir + 4) % 4; + const kickTable = state.current.type === "I" ? KICK_DATA_I : KICK_DATA_NORMAL; + const key = `${oldRot}>${newRot}`; + const kicks = kickTable[key] || [[0, 0]]; + for (const [kx, ky] of kicks) { + const test = { ...state.current, rotation: newRot, x: state.current.x + kx, y: state.current.y - ky }; + if (!collides(state.board, test)) { + state.current = test; + return true; + } + } + return false; +} +function hardDrop(state) { + let dropped = 0; + while (tryMove(state, 0, 1)) { + dropped++; + } + state.score += dropped * 2; + placePiece(state); +} +function holdSwap(state) { + if (state.holdUsed) + return; + state.holdUsed = true; + const currentType = state.current.type; + if (state.holdPiece) { + state.current = spawnPiece(state.holdPiece); + state.holdPiece = currentType; + } + else { + state.holdPiece = currentType; + state.current = state.next; + state.next = spawnPiece(nextFromBag(state)); + } +} +function placePiece(state) { + lockPiece(state); + const linesCleared = clearLines(state); + addScore(state, linesCleared); + state.holdUsed = false; + // Spawn next piece + state.current = state.next; + state.next = spawnPiece(nextFromBag(state)); + if (collides(state.board, state.current)) { + state.gameOver = true; + } + state.lockTimer = 0; +} +function getGhostY(board, piece) { + let ghost = { ...piece }; + while (!collides(board, { ...ghost, y: ghost.y + 1 })) { + ghost.y++; + } + return ghost.y; +} +// --------------- Rendering --------------- +function drawBlock(ctx, x, y, size, color, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size, y * size, size, size); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x * size, y * size, size, 2); + ctx.fillRect(x * size, y * size, 2, size); + // Shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x * size + size - 2, y * size, 2, size); + ctx.fillRect(x * size, y * size + size - 2, size, 2); + // Grid border + ctx.strokeStyle = "rgba(0,0,0,0.3)"; + ctx.lineWidth = 1; + ctx.strokeRect(x * size, y * size, size, size); + ctx.globalAlpha = 1; +} +function drawBoard(ctx, board) { + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(COLS * BLOCK_SIZE, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c]) { + drawBlock(ctx, c, r, BLOCK_SIZE, board[r][c]); + } + } + } +} +function drawPiece(ctx, piece, size, offsetX = 0, offsetY = 0, alpha = 1) { + const matrix = getMatrix(piece); + const color = COLORS[piece.type]; + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (matrix[r][c]) { + const drawY = piece.y + r + offsetY; + const drawX = piece.x + c + offsetX; + if (drawY >= 0) { + drawBlock(ctx, drawX, drawY, size, color, alpha); + } + } + } + } +} +function drawPreview(ctx, piece, label, ox, oy) { + ctx.fillStyle = "#ccc"; + ctx.font = "bold 14px monospace"; + ctx.fillText(label, ox, oy - 8); + const matrix = getMatrix(piece); + const color = COLORS[piece.type]; + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (matrix[r][c]) { + ctx.fillStyle = color; + const bx = ox + c * PREVIEW_BLOCK; + const by = oy + r * PREVIEW_BLOCK; + ctx.fillRect(bx, by, PREVIEW_BLOCK, PREVIEW_BLOCK); + ctx.strokeStyle = "rgba(0,0,0,0.4)"; + ctx.lineWidth = 1; + ctx.strokeRect(bx, by, PREVIEW_BLOCK, PREVIEW_BLOCK); + } + } + } +} +function drawHUD(ctx, state) { + const panelX = COLS * BLOCK_SIZE + 15; + ctx.fillStyle = "#ccc"; + ctx.font = "bold 16px monospace"; + ctx.fillText(`Score`, panelX, 30); + ctx.fillText(`${state.score}`, panelX, 52); + ctx.fillText(`Level`, panelX, 90); + ctx.fillText(`${state.level}`, panelX, 112); + ctx.fillText(`Lines`, panelX, 150); + ctx.fillText(`${state.lines}`, panelX, 172); + // Next piece preview + drawPreview(ctx, state.next, "NEXT", panelX, 210); + // Hold piece preview + if (state.holdPiece) { + const holdPiece = spawnPiece(state.holdPiece); + drawPreview(ctx, holdPiece, "HOLD", panelX, 340); + } + else { + ctx.fillStyle = "#ccc"; + ctx.font = "bold 14px monospace"; + ctx.fillText("HOLD", panelX, 332); + ctx.fillStyle = "#555"; + ctx.font = "12px monospace"; + ctx.fillText("(empty)", panelX, 358); + } +} +function drawOverlay(ctx, text, subtext) { + ctx.fillStyle = "rgba(0,0,0,0.65)"; + ctx.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.fillStyle = "#fff"; + ctx.font = "bold 30px monospace"; + ctx.textAlign = "center"; + ctx.fillText(text, (COLS * BLOCK_SIZE) / 2, ROWS * BLOCK_SIZE / 2 - 15); + ctx.font = "16px monospace"; + ctx.fillStyle = "#aaa"; + ctx.fillText(subtext, (COLS * BLOCK_SIZE) / 2, ROWS * BLOCK_SIZE / 2 + 20); + ctx.textAlign = "left"; +} +// --------------- Main Game Loop --------------- +function main() { + const canvas = document.getElementById("game-canvas"); + const ctx = canvas.getContext("2d"); + const totalWidth = COLS * BLOCK_SIZE + 160; + const totalHeight = ROWS * BLOCK_SIZE; + canvas.width = totalWidth; + canvas.height = totalHeight; + let state = createGameState(); + // DAS (Delayed Auto Shift) state + const dasDelay = 170; // ms before auto-repeat starts + const dasRate = 50; // ms between repeats + const keysDown = {}; + let dasKey = null; + let dasTimer = 0; + let dasRepeatTimer = 0; + function handleKey(key) { + if (state.gameOver || state.paused) + return; + switch (key) { + case "ArrowLeft": + tryMove(state, -1, 0); + break; + case "ArrowRight": + tryMove(state, 1, 0); + break; + case "ArrowDown": + if (tryMove(state, 0, 1)) { + state.score += 1; // soft drop score + state.lastDrop = performance.now(); + } + break; + case "ArrowUp": + case "x": + tryRotate(state, 1); + break; + case "z": + tryRotate(state, -1); + break; + case " ": + hardDrop(state); + state.lastDrop = performance.now(); + break; + case "c": + case "Shift": + holdSwap(state); + break; + } + } + document.addEventListener("keydown", (e) => { + if (e.repeat) + return; + // Global keys + if (e.key === "p" || e.key === "Escape") { + if (!state.gameOver) { + state.paused = !state.paused; + if (!state.paused) + state.lastDrop = performance.now(); + } + return; + } + if (e.key === "r") { + state = createGameState(); + return; + } + keysDown[e.key] = true; + // Prevent scrolling for game keys + if (["ArrowLeft", "ArrowRight", "ArrowDown", "ArrowUp", " "].includes(e.key)) { + e.preventDefault(); + } + handleKey(e.key); + // Start DAS for directional keys + if (e.key === "ArrowLeft" || e.key === "ArrowRight" || e.key === "ArrowDown") { + dasKey = e.key; + dasTimer = performance.now(); + dasRepeatTimer = 0; + } + }); + document.addEventListener("keyup", (e) => { + delete keysDown[e.key]; + if (e.key === dasKey) { + dasKey = null; + } + }); + function processDAS(now) { + if (!dasKey || !keysDown[dasKey]) { + dasKey = null; + return; + } + const elapsed = now - dasTimer; + if (elapsed >= dasDelay) { + if (dasRepeatTimer === 0) { + dasRepeatTimer = dasTimer + dasDelay; + } + while (now - dasRepeatTimer >= dasRate) { + handleKey(dasKey); + dasRepeatTimer += dasRate; + } + } + } + function update(now) { + if (state.gameOver || state.paused) + return; + processDAS(now); + // Gravity + if (now - state.lastDrop >= state.dropInterval) { + if (!tryMove(state, 0, 1)) { + // Piece can't move down – lock delay + state.lockTimer += now - state.lastDrop; + if (state.lockTimer >= state.lockDelay) { + placePiece(state); + } + } + else { + state.lockTimer = 0; + } + state.lastDrop = now; + } + } + function render() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + // Fill entire canvas bg + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Draw board + drawBoard(ctx, state.board); + if (!state.gameOver && !state.paused) { + // Ghost piece + const ghostY = getGhostY(state.board, state.current); + const ghostPiece = { ...state.current, y: ghostY }; + drawPiece(ctx, ghostPiece, BLOCK_SIZE, 0, 0, GHOST_ALPHA); + // Current piece + drawPiece(ctx, state.current, BLOCK_SIZE); + } + // HUD + drawHUD(ctx, state); + // Overlays + if (state.paused) { + drawOverlay(ctx, "PAUSED", "Press P to resume"); + } + if (state.gameOver) { + drawOverlay(ctx, "GAME OVER", "Press R to restart"); + } + } + function gameLoop(now) { + update(now); + render(); + requestAnimationFrame(gameLoop); + } + requestAnimationFrame(gameLoop); +} +// Start when DOM is ready +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", main); +} +else { + main(); +} +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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C,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,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AC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,602 @@ +"use strict"; +// ─── Constants ─────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 30; +const SIDEBAR_WIDTH = 180; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const LOCK_DELAY = 500; // ms before a landed piece locks +const LOCK_MOVE_LIMIT = 15; // max resets of the lock timer +const LINES_PER_LEVEL = 10; +// Wall‑kick data (SRS) for J, L, S, T, Z pieces +const JLSTZ_KICKS = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +const I_KICKS = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// Each shape is defined by its cells for rotation state 0. +// We store all 4 rotation states explicitly. +const SHAPES = { + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + O: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +// ─── Helpers ───────────────────────────────────────────────────────────────── +function getLevel(totalLines) { + return Math.floor(totalLines / LINES_PER_LEVEL); +} +function getDropInterval(level) { + // NES‑style speed curve (capped at level 29‑equivalent) + const framesPerRow = Math.max(1, Math.floor(((0.8 - level * 0.007) ** level) * 1000)); + return Math.max(50, framesPerRow); +} +// 7‑bag randomiser +function createBag() { + const types = ["I", "O", "T", "S", "Z", "J", "L"]; + for (let i = types.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [types[i], types[j]] = [types[j], types[i]]; + } + return types; +} +function emptyBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +let board = emptyBoard(); +let current; +let heldPiece = null; +let canHold = true; +let bag = []; +let nextQueue = []; +let score = 0; +let lines = 0; +let level = 0; +let gameOver = false; +let paused = false; +let lastDrop = 0; +let lockTimer = null; +let lockMoves = 0; +let animatingRows = []; +let animationStart = 0; +const ANIMATION_DURATION = 300; // ms +// ─── Canvas Setup ──────────────────────────────────────────────────────────── +const canvas = document.getElementById("game"); +const ctx = canvas.getContext("2d"); +canvas.width = COLS * BLOCK_SIZE + SIDEBAR_WIDTH; +canvas.height = ROWS * BLOCK_SIZE; +// ─── Piece helpers ─────────────────────────────────────────────────────────── +function pieceCells(p) { + const shape = SHAPES[p.type][p.rotation]; + const cells = []; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) + cells.push([p.y + r, p.x + c]); + } + } + return cells; +} +function collides(p, b) { + for (const [r, c] of pieceCells(p)) { + if (r < 0 || r >= ROWS || c < 0 || c >= COLS) + return true; + if (b[r][c] !== null) + return true; + } + return false; +} +function spawnPiece(type) { + const shape = SHAPES[type][0]; + const cols = shape[0].length; + return { type, rotation: 0, x: Math.floor((COLS - cols) / 2), y: 0 }; +} +function nextPieceType() { + if (bag.length === 0) + bag = createBag(); + return bag.pop(); +} +function fillQueue() { + while (nextQueue.length < 3) { + nextQueue.push(nextPieceType()); + } +} +function popQueue() { + fillQueue(); + const t = nextQueue.shift(); + fillQueue(); + return t; +} +// ─── Core Mechanics ────────────────────────────────────────────────────────── +function resetLock() { + if (lockTimer !== null && lockMoves < LOCK_MOVE_LIMIT) { + lockTimer = performance.now(); + lockMoves++; + } +} +function tryMove(dx, dy) { + const moved = { ...current, x: current.x + dx, y: current.y + dy }; + if (!collides(moved, board)) { + current = moved; + resetLock(); + return true; + } + return false; +} +function tryRotate(dir) { + const oldR = current.rotation; + const newR = ((oldR + dir) % 4 + 4) % 4; + const kicks = current.type === "I" ? I_KICKS : (current.type === "O" ? null : JLSTZ_KICKS); + if (!kicks) + return false; // O piece – no rotation needed (shape doesn't change) + const key = `${oldR}>${newR}`; + const tests = kicks[key]; + if (!tests) + return false; + for (const [kx, ky] of tests) { + const candidate = { ...current, rotation: newR, x: current.x + kx, y: current.y - ky }; + if (!collides(candidate, board)) { + current = candidate; + resetLock(); + return true; + } + } + return false; +} +function hardDrop() { + let dropDist = 0; + while (!collides({ ...current, y: current.y + 1 }, board)) { + current.y++; + dropDist++; + } + score += dropDist * 2; + lockPiece(); +} +function lockPiece() { + const color = COLORS[current.type]; + for (const [r, c] of pieceCells(current)) { + if (r >= 0 && r < ROWS && c >= 0 && c < COLS) { + board[r][c] = color; + } + } + lockTimer = null; + lockMoves = 0; + clearLines(); +} +function clearLines() { + const full = []; + for (let r = 0; r < ROWS; r++) { + if (board[r].every(cell => cell !== null)) + full.push(r); + } + if (full.length > 0) { + animatingRows = full; + animationStart = performance.now(); + } + else { + spawnNext(); + } +} +function finishClear() { + const full = animatingRows; + animatingRows = []; + // Scoring (original BPS / Nintendo) + const pts = [0, 100, 300, 500, 800]; + score += (pts[full.length] ?? 0) * (level + 1); + lines += full.length; + level = getLevel(lines); + // Remove rows top‑down (indexes stay valid because we splice from top) + for (const r of full.sort((a, b) => a - b)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + } + spawnNext(); +} +function spawnNext() { + canHold = true; + current = spawnPiece(popQueue()); + if (collides(current, board)) { + gameOver = true; + } + lastDrop = performance.now(); +} +function hold() { + if (!canHold) + return; + canHold = false; + const type = current.type; + if (heldPiece) { + current = spawnPiece(heldPiece); + } + else { + current = spawnPiece(popQueue()); + } + heldPiece = type; + lockTimer = null; + lockMoves = 0; + lastDrop = performance.now(); +} +function ghostY() { + let gy = current.y; + while (!collides({ ...current, y: gy + 1 }, board)) + gy++; + return gy; +} +// ─── Drawing ───────────────────────────────────────────────────────────────── +function drawBlock(x, y, color, ghost = false) { + const bx = x * BLOCK_SIZE; + const by = y * BLOCK_SIZE; + if (ghost) { + ctx.strokeStyle = color; + ctx.lineWidth = 2; + ctx.globalAlpha = 0.35; + ctx.strokeRect(bx + 1, by + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + ctx.globalAlpha = 1; + return; + } + ctx.fillStyle = color; + ctx.fillRect(bx, by, BLOCK_SIZE, BLOCK_SIZE); + // highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(bx, by, BLOCK_SIZE, 3); + ctx.fillRect(bx, by, 3, BLOCK_SIZE); + // shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(bx, by + BLOCK_SIZE - 3, BLOCK_SIZE, 3); + ctx.fillRect(bx + BLOCK_SIZE - 3, by, 3, BLOCK_SIZE); + // border + ctx.strokeStyle = "#111"; + ctx.lineWidth = 1; + ctx.strokeRect(bx, by, BLOCK_SIZE, BLOCK_SIZE); +} +function drawSmallBlock(px, py, color, size) { + ctx.fillStyle = color; + ctx.fillRect(px, py, size, size); + ctx.strokeStyle = "#111"; + ctx.lineWidth = 1; + ctx.strokeRect(px, py, size, size); +} +function drawMiniPiece(type, cx, cy, size) { + const shape = SHAPES[type][0]; + const color = COLORS[type]; + const h = shape.length; + const w = shape[0].length; + const offX = cx - (w * size) / 2; + const offY = cy - (h * size) / 2; + for (let r = 0; r < h; r++) { + for (let c = 0; c < w; c++) { + if (shape[r][c]) + drawSmallBlock(offX + c * size, offY + r * size, color, size); + } + } +} +function draw(now) { + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Grid + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(COLS * BLOCK_SIZE, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.stroke(); + } + // Board cells + for (let r = 0; r < ROWS; r++) { + // Handle animation flash for clearing rows + if (animatingRows.includes(r)) { + const elapsed = now - animationStart; + const progress = Math.min(elapsed / ANIMATION_DURATION, 1); + const flash = Math.sin(progress * Math.PI * 3) > 0; + if (flash) { + ctx.fillStyle = "#fff"; + ctx.fillRect(0, r * BLOCK_SIZE, COLS * BLOCK_SIZE, BLOCK_SIZE); + } + continue; + } + for (let c = 0; c < COLS; c++) { + if (board[r][c]) + drawBlock(c, r, board[r][c]); + } + } + if (!gameOver && animatingRows.length === 0) { + // Ghost piece + const gy = ghostY(); + const ghostCells = pieceCells({ ...current, y: gy }); + for (const [r, c] of ghostCells) { + if (r >= 0) + drawBlock(c, r, COLORS[current.type], true); + } + // Current piece + const color = COLORS[current.type]; + for (const [r, c] of pieceCells(current)) { + if (r >= 0) + drawBlock(c, r, color); + } + } + // ── Sidebar ────────────────────────────────────────────────────────────── + const sx = COLS * BLOCK_SIZE + 12; + ctx.fillStyle = "#ccc"; + ctx.font = "bold 16px monospace"; + // Score / Level / Lines + ctx.fillText("SCORE", sx, 30); + ctx.fillText(String(score), sx, 50); + ctx.fillText("LEVEL", sx, 80); + ctx.fillText(String(level), sx, 100); + ctx.fillText("LINES", sx, 130); + ctx.fillText(String(lines), sx, 150); + // Next + ctx.fillText("NEXT", sx, 190); + for (let i = 0; i < nextQueue.length; i++) { + drawMiniPiece(nextQueue[i], sx + 40, 220 + i * 55, 16); + } + // Hold + ctx.fillStyle = "#ccc"; + ctx.fillText("HOLD", sx, 400); + if (heldPiece) { + drawMiniPiece(heldPiece, sx + 40, 430, 16); + } + // Game over / pause overlay + if (gameOver) { + ctx.fillStyle = "rgba(0,0,0,0.65)"; + ctx.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.fillStyle = "#f44"; + ctx.font = "bold 36px monospace"; + ctx.textAlign = "center"; + ctx.fillText("GAME OVER", (COLS * BLOCK_SIZE) / 2, ROWS * BLOCK_SIZE / 2 - 20); + ctx.fillStyle = "#ccc"; + ctx.font = "18px monospace"; + ctx.fillText("Press R to restart", (COLS * BLOCK_SIZE) / 2, ROWS * BLOCK_SIZE / 2 + 20); + ctx.textAlign = "left"; + } + else if (paused) { + ctx.fillStyle = "rgba(0,0,0,0.55)"; + ctx.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.fillStyle = "#fff"; + ctx.font = "bold 30px monospace"; + ctx.textAlign = "center"; + ctx.fillText("PAUSED", (COLS * BLOCK_SIZE) / 2, ROWS * BLOCK_SIZE / 2); + ctx.textAlign = "left"; + } + // Controls legend at very bottom of sidebar + ctx.fillStyle = "#888"; + ctx.font = "11px monospace"; + const controlsX = sx; + ctx.fillText("← → Move", controlsX, 490); + ctx.fillText("↓ Soft drop", controlsX, 505); + ctx.fillText("↑/X Rotate CW", controlsX, 520); + ctx.fillText("Z Rotate CCW", controlsX, 535); + ctx.fillText("SPC Hard drop", controlsX, 550); + ctx.fillText("C Hold", controlsX, 565); + ctx.fillText("P Pause", controlsX, 580); + ctx.fillText("R Restart", controlsX, 595); +} +// ─── Input ─────────────────────────────────────────────────────────────────── +// DAS (Delayed Auto Shift) +const DAS_DELAY = 170; // ms before auto‑repeat starts +const DAS_RATE = 50; // ms between auto‑repeat moves +let dasDir = 0; // -1 left, 1 right, 0 none +let dasTimer = 0; +let dasRepeating = false; +let softDropping = false; +document.addEventListener("keydown", (e) => { + if (e.key === "r" || e.key === "R") { + restart(); + return; + } + if (gameOver) + return; + if (e.key === "p" || e.key === "P") { + paused = !paused; + return; + } + if (paused) + return; + if (animatingRows.length > 0) + return; + switch (e.key) { + case "ArrowLeft": + e.preventDefault(); + if (dasDir !== -1) { + dasDir = -1; + dasTimer = performance.now(); + dasRepeating = false; + tryMove(-1, 0); + } + break; + case "ArrowRight": + e.preventDefault(); + if (dasDir !== 1) { + dasDir = 1; + dasTimer = performance.now(); + dasRepeating = false; + tryMove(1, 0); + } + break; + case "ArrowDown": + e.preventDefault(); + softDropping = true; + if (tryMove(0, 1)) { + score += 1; + lastDrop = performance.now(); + } + break; + case "ArrowUp": + case "x": + case "X": + e.preventDefault(); + tryRotate(1); + break; + case "z": + case "Z": + e.preventDefault(); + tryRotate(-1); + break; + case " ": + e.preventDefault(); + hardDrop(); + break; + case "c": + case "C": + hold(); + break; + } +}); +document.addEventListener("keyup", (e) => { + if (e.key === "ArrowLeft" && dasDir === -1) + dasDir = 0; + if (e.key === "ArrowRight" && dasDir === 1) + dasDir = 0; + if (e.key === "ArrowDown") + softDropping = false; +}); +// ─── Game Loop ─────────────────────────────────────────────────────────────── +function restart() { + board = emptyBoard(); + bag = []; + nextQueue = []; + fillQueue(); + score = 0; + lines = 0; + level = 0; + heldPiece = null; + canHold = true; + gameOver = false; + paused = false; + lockTimer = null; + lockMoves = 0; + animatingRows = []; + current = spawnPiece(popQueue()); + lastDrop = performance.now(); + dasDir = 0; + softDropping = false; +} +function update(now) { + if (gameOver || paused) + return; + // Handle line clear animation + if (animatingRows.length > 0) { + if (now - animationStart >= ANIMATION_DURATION) { + finishClear(); + } + return; + } + // DAS auto‑repeat + if (dasDir !== 0) { + const elapsed = now - dasTimer; + if (!dasRepeating && elapsed >= DAS_DELAY) { + dasRepeating = true; + dasTimer = now; + tryMove(dasDir, 0); + } + else if (dasRepeating && elapsed >= DAS_RATE) { + dasTimer = now; + tryMove(dasDir, 0); + } + } + // Gravity + const interval = softDropping ? Math.min(getDropInterval(level), 50) : getDropInterval(level); + if (now - lastDrop >= interval) { + if (!tryMove(0, 1)) { + // Piece landed – start lock delay + if (lockTimer === null) { + lockTimer = now; + } + } + else { + if (softDropping) + score += 1; + } + lastDrop = now; + } + // Lock delay + if (lockTimer !== null) { + // Verify still on ground + if (!collides({ ...current, y: current.y + 1 }, board)) { + // Piece is no longer on ground (moved off ledge etc.) + lockTimer = null; + lockMoves = 0; + } + else if (now - lockTimer >= LOCK_DELAY || lockMoves >= LOCK_MOVE_LIMIT) { + lockPiece(); + } + } +} +function gameLoop(now) { + update(now); + draw(now); + requestAnimationFrame(gameLoop); +} +// Kick things off +restart(); +requestAnimationFrame(gameLoop); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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AC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1C;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACb,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACb,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACb,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KACd;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,482 @@ +"use strict"; +// ─── Types & Constants ─────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 32; +const PREVIEW_BLOCK = 20; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const GHOST_ALPHA = 0.25; +const PIECES = { + I: { shape: [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], color: COLORS.I }, + O: { shape: [[1, 1], [1, 1]], color: COLORS.O }, + T: { shape: [[0, 1, 0], [1, 1, 1], [0, 0, 0]], color: COLORS.T }, + S: { shape: [[0, 1, 1], [1, 1, 0], [0, 0, 0]], color: COLORS.S }, + Z: { shape: [[1, 1, 0], [0, 1, 1], [0, 0, 0]], color: COLORS.Z }, + J: { shape: [[1, 0, 0], [1, 1, 1], [0, 0, 0]], color: COLORS.J }, + L: { shape: [[0, 0, 1], [1, 1, 1], [0, 0, 0]], color: COLORS.L }, +}; +// SRS wall-kick data (non-I pieces) +const WALL_KICKS = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// SRS wall-kick data for I piece +const WALL_KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +const PIECE_NAMES = Object.keys(PIECES); +// Scoring (original Nintendo scoring) +const LINE_SCORES = [0, 100, 300, 500, 800]; +// ─── Game State ────────────────────────────────────────────────────── +let board = []; +let currentPiece = null; +let nextPiece = null; +let score = 0; +let lines = 0; +let level = 1; +let gameOver = false; +let paused = false; +let dropTimer = 0; +let lastTime = 0; +let animationId = 0; +let lockDelay = 0; +let lockDelayMax = 500; // ms before piece locks +let lockMoveResets = 0; +let lockMoveResetsMax = 15; +// Bag randomizer: generates pieces in shuffled sets of 7 +let bag = []; +function shuffledBag() { + const arr = [...PIECE_NAMES]; + for (let i = arr.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [arr[i], arr[j]] = [arr[j], arr[i]]; + } + return arr; +} +function nextFromBag() { + if (bag.length === 0) + bag = shuffledBag(); + return bag.pop(); +} +// ─── Canvas Setup ──────────────────────────────────────────────────── +const canvas = document.getElementById("game-canvas"); +const ctx = canvas.getContext("2d"); +canvas.width = COLS * BLOCK_SIZE; +canvas.height = ROWS * BLOCK_SIZE; +const previewCanvas = document.getElementById("preview-canvas"); +const previewCtx = previewCanvas.getContext("2d"); +previewCanvas.width = 6 * PREVIEW_BLOCK; +previewCanvas.height = 4 * PREVIEW_BLOCK; +const scoreEl = document.getElementById("score"); +const linesEl = document.getElementById("lines"); +const levelEl = document.getElementById("level"); +const messageEl = document.getElementById("message"); +// ─── Board Helpers ─────────────────────────────────────────────────── +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function collides(shape, bx, by) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = bx + c; + const ny = by + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && board[ny][nx] !== null) + return true; + } + } + return false; +} +function lockPiece() { + if (!currentPiece) + return; + const { shape, color, x, y } = currentPiece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const ny = y + r; + const nx = x + c; + if (ny < 0) { + triggerGameOver(); + return; + } + board[ny][nx] = color; + } + } + clearLines(); + spawnPiece(); +} +function clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every((cell) => cell !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check same row index + } + } + if (cleared > 0) { + lines += cleared; + score += LINE_SCORES[cleared] * level; + const newLevel = Math.floor(lines / 10) + 1; + if (newLevel > level) + level = newLevel; + updateHUD(); + } +} +function getDropSpeed() { + // Speeds up as level increases, capped at very fast + return Math.max(50, 1000 - (level - 1) * 80); +} +// ─── Piece Helpers ─────────────────────────────────────────────────── +function rotateCW(shape) { + const n = shape.length; + const rotated = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + rotated[c][n - 1 - r] = shape[r][c]; + } + } + return rotated; +} +function rotateCCW(shape) { + const n = shape.length; + const rotated = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + rotated[n - 1 - c][r] = shape[r][c]; + } + } + return rotated; +} +function tryRotate(direction) { + if (!currentPiece) + return; + const { shape, x, y, type, rotation } = currentPiece; + const newShape = direction === 1 ? rotateCW(shape) : rotateCCW(shape); + const newRotation = ((rotation + direction) % 4 + 4) % 4; + const kickKey = `${rotation}>${newRotation}`; + const kicks = type === "I" ? WALL_KICKS_I[kickKey] : WALL_KICKS[kickKey]; + if (kicks) { + for (const [dx, dy] of kicks) { + if (!collides(newShape, x + dx, y - dy)) { + currentPiece.shape = newShape; + currentPiece.x = x + dx; + currentPiece.y = y - dy; + currentPiece.rotation = newRotation; + resetLockDelay(); + return; + } + } + } + else { + // Fallback: no kicks (shouldn't happen with full SRS) + if (!collides(newShape, x, y)) { + currentPiece.shape = newShape; + currentPiece.rotation = newRotation; + resetLockDelay(); + } + } +} +function ghostY() { + if (!currentPiece) + return 0; + let gy = currentPiece.y; + while (!collides(currentPiece.shape, currentPiece.x, gy + 1)) + gy++; + return gy; +} +function resetLockDelay() { + if (lockMoveResets < lockMoveResetsMax) { + lockDelay = 0; + lockMoveResets++; + } +} +// ─── Spawning ──────────────────────────────────────────────────────── +function makePiece(name) { + const def = PIECES[name]; + return { + shape: def.shape.map((r) => [...r]), + color: def.color, + type: name, + }; +} +function spawnPiece() { + if (!nextPiece) + nextPiece = makePiece(nextFromBag()); + const p = nextPiece; + nextPiece = makePiece(nextFromBag()); + const spawnX = Math.floor((COLS - p.shape[0].length) / 2); + const spawnY = -1; // start partially above the board + currentPiece = { ...p, x: spawnX, y: spawnY, rotation: 0 }; + lockDelay = 0; + lockMoveResets = 0; + if (collides(currentPiece.shape, currentPiece.x, currentPiece.y)) { + // Try one row higher + currentPiece.y = -2; + if (collides(currentPiece.shape, currentPiece.x, currentPiece.y)) { + triggerGameOver(); + } + } +} +// ─── Drawing ───────────────────────────────────────────────────────── +function drawBlock(context, x, y, color, size, alpha = 1) { + context.globalAlpha = alpha; + context.fillStyle = color; + context.fillRect(x * size, y * size, size, size); + // Bevel highlight + context.fillStyle = "rgba(255,255,255,0.3)"; + context.fillRect(x * size, y * size, size, 3); + context.fillRect(x * size, y * size, 3, size); + // Bevel shadow + context.fillStyle = "rgba(0,0,0,0.3)"; + context.fillRect(x * size, (y + 1) * size - 3, size, 3); + context.fillRect((x + 1) * size - 3, y * size, 3, size); + // Outline + context.strokeStyle = "rgba(0,0,0,0.5)"; + context.lineWidth = 1; + context.strokeRect(x * size, y * size, size, size); + context.globalAlpha = 1; +} +function drawBoard() { + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + ctx.lineWidth = 1; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(canvas.width, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, canvas.height); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c]) { + drawBlock(ctx, c, r, board[r][c], BLOCK_SIZE); + } + } + } +} +function drawGhost() { + if (!currentPiece) + return; + const gy = ghostY(); + if (gy === currentPiece.y) + return; + const { shape, color } = currentPiece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const ny = gy + r; + if (ny < 0) + continue; + drawBlock(ctx, currentPiece.x + c, ny, color, BLOCK_SIZE, GHOST_ALPHA); + } + } +} +function drawCurrentPiece() { + if (!currentPiece) + return; + const { shape, color, x, y } = currentPiece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const ny = y + r; + if (ny < 0) + continue; + drawBlock(ctx, x + c, ny, color, BLOCK_SIZE); + } + } +} +function drawPreview() { + previewCtx.fillStyle = "#1a1a2e"; + previewCtx.fillRect(0, 0, previewCanvas.width, previewCanvas.height); + if (!nextPiece) + return; + const { shape, color } = nextPiece; + const offsetX = (6 - shape[0].length) / 2; + const offsetY = (4 - shape.length) / 2; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + drawBlock(previewCtx, offsetX + c, offsetY + r, color, PREVIEW_BLOCK); + } + } +} +function updateHUD() { + scoreEl.textContent = score.toLocaleString(); + linesEl.textContent = String(lines); + levelEl.textContent = String(level); +} +// ─── Game Loop ─────────────────────────────────────────────────────── +function update(dt) { + if (!currentPiece || gameOver || paused) + return; + dropTimer += dt; + // Check if piece is resting on surface + const onSurface = collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1); + if (onSurface) { + lockDelay += dt; + if (lockDelay >= lockDelayMax) { + lockPiece(); + dropTimer = 0; + return; + } + } + else { + lockDelay = 0; + } + if (dropTimer >= getDropSpeed()) { + dropTimer = 0; + if (!onSurface) { + currentPiece.y++; + } + } +} +function render() { + drawBoard(); + drawGhost(); + drawCurrentPiece(); + drawPreview(); +} +function gameLoop(timestamp) { + const dt = timestamp - lastTime; + lastTime = timestamp; + update(dt); + render(); + animationId = requestAnimationFrame(gameLoop); +} +function triggerGameOver() { + gameOver = true; + messageEl.textContent = "GAME OVER — Press R to restart"; + messageEl.style.display = "block"; +} +// ─── Input ─────────────────────────────────────────────────────────── +document.addEventListener("keydown", (e) => { + if (gameOver) { + if (e.key === "r" || e.key === "R") { + startGame(); + } + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + paused = !paused; + messageEl.textContent = paused ? "PAUSED" : ""; + messageEl.style.display = paused ? "block" : "none"; + return; + } + if (paused || !currentPiece) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + if (!collides(currentPiece.shape, currentPiece.x - 1, currentPiece.y)) { + currentPiece.x--; + resetLockDelay(); + } + e.preventDefault(); + break; + case "ArrowRight": + case "d": + if (!collides(currentPiece.shape, currentPiece.x + 1, currentPiece.y)) { + currentPiece.x++; + resetLockDelay(); + } + e.preventDefault(); + break; + case "ArrowDown": + case "s": + if (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) { + currentPiece.y++; + score += 1; // soft drop bonus + dropTimer = 0; + updateHUD(); + } + e.preventDefault(); + break; + case "ArrowUp": + case "w": + tryRotate(1); // CW + e.preventDefault(); + break; + case "z": + case "Z": + tryRotate(-1); // CCW + e.preventDefault(); + break; + case " ": + // Hard drop + { + let dropped = 0; + while (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) { + currentPiece.y++; + dropped++; + } + score += dropped * 2; + updateHUD(); + lockPiece(); + dropTimer = 0; + } + e.preventDefault(); + break; + } +}); +// ─── Start / Restart ───────────────────────────────────────────────── +function startGame() { + board = createBoard(); + score = 0; + lines = 0; + level = 1; + gameOver = false; + paused = false; + dropTimer = 0; + lastTime = performance.now(); + bag = []; + currentPiece = null; + nextPiece = null; + messageEl.style.display = "none"; + updateHUD(); + spawnPiece(); + cancelAnimationFrame(animationId); + animationId = requestAnimationFrame(gameLoop); +} +startGame(); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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AAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;CAC1C,CAAC;AAEF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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,448 @@ +"use strict"; +// ── Types ────────────────────────────────────────────────────────────────── +// ── Constants ────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell +const PREVIEW_BLOCK = 20; // px per cell in next-piece preview +const INITIAL_DROP_INTERVAL = 800; // ms +const MIN_DROP_INTERVAL = 80; +const SPEED_DECREMENT = 50; // ms faster per level +const LINES_PER_LEVEL = 10; +const LINE_POINTS = [0, 100, 300, 500, 800]; // 0,1,2,3,4 lines +// Standard 7 tetrominoes (SRS rotations) +const TETROMINOES = [ + { + shapes: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + color: "#00f0f0", + }, + { + shapes: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + color: "#f0f000", + }, + { + shapes: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + color: "#a000f0", + }, + { + shapes: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + color: "#00f000", + }, + { + shapes: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + color: "#f00000", + }, + { + shapes: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + color: "#0000f0", + }, + { + shapes: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], + color: "#f0a000", + }, +]; +// ── Game State ───────────────────────────────────────────────────────────── +class TetrisGame { + constructor(canvas, previewCanvas, scoreEl, levelEl, linesEl, gameOverEl) { + this.canvas = canvas; + this.previewCanvas = previewCanvas; + this.scoreEl = scoreEl; + this.levelEl = levelEl; + this.linesEl = linesEl; + this.gameOverEl = gameOverEl; + // ── Game loop ────────────────────────────────────────────────────────── + this.loop = (now) => { + if (this.gameOver || this.paused) + return; + if (now - this.lastDrop > this.dropInterval) { + this.moveDown(); + this.lastDrop = now; + this.updateHUD(); + } + this.draw(); + this.animFrameId = requestAnimationFrame(this.loop); + }; + this.ctx = canvas.getContext("2d"); + this.previewCtx = previewCanvas.getContext("2d"); + canvas.width = COLS * BLOCK; + canvas.height = ROWS * BLOCK; + previewCanvas.width = 4 * PREVIEW_BLOCK; + previewCanvas.height = 4 * PREVIEW_BLOCK; + this.board = []; + this.score = 0; + this.level = 1; + this.lines = 0; + this.dropInterval = INITIAL_DROP_INTERVAL; + this.gameOver = false; + this.paused = false; + this.rotationIndex = 0; + this.nextRotationIndex = 0; + this.nextTetrominoIdx = 0; + this.currentTetrominoIdx = 0; + this.lastDrop = 0; + this.animFrameId = 0; + this.current = this.spawnPiece(); + this.next = this.spawnPiece(); + this.init(); + } + // ── Initialisation ───────────────────────────────────────────────────── + init() { + this.board = this.createBoard(); + this.score = 0; + this.level = 1; + this.lines = 0; + this.dropInterval = INITIAL_DROP_INTERVAL; + this.gameOver = false; + this.paused = false; + this.gameOverEl.style.display = "none"; + this.rotationIndex = 0; + this.currentTetrominoIdx = this.randomTetromino(); + this.current = this.buildPiece(this.currentTetrominoIdx, 0); + this.nextRotationIndex = 0; + this.nextTetrominoIdx = this.randomTetromino(); + this.next = this.buildPiece(this.nextTetrominoIdx, 0); + this.updateHUD(); + this.drawPreview(); + this.lastDrop = performance.now(); + if (this.animFrameId) + cancelAnimationFrame(this.animFrameId); + this.loop(performance.now()); + } + restart() { + this.init(); + } + // ── Board helpers ────────────────────────────────────────────────────── + createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); + } + randomTetromino() { + return Math.floor(Math.random() * TETROMINOES.length); + } + buildPiece(tetrominoIdx, rotation) { + const t = TETROMINOES[tetrominoIdx]; + const shape = t.shapes[rotation]; + return { + shape, + color: t.color, + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + }; + } + spawnPiece() { + const idx = this.randomTetromino(); + return this.buildPiece(idx, 0); + } + // ── Collision detection ──────────────────────────────────────────────── + collides(shape, px, py) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = px + c; + const ny = py + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && this.board[ny][nx]) + return true; + } + } + return false; + } + // ── Piece actions ────────────────────────────────────────────────────── + moveLeft() { + if (this.gameOver || this.paused) + return; + if (!this.collides(this.current.shape, this.current.x - 1, this.current.y)) { + this.current.x--; + } + } + moveRight() { + if (this.gameOver || this.paused) + return; + if (!this.collides(this.current.shape, this.current.x + 1, this.current.y)) { + this.current.x++; + } + } + moveDown() { + if (this.gameOver || this.paused) + return false; + if (!this.collides(this.current.shape, this.current.x, this.current.y + 1)) { + this.current.y++; + return true; + } + this.lock(); + return false; + } + hardDrop() { + if (this.gameOver || this.paused) + return; + let dropDist = 0; + while (!this.collides(this.current.shape, this.current.x, this.current.y + 1)) { + this.current.y++; + dropDist++; + } + this.score += dropDist * 2; + this.lock(); + } + rotate() { + if (this.gameOver || this.paused) + return; + const nextRot = (this.rotationIndex + 1) % 4; + const newShape = TETROMINOES[this.currentTetrominoIdx].shapes[nextRot]; + // Try basic rotation, then wall kicks (-1, +1, -2, +2) + const kicks = [0, -1, 1, -2, 2]; + for (const kick of kicks) { + if (!this.collides(newShape, this.current.x + kick, this.current.y)) { + this.current.shape = newShape; + this.current.x += kick; + this.rotationIndex = nextRot; + return; + } + } + } + togglePause() { + if (this.gameOver) + return; + this.paused = !this.paused; + if (!this.paused) { + this.lastDrop = performance.now(); + this.loop(performance.now()); + } + } + // ── Lock, clear, spawn ──────────────────────────────────────────────── + lock() { + const { shape, color, x, y } = this.current; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const ny = y + r; + const nx = x + c; + if (ny < 0) { + this.endGame(); + return; + } + this.board[ny][nx] = color; + } + } + this.clearLines(); + this.advancePiece(); + this.updateHUD(); + } + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every((c) => c !== null)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // recheck same row index after splice + } + } + if (cleared > 0) { + this.lines += cleared; + this.score += LINE_POINTS[cleared] * this.level; + const newLevel = Math.floor(this.lines / LINES_PER_LEVEL) + 1; + if (newLevel > this.level) { + this.level = newLevel; + this.dropInterval = Math.max(MIN_DROP_INTERVAL, INITIAL_DROP_INTERVAL - (this.level - 1) * SPEED_DECREMENT); + } + this.updateHUD(); + } + } + advancePiece() { + this.current = this.next; + this.currentTetrominoIdx = this.nextTetrominoIdx; + this.rotationIndex = this.nextRotationIndex; + this.nextRotationIndex = 0; + this.nextTetrominoIdx = this.randomTetromino(); + this.next = this.buildPiece(this.nextTetrominoIdx, 0); + // check instant death + if (this.collides(this.current.shape, this.current.x, this.current.y)) { + this.endGame(); + } + this.drawPreview(); + } + endGame() { + this.gameOver = true; + this.gameOverEl.style.display = "flex"; + cancelAnimationFrame(this.animFrameId); + } + // ── HUD ──────────────────────────────────────────────────────────────── + updateHUD() { + this.scoreEl.textContent = String(this.score); + this.levelEl.textContent = String(this.level); + this.linesEl.textContent = String(this.lines); + } + // ── Ghost piece (shadow) ─────────────────────────────────────────────── + ghostY() { + let gy = this.current.y; + while (!this.collides(this.current.shape, this.current.x, gy + 1)) { + gy++; + } + return gy; + } + // ── Drawing ──────────────────────────────────────────────────────────── + drawBlock(ctx, x, y, color, size, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size, y * size, size, size); + // highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x * size, y * size, size, size * 0.15); + ctx.fillRect(x * size, y * size, size * 0.15, size); + // shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x * size, y * size + size * 0.85, size, size * 0.15); + ctx.fillRect(x * size + size * 0.85, y * size, size * 0.15, size); + ctx.globalAlpha = 1; + // border + ctx.strokeStyle = "#111"; + ctx.lineWidth = 0.5; + ctx.strokeRect(x * size, y * size, size, size); + } + draw() { + const ctx = this.ctx; + ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + // background grid + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK, r * BLOCK, BLOCK, BLOCK); + } + } + // locked blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.board[r][c]) { + this.drawBlock(ctx, c, r, this.board[r][c], BLOCK); + } + } + } + // ghost + if (!this.gameOver) { + const gy = this.ghostY(); + const { shape, color, x } = this.current; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + this.drawBlock(ctx, x + c, gy + r, color, BLOCK, 0.25); + } + } + } + } + // current piece + if (!this.gameOver) { + const { shape, color, x, y } = this.current; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + this.drawBlock(ctx, x + c, y + r, color, BLOCK); + } + } + } + } + } + drawPreview() { + const ctx = this.previewCtx; + ctx.clearRect(0, 0, this.previewCanvas.width, this.previewCanvas.height); + ctx.fillStyle = "#1a1a1a"; + ctx.fillRect(0, 0, this.previewCanvas.width, this.previewCanvas.height); + const { shape, color } = this.next; + const offsetX = Math.floor((4 - shape[0].length) / 2); + const offsetY = Math.floor((4 - shape.length) / 2); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + this.drawBlock(ctx, offsetX + c, offsetY + r, color, PREVIEW_BLOCK); + } + } + } + } +} +// ── Bootstrap ──────────────────────────────────────────────────────────── +function bootstrap() { + const canvas = document.getElementById("game-canvas"); + const preview = document.getElementById("preview-canvas"); + const scoreEl = document.getElementById("score"); + const levelEl = document.getElementById("level"); + const linesEl = document.getElementById("lines"); + const gameOverEl = document.getElementById("game-over"); + const restartBtn = document.getElementById("restart-btn"); + const game = new TetrisGame(canvas, preview, scoreEl, levelEl, linesEl, gameOverEl); + document.addEventListener("keydown", (e) => { + switch (e.key) { + case "ArrowLeft": + e.preventDefault(); + game.moveLeft(); + break; + case "ArrowRight": + e.preventDefault(); + game.moveRight(); + break; + case "ArrowDown": + e.preventDefault(); + game.moveDown(); + break; + case "ArrowUp": + e.preventDefault(); + game.rotate(); + break; + case " ": + e.preventDefault(); + game.hardDrop(); + break; + case "p": + case "P": + e.preventDefault(); + game.togglePause(); + break; + case "r": + case "R": + e.preventDefault(); + game.restart(); + break; + } + }); + restartBtn.addEventListener("click", () => game.restart()); +} +document.addEventListener("DOMContentLoaded", bootstrap); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run1/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run1/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,611 @@ +"use strict"; +// ─── Types & Constants ─────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const CELL_SIZE = 32; +const PREVIEW_CELLS = 4; +const LOCK_DELAY_MS = 500; +const LINES_PER_LEVEL = 10; +const BASE_SPEED_MS = 800; +const MIN_SPEED_MS = 50; +const SPEED_DECREASE_PER_LEVEL = 50; +// SRS wall-kick data (for J, L, S, T, Z pieces) +const WALL_KICKS_JLSTZ = { + "0>1": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "1>0": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "1>2": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "2>1": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "2>3": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "3>2": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "3>0": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "0>3": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], +}; +// SRS wall-kick data for I piece +const WALL_KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, 1], [1, -2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, -1], [-1, 2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, -2], [2, 1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, 2], [-2, -1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, -1], [-1, 2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, 1], [1, -2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, 2], [-2, -1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, -2], [2, 1]], +}; +// ─── Tetromino Definitions ─────────────────────────────────────────── +const TETROMINOES = { + I: { + color: "#00f0f0", + shape: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + }, + O: { + color: "#f0f000", + shape: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + }, + T: { + color: "#a000f0", + shape: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + }, + S: { + color: "#00f000", + shape: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + }, + Z: { + color: "#f00000", + shape: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + }, + J: { + color: "#0000f0", + shape: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + }, + L: { + color: "#f0a000", + shape: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], + }, +}; +const PIECE_NAMES = Object.keys(TETROMINOES); +// ─── Scoring ───────────────────────────────────────────────────────── +function getLinePoints(lines, level) { + const base = [0, 100, 300, 500, 800]; + return (base[lines] ?? 0) * (level + 1); +} +// ─── 7-Bag Randomizer ─────────────────────────────────────────────── +class BagRandomizer { + constructor() { + this.bag = []; + } + next() { + if (this.bag.length === 0) { + this.bag = [...PIECE_NAMES]; + // Fisher-Yates shuffle + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop(); + } +} +// ─── Piece ─────────────────────────────────────────────────────────── +class Piece { + constructor(name) { + this.name = name; + this.rotation = 0; + this.color = TETROMINOES[name].color; + const shape = this.getShape(); + // Center horizontally; start above the visible board + this.pos = { + x: Math.floor((COLS - shape[0].length) / 2), + y: -this.topFilledRow(), + }; + } + getShape(rotation) { + return TETROMINOES[this.name].shape[rotation ?? this.rotation]; + } + topFilledRow() { + const shape = this.getShape(); + for (let r = 0; r < shape.length; r++) { + if (shape[r].some((c) => c !== 0)) + return r; + } + return 0; + } + clone() { + const p = new Piece(this.name); + p.rotation = this.rotation; + p.pos = { ...this.pos }; + return p; + } +} +// ─── Game ──────────────────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.heldPiece = null; + this.canHold = true; + this.score = 0; + this.level = 0; + this.linesCleared = 0; + this.gameOver = false; + this.paused = false; + this.dropTimer = 0; + this.lockTimer = null; + this.lastTime = 0; + this.animationId = 0; + // Line-clear animation + this.clearingRows = []; + this.clearAnimTimer = 0; + this.CLEAR_ANIM_DURATION = 300; // ms + // ── Game Loop ─────────────────────────────────── + this.loop = (time) => { + const dt = time - this.lastTime; + this.lastTime = time; + if (!this.gameOver && !this.paused) { + this.update(dt); + } + this.draw(); + this.animationId = requestAnimationFrame(this.loop); + }; + this.bag = new BagRandomizer(); + this.board = this.createBoard(); + const gameCanvas = document.getElementById("game-canvas"); + const previewCanvas = document.getElementById("preview-canvas"); + const holdCanvas = document.getElementById("hold-canvas"); + gameCanvas.width = COLS * CELL_SIZE; + gameCanvas.height = ROWS * CELL_SIZE; + previewCanvas.width = PREVIEW_CELLS * CELL_SIZE; + previewCanvas.height = PREVIEW_CELLS * CELL_SIZE; + holdCanvas.width = PREVIEW_CELLS * CELL_SIZE; + holdCanvas.height = PREVIEW_CELLS * CELL_SIZE; + this.ctx = gameCanvas.getContext("2d"); + this.previewCtx = previewCanvas.getContext("2d"); + this.holdCtx = holdCanvas.getContext("2d"); + this.scoreEl = document.getElementById("score"); + this.levelEl = document.getElementById("level"); + this.linesEl = document.getElementById("lines"); + this.overlayEl = document.getElementById("overlay"); + this.overlayTextEl = document.getElementById("overlay-text"); + this.spawnPiece(); + this.nextPiece = new Piece(this.bag.next()); + this.bindKeys(); + this.lastTime = performance.now(); + this.loop(this.lastTime); + } + // ── Board helpers ─────────────────────────────── + createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); + } + isValid(piece, dx = 0, dy = 0, rotation) { + const shape = piece.getShape(rotation); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = piece.pos.x + c + dx; + const ny = piece.pos.y + r + dy; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return false; + if (ny >= 0 && this.board[ny][nx] !== null) + return false; + } + } + return true; + } + lock(piece) { + const shape = piece.getShape(); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const y = piece.pos.y + r; + const x = piece.pos.x + c; + if (y < 0) { + this.triggerGameOver(); + return; + } + this.board[y][x] = piece.color; + } + } + this.canHold = true; + this.lockTimer = null; + this.checkLines(); + } + checkLines() { + const fullRows = []; + for (let r = 0; r < ROWS; r++) { + if (this.board[r].every((c) => c !== null)) { + fullRows.push(r); + } + } + if (fullRows.length > 0) { + this.clearingRows = fullRows; + this.clearAnimTimer = 0; + // Score & level + this.score += getLinePoints(fullRows.length, this.level); + this.linesCleared += fullRows.length; + this.level = Math.floor(this.linesCleared / LINES_PER_LEVEL); + } + else { + this.spawnPiece(); + } + } + removeFullRows() { + // Remove rows top-to-bottom so indices stay stable + for (const row of [...this.clearingRows].sort((a, b) => a - b)) { + this.board.splice(row, 1); + this.board.unshift(Array(COLS).fill(null)); + } + this.clearingRows = []; + this.spawnPiece(); + } + // ── Piece management ──────────────────────────── + spawnPiece() { + if (this.nextPiece) { + this.current = this.nextPiece; + } + else { + this.current = new Piece(this.bag.next()); + } + this.nextPiece = new Piece(this.bag.next()); + this.dropTimer = 0; + this.lockTimer = null; + if (!this.isValid(this.current)) { + this.triggerGameOver(); + } + } + triggerGameOver() { + this.gameOver = true; + this.overlayTextEl.textContent = "GAME OVER — Press R to restart"; + this.overlayEl.classList.remove("hidden"); + } + // ── Movement ──────────────────────────────────── + move(dx, dy) { + if (this.isValid(this.current, dx, dy)) { + this.current.pos.x += dx; + this.current.pos.y += dy; + return true; + } + return false; + } + rotate(dir) { + const oldRot = this.current.rotation; + const newRot = (oldRot + dir + 4) % 4; + const kicks = this.current.name === "I" ? WALL_KICKS_I : WALL_KICKS_JLSTZ; + const key = dir === 1 ? `${oldRot}>${newRot}` : `${oldRot}>${newRot}`; + const tests = kicks[key]; + if (!tests) + return; + for (const [kx, ky] of tests) { + if (this.isValid(this.current, kx, -ky, newRot)) { + this.current.rotation = newRot; + this.current.pos.x += kx; + this.current.pos.y += -ky; + return; + } + } + } + hardDrop() { + let rows = 0; + while (this.isValid(this.current, 0, 1)) { + this.current.pos.y++; + rows++; + } + this.score += rows * 2; + this.lock(this.current); + } + softDrop() { + if (this.move(0, 1)) { + this.score += 1; + this.dropTimer = 0; + } + } + hold() { + if (!this.canHold) + return; + this.canHold = false; + const name = this.current.name; + if (this.heldPiece) { + this.current = new Piece(this.heldPiece); + this.heldPiece = name; + this.dropTimer = 0; + this.lockTimer = null; + } + else { + this.heldPiece = name; + this.spawnPiece(); + } + } + ghostY() { + let gy = 0; + while (this.isValid(this.current, 0, gy + 1)) { + gy++; + } + return this.current.pos.y + gy; + } + // ── Speed ─────────────────────────────────────── + getSpeed() { + return Math.max(MIN_SPEED_MS, BASE_SPEED_MS - this.level * SPEED_DECREASE_PER_LEVEL); + } + // ── Input ─────────────────────────────────────── + bindKeys() { + document.addEventListener("keydown", (e) => { + if (e.key === "r" || e.key === "R") { + this.restart(); + return; + } + if (this.gameOver) + return; + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.togglePause(); + return; + } + if (this.paused || this.clearingRows.length > 0) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + e.preventDefault(); + this.move(-1, 0); + break; + case "ArrowRight": + case "d": + e.preventDefault(); + this.move(1, 0); + break; + case "ArrowDown": + case "s": + e.preventDefault(); + this.softDrop(); + break; + case "ArrowUp": + case "w": + e.preventDefault(); + this.rotate(1); + break; + case "z": + case "Z": + e.preventDefault(); + this.rotate(-1); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + case "c": + case "C": + case "Shift": + e.preventDefault(); + this.hold(); + break; + } + this.updateHUD(); + }); + } + togglePause() { + this.paused = !this.paused; + if (this.paused) { + this.overlayTextEl.textContent = "PAUSED — Press P to resume"; + this.overlayEl.classList.remove("hidden"); + } + else { + this.overlayEl.classList.add("hidden"); + this.lastTime = performance.now(); + } + } + restart() { + this.board = this.createBoard(); + this.bag = new BagRandomizer(); + this.score = 0; + this.level = 0; + this.linesCleared = 0; + this.gameOver = false; + this.paused = false; + this.heldPiece = null; + this.canHold = true; + this.clearingRows = []; + this.clearAnimTimer = 0; + this.lockTimer = null; + this.overlayEl.classList.add("hidden"); + this.nextPiece = new Piece(this.bag.next()); + this.spawnPiece(); + this.lastTime = performance.now(); + } + update(dt) { + // Line-clear animation + if (this.clearingRows.length > 0) { + this.clearAnimTimer += dt; + if (this.clearAnimTimer >= this.CLEAR_ANIM_DURATION) { + this.removeFullRows(); + } + return; + } + // Gravity + this.dropTimer += dt; + if (this.dropTimer >= this.getSpeed()) { + this.dropTimer = 0; + if (!this.move(0, 1)) { + // Piece can't move down – start or continue lock timer + if (this.lockTimer === null) { + this.lockTimer = 0; + } + } + else { + // Successfully moved down, reset lock timer + this.lockTimer = null; + } + } + // Lock delay + if (this.lockTimer !== null) { + this.lockTimer += dt; + // Reset if piece can still move down (e.g. player shifted it) + if (this.isValid(this.current, 0, 1)) { + this.lockTimer = null; + } + else if (this.lockTimer >= LOCK_DELAY_MS) { + this.lock(this.current); + } + } + this.updateHUD(); + } + updateHUD() { + this.scoreEl.textContent = this.score.toString(); + this.levelEl.textContent = this.level.toString(); + this.linesEl.textContent = this.linesCleared.toString(); + } + // ── Rendering ─────────────────────────────────── + draw() { + this.drawBoard(); + this.drawPreview(); + this.drawHold(); + } + drawBoard() { + const ctx = this.ctx; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, COLS * CELL_SIZE, ROWS * CELL_SIZE); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL_SIZE); + ctx.lineTo(COLS * CELL_SIZE, r * CELL_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL_SIZE, 0); + ctx.lineTo(c * CELL_SIZE, ROWS * CELL_SIZE); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.board[r][c]) { + // Flash clearing rows + if (this.clearingRows.includes(r)) { + const flash = Math.sin((this.clearAnimTimer / this.CLEAR_ANIM_DURATION) * Math.PI * 4); + ctx.fillStyle = flash > 0 ? "#fff" : this.board[r][c]; + } + else { + ctx.fillStyle = this.board[r][c]; + } + this.drawCell(ctx, c, r); + } + } + } + if (this.gameOver || this.clearingRows.length > 0) + return; + // Ghost piece + const ghostY = this.ghostY(); + const shape = this.current.getShape(); + ctx.globalAlpha = 0.2; + ctx.fillStyle = this.current.color; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const y = ghostY + r; + const x = this.current.pos.x + c; + if (y >= 0) + this.drawCell(ctx, x, y); + } + } + } + ctx.globalAlpha = 1.0; + // Current piece + ctx.fillStyle = this.current.color; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const y = this.current.pos.y + r; + const x = this.current.pos.x + c; + if (y >= 0) + this.drawCell(ctx, x, y); + } + } + } + } + drawPreview() { + this.drawSmallPiece(this.previewCtx, this.nextPiece.name); + } + drawHold() { + this.holdCtx.fillStyle = "#1a1a2e"; + this.holdCtx.fillRect(0, 0, PREVIEW_CELLS * CELL_SIZE, PREVIEW_CELLS * CELL_SIZE); + if (this.heldPiece) { + this.drawSmallPiece(this.holdCtx, this.heldPiece); + } + } + drawSmallPiece(ctx, name) { + const def = TETROMINOES[name]; + const shape = def.shape[0]; + const size = PREVIEW_CELLS * CELL_SIZE; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, size, size); + const rows = shape.length; + const cols = shape[0].length; + const offsetX = (size - cols * CELL_SIZE) / 2; + const offsetY = (size - rows * CELL_SIZE) / 2; + ctx.fillStyle = def.color; + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (shape[r][c]) { + const x = offsetX + c * CELL_SIZE; + const y = offsetY + r * CELL_SIZE; + ctx.fillRect(x + 1, y + 1, CELL_SIZE - 2, CELL_SIZE - 2); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.18)"; + ctx.fillRect(x + 1, y + 1, CELL_SIZE - 2, 4); + ctx.fillStyle = def.color; + } + } + } + } + drawCell(ctx, x, y) { + const px = x * CELL_SIZE; + const py = y * CELL_SIZE; + ctx.fillRect(px + 1, py + 1, CELL_SIZE - 2, CELL_SIZE - 2); + // Top highlight + const c = ctx.fillStyle; + ctx.fillStyle = "rgba(255,255,255,0.18)"; + ctx.fillRect(px + 1, py + 1, CELL_SIZE - 2, 4); + ctx.fillStyle = c; + } +} +// ─── Bootstrap ─────────────────────────────────────────────────────── +window.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,559 @@ +"use strict"; +// ─── Types ─────────────────────────────────────────────────────────────────── +// ─── Constants ─────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 32; +const PREVIEW_BLOCK = 24; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const SHAPES = { + I: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + O: [ + [1, 1], + [1, 1], + ], + T: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + S: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + Z: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + J: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + L: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], +}; +// SRS wall-kick data (non-I pieces) +const WALL_KICKS = { + "0>1": [{ x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "1>0": [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], + "1>2": [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], + "2>1": [{ x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "2>3": [{ x: 1, y: 0 }, { x: 1, y: -1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], + "3>2": [{ x: -1, y: 0 }, { x: -1, y: 1 }, { x: 0, y: -2 }, { x: -1, y: -2 }], + "3>0": [{ x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "0>3": [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], +}; +// SRS wall-kick data for I piece +const WALL_KICKS_I = { + "0>1": [{ x: -2, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 1 }, { x: 1, y: -2 }], + "1>0": [{ x: 2, y: 0 }, { x: -1, y: 0 }, { x: 2, y: -1 }, { x: -1, y: 2 }], + "1>2": [{ x: -1, y: 0 }, { x: 2, y: 0 }, { x: -1, y: -2 }, { x: 2, y: 1 }], + "2>1": [{ x: 1, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 2 }, { x: -2, y: -1 }], + "2>3": [{ x: 2, y: 0 }, { x: -1, y: 0 }, { x: 2, y: -1 }, { x: -1, y: 2 }], + "3>2": [{ x: -2, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 1 }, { x: 1, y: -2 }], + "3>0": [{ x: 1, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 2 }, { x: -2, y: -1 }], + "0>3": [{ x: -1, y: 0 }, { x: 2, y: 0 }, { x: -1, y: -2 }, { x: 2, y: 1 }], +}; +const PIECE_NAMES = Object.keys(SHAPES); +const LINES_PER_LEVEL = 10; +const BASE_SPEED = 800; // ms per drop at level 1 +// Scoring: index = number of lines cleared at once (1-4) +const SCORE_TABLE = [0, 100, 300, 500, 800]; +// ─── Helpers ───────────────────────────────────────────────────────────────── +function rotateMatrix(matrix) { + const n = matrix.length; + const result = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + result[c][n - 1 - r] = matrix[r][c]; + } + } + return result; +} +function randomPiece() { + const name = PIECE_NAMES[Math.floor(Math.random() * PIECE_NAMES.length)]; + return { + name, + tetromino: { + shape: SHAPES[name].map((row) => [...row]), + color: COLORS[name], + }, + }; +} +// ─── Game Class ────────────────────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.lastDrop = 0; + this.animationId = 0; + // For DAS (Delayed Auto Shift) + this.keysDown = new Set(); + this.dasTimer = {}; + this.DAS_DELAY = 170; // ms before auto-repeat starts + this.DAS_RATE = 50; // ms between auto-repeat moves + // Ghost piece + this.ghostPos = { x: 0, y: 0 }; + // Lock delay + this.lockTimer = 0; + this.LOCK_DELAY = 500; + this.isLocking = false; + this.canvas = document.getElementById("game-canvas"); + this.ctx = this.canvas.getContext("2d"); + this.canvas.width = COLS * BLOCK_SIZE; + this.canvas.height = ROWS * BLOCK_SIZE; + this.previewCanvas = document.getElementById("preview-canvas"); + this.previewCtx = this.previewCanvas.getContext("2d"); + this.previewCanvas.width = 4 * PREVIEW_BLOCK; + this.previewCanvas.height = 4 * PREVIEW_BLOCK; + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.messageEl = document.getElementById("message"); + this.board = this.createBoard(); + this.setupInput(); + this.init(); + } + // ─── Initialisation ───────────────────────────────────────────────────── + createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); + } + init() { + this.board = this.createBoard(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.lastDrop = 0; + this.isLocking = false; + this.updateHUD(); + this.messageEl.textContent = ""; + const first = randomPiece(); + const second = randomPiece(); + this.spawnPiece(first.name, first.tetromino); + this.nextName = second.name; + this.nextPiece = second.tetromino; + this.updateGhost(); + this.drawPreview(); + cancelAnimationFrame(this.animationId); + this.lastDrop = performance.now(); + this.animationId = requestAnimationFrame((t) => this.gameLoop(t)); + } + // ─── Piece management ─────────────────────────────────────────────────── + spawnPiece(name, piece) { + this.currentName = name; + this.currentPiece = piece; + this.currentRotation = 0; + this.currentPos = { + x: Math.floor((COLS - piece.shape[0].length) / 2), + y: 0, + }; + // If spawn collides, game over + if (this.collides(this.currentPiece.shape, this.currentPos)) { + this.gameOver = true; + } + } + collides(shape, pos) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = pos.x + c; + const by = pos.y + r; + if (bx < 0 || bx >= COLS || by >= ROWS) + return true; + if (by < 0) + continue; // allow pieces above the top + if (this.board[by][bx] !== null) + return true; + } + } + return false; + } + lockPiece() { + const shape = this.currentPiece.shape; + const pos = this.currentPos; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = pos.x + c; + const by = pos.y + r; + if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) { + this.board[by][bx] = this.currentPiece.color; + } + } + } + this.isLocking = false; + this.clearLines(); + this.advancePiece(); + } + advancePiece() { + this.spawnPiece(this.nextName, this.nextPiece); + const next = randomPiece(); + this.nextName = next.name; + this.nextPiece = next.tetromino; + this.updateGhost(); + this.drawPreview(); + } + // ─── Movement ─────────────────────────────────────────────────────────── + moveLeft() { + const newPos = { x: this.currentPos.x - 1, y: this.currentPos.y }; + if (!this.collides(this.currentPiece.shape, newPos)) { + this.currentPos = newPos; + this.resetLockIfNeeded(); + this.updateGhost(); + } + } + moveRight() { + const newPos = { x: this.currentPos.x + 1, y: this.currentPos.y }; + if (!this.collides(this.currentPiece.shape, newPos)) { + this.currentPos = newPos; + this.resetLockIfNeeded(); + this.updateGhost(); + } + } + moveDown() { + const newPos = { x: this.currentPos.x, y: this.currentPos.y + 1 }; + if (!this.collides(this.currentPiece.shape, newPos)) { + this.currentPos = newPos; + return true; + } + return false; + } + hardDrop() { + let dropDist = 0; + while (this.moveDown()) { + dropDist++; + } + this.score += dropDist * 2; + this.updateHUD(); + this.lockPiece(); + } + softDrop() { + if (this.moveDown()) { + this.score += 1; + this.updateHUD(); + this.lastDrop = performance.now(); + } + } + // ─── Rotation (SRS) ──────────────────────────────────────────────────── + rotate(direction) { + let newShape = this.currentPiece.shape; + if (direction === 1) { + newShape = rotateMatrix(newShape); + } + else { + // Rotate 3 times clockwise = 1 counter-clockwise + newShape = rotateMatrix(rotateMatrix(rotateMatrix(newShape))); + } + const oldRot = this.currentRotation; + const newRot = (oldRot + direction + 4) % 4; + const kickKey = `${oldRot}>${newRot}`; + // Try basic rotation first (no kick) + if (!this.collides(newShape, this.currentPos)) { + this.currentPiece.shape = newShape; + this.currentRotation = newRot; + this.resetLockIfNeeded(); + this.updateGhost(); + return; + } + // Try wall kicks + const kicks = this.currentName === "I" ? WALL_KICKS_I[kickKey] : WALL_KICKS[kickKey]; + if (kicks) { + for (const kick of kicks) { + const testPos = { + x: this.currentPos.x + kick.x, + y: this.currentPos.y - kick.y, // SRS y is inverted relative to screen + }; + if (!this.collides(newShape, testPos)) { + this.currentPiece.shape = newShape; + this.currentPos = testPos; + this.currentRotation = newRot; + this.resetLockIfNeeded(); + this.updateGhost(); + return; + } + } + } + } + // ─── Lock delay helpers ───────────────────────────────────────────────── + resetLockIfNeeded() { + if (this.isLocking) { + this.lockTimer = performance.now(); + } + } + // ─── Ghost piece ──────────────────────────────────────────────────────── + updateGhost() { + this.ghostPos = { ...this.currentPos }; + while (!this.collides(this.currentPiece.shape, { + x: this.ghostPos.x, + y: this.ghostPos.y + 1, + })) { + this.ghostPos.y++; + } + } + // ─── Line clearing ───────────────────────────────────────────────────── + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every((cell) => cell !== null)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check this row + } + } + if (cleared > 0) { + this.lines += cleared; + this.score += SCORE_TABLE[cleared] * this.level; + const newLevel = Math.floor(this.lines / LINES_PER_LEVEL) + 1; + if (newLevel > this.level) { + this.level = newLevel; + } + this.updateHUD(); + } + } + // ─── Speed ────────────────────────────────────────────────────────────── + getDropInterval() { + // Gradually speed up: each level reduces interval + return Math.max(50, BASE_SPEED - (this.level - 1) * 60); + } + // ─── Input ────────────────────────────────────────────────────────────── + setupInput() { + document.addEventListener("keydown", (e) => { + if (this.gameOver) { + if (e.key === "Enter") { + this.init(); + } + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.paused = !this.paused; + if (!this.paused) { + this.lastDrop = performance.now(); + this.animationId = requestAnimationFrame((t) => this.gameLoop(t)); + } + this.messageEl.textContent = this.paused ? "PAUSED" : ""; + return; + } + if (this.paused) + return; + // Prevent default for game keys + if (["ArrowLeft", "ArrowRight", "ArrowDown", "ArrowUp", " ", "z", "Z", "x", "X"].includes(e.key)) { + e.preventDefault(); + } + // Handle initial key press + if (!this.keysDown.has(e.key)) { + this.keysDown.add(e.key); + this.handleKeyAction(e.key); + // Start DAS timer + this.dasTimer[e.key] = window.setTimeout(() => { + this.dasRepeat(e.key); + }, this.DAS_DELAY); + } + }); + document.addEventListener("keyup", (e) => { + this.keysDown.delete(e.key); + if (this.dasTimer[e.key]) { + clearTimeout(this.dasTimer[e.key]); + delete this.dasTimer[e.key]; + } + }); + // Restart button + document.getElementById("restart-btn")?.addEventListener("click", () => { + this.init(); + }); + } + dasRepeat(key) { + if (!this.keysDown.has(key) || this.paused || this.gameOver) + return; + this.handleKeyAction(key); + this.dasTimer[key] = window.setTimeout(() => { + this.dasRepeat(key); + }, this.DAS_RATE); + } + handleKeyAction(key) { + switch (key) { + case "ArrowLeft": + this.moveLeft(); + break; + case "ArrowRight": + this.moveRight(); + break; + case "ArrowDown": + this.softDrop(); + break; + case "ArrowUp": + case "x": + case "X": + this.rotate(1); + break; + case "z": + case "Z": + this.rotate(-1); + break; + case " ": + this.hardDrop(); + break; + } + } + // ─── HUD ──────────────────────────────────────────────────────────────── + updateHUD() { + this.scoreEl.textContent = this.score.toString(); + this.linesEl.textContent = this.lines.toString(); + this.levelEl.textContent = this.level.toString(); + } + // ─── Rendering ────────────────────────────────────────────────────────── + drawBlock(ctx, x, y, color, size, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size + 1, y * size + 1, size - 2, size - 2); + // Highlight (top-left bevel) + ctx.fillStyle = "rgba(255,255,255,0.3)"; + ctx.fillRect(x * size + 1, y * size + 1, size - 2, 3); + ctx.fillRect(x * size + 1, y * size + 1, 3, size - 2); + // Shadow (bottom-right bevel) + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(x * size + 1, y * size + size - 4, size - 2, 3); + ctx.fillRect(x * size + size - 4, y * size + 1, 3, size - 2); + ctx.globalAlpha = 1; + } + draw() { + const ctx = this.ctx; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(COLS * BLOCK_SIZE, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.stroke(); + } + // Board (locked pieces) + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.board[r][c]) { + this.drawBlock(ctx, c, r, this.board[r][c], BLOCK_SIZE); + } + } + } + if (!this.gameOver) { + // Ghost piece + const gs = this.currentPiece.shape; + for (let r = 0; r < gs.length; r++) { + for (let c = 0; c < gs[r].length; c++) { + if (!gs[r][c]) + continue; + const bx = this.ghostPos.x + c; + const by = this.ghostPos.y + r; + if (by >= 0) { + this.drawBlock(ctx, bx, by, this.currentPiece.color, BLOCK_SIZE, 0.2); + } + } + } + // Current piece + const shape = this.currentPiece.shape; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = this.currentPos.x + c; + const by = this.currentPos.y + r; + if (by >= 0) { + this.drawBlock(ctx, bx, by, this.currentPiece.color, BLOCK_SIZE); + } + } + } + } + } + drawPreview() { + const ctx = this.previewCtx; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, this.previewCanvas.width, this.previewCanvas.height); + const shape = this.nextPiece.shape; + const offsetX = (4 - shape[0].length) / 2; + const offsetY = (4 - shape.length) / 2; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + this.drawBlock(ctx, c + offsetX, r + offsetY, this.nextPiece.color, PREVIEW_BLOCK); + } + } + } + } + // ─── Game loop ────────────────────────────────────────────────────────── + gameLoop(timestamp) { + if (this.gameOver) { + this.draw(); + this.messageEl.textContent = "GAME OVER — press Enter to restart"; + return; + } + if (this.paused) + return; + const dropInterval = this.getDropInterval(); + if (timestamp - this.lastDrop >= dropInterval) { + if (!this.moveDown()) { + // Piece can't move down + if (!this.isLocking) { + this.isLocking = true; + this.lockTimer = performance.now(); + } + } + else { + this.isLocking = false; + this.updateGhost(); + } + this.lastDrop = timestamp; + } + // Lock delay check + if (this.isLocking && performance.now() - this.lockTimer >= this.LOCK_DELAY) { + // Confirm the piece truly can't move down before locking + if (!this.collides(this.currentPiece.shape, { x: this.currentPos.x, y: this.currentPos.y + 1 })) { + this.isLocking = false; + } + else { + this.lockPiece(); + } + } + this.draw(); + this.animationId = requestAnimationFrame((t) => this.gameLoop(t)); + } +} +// ─── Bootstrap ─────────────────────────────────────────────────────────────── +document.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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E,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAA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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/tetris.js @@ -0,0 +1,351 @@ +"use strict"; +// ── Constants ──────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 32; // px per cell +const PREVIEW_BLOCK = 20; +const LINES_PER_LEVEL = 10; +const BASE_INTERVAL = 800; // ms at level 1 +const MIN_INTERVAL = 50; +const TETROMINOES = [ + { shape: [[1, 1, 1, 1]], color: "#00f0f0" }, // I + { shape: [[1, 0, 0], [1, 1, 1]], color: "#0000f0" }, // J + { shape: [[0, 0, 1], [1, 1, 1]], color: "#f0a000" }, // L + { shape: [[1, 1], [1, 1]], color: "#f0f000" }, // O + { shape: [[0, 1, 1], [1, 1, 0]], color: "#00f000" }, // S + { shape: [[0, 1, 0], [1, 1, 1]], color: "#a000f0" }, // T + { shape: [[1, 1, 0], [0, 1, 1]], color: "#f00000" }, // Z +]; +// ── Canvas setup ───────────────────────────────────────────────────── +const canvas = document.getElementById("game-canvas"); +const ctx = canvas.getContext("2d"); +const preview = document.getElementById("preview-canvas"); +const pctx = preview.getContext("2d"); +canvas.width = COLS * BLOCK; +canvas.height = ROWS * BLOCK; +preview.width = 4 * PREVIEW_BLOCK; +preview.height = 4 * PREVIEW_BLOCK; +// ── Game state ─────────────────────────────────────────────────────── +// Bag must be declared before spawnPiece() is called +let bag = []; +let board = createEmptyBoard(); +let current = spawnPiece(); +let next = spawnPiece(); +let score = 0; +let lines = 0; +let level = 1; +let gameOver = false; +let paused = false; +let dropTimer = 0; +let lastTime = 0; +let animFrameId = 0; +// ── Board helpers ──────────────────────────────────────────────────── +function createEmptyBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function shuffledBag() { + const a = [0, 1, 2, 3, 4, 5, 6]; + for (let i = a.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [a[i], a[j]] = [a[j], a[i]]; + } + return a; +} +function nextIndex() { + if (bag.length === 0) + bag = shuffledBag(); + return bag.pop(); +} +function spawnPiece() { + const def = TETROMINOES[nextIndex()]; + const shape = def.shape.map(r => [...r]); + return { + shape, + color: def.color, + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + }; +} +function collides(piece, dx, dy, shape) { + const s = shape ?? piece.shape; + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const nx = piece.x + c + dx; + const ny = piece.y + r + dy; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && board[ny][nx]) + return true; + } + } + return false; +} +function lock(piece) { + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + const bx = piece.x + c; + const by = piece.y + r; + if (by < 0) { + gameOver = true; + return; + } + board[by][bx] = piece.color; + } + } +} +function clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every(cell => cell !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check same row index + } + } + return cleared; +} +function rotate(shape) { + const rows = shape.length; + const cols = shape[0].length; + const rotated = Array.from({ length: cols }, () => Array(rows).fill(0)); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + rotated[c][rows - 1 - r] = shape[r][c]; + } + } + return rotated; +} +// Wall-kick: try 0, ±1, ±2 horizontal offsets after rotation +function tryRotate(piece) { + const newShape = rotate(piece.shape); + for (const kick of [0, -1, 1, -2, 2]) { + if (!collides(piece, kick, 0, newShape)) { + piece.shape = newShape; + piece.x += kick; + return; + } + } +} +function ghostY(piece) { + let dy = 0; + while (!collides(piece, 0, dy + 1)) + dy++; + return piece.y + dy; +} +// ── Scoring ────────────────────────────────────────────────────────── +const LINE_SCORES = [0, 100, 300, 500, 800]; +function addScore(cleared) { + score += LINE_SCORES[cleared] * level; + lines += cleared; + const newLevel = Math.floor(lines / LINES_PER_LEVEL) + 1; + if (newLevel > level) + level = newLevel; +} +function dropInterval() { + return Math.max(MIN_INTERVAL, BASE_INTERVAL - (level - 1) * 60); +} +// ── Drawing ────────────────────────────────────────────────────────── +function drawBlock(context, x, y, size, color, alpha = 1) { + context.globalAlpha = alpha; + context.fillStyle = color; + context.fillRect(x * size, y * size, size, size); + // highlight + context.fillStyle = "rgba(255,255,255,0.25)"; + context.fillRect(x * size, y * size, size, 2); + context.fillRect(x * size, y * size, 2, size); + // shadow + context.fillStyle = "rgba(0,0,0,0.25)"; + context.fillRect(x * size + size - 2, y * size, 2, size); + context.fillRect(x * size, y * size + size - 2, size, 2); + context.globalAlpha = 1; + // grid line + context.strokeStyle = "#111"; + context.lineWidth = 0.5; + context.strokeRect(x * size, y * size, size, size); +} +function drawBoard() { + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // draw grid lines (subtle) + ctx.strokeStyle = "#1a1a1a"; + ctx.lineWidth = 0.5; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK, r * BLOCK, BLOCK, BLOCK); + } + } + // locked blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c]) + drawBlock(ctx, c, r, BLOCK, board[r][c]); + } + } +} +function drawGhost(piece) { + const gy = ghostY(piece); + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + drawBlock(ctx, piece.x + c, gy + r, BLOCK, piece.color, 0.2); + } + } +} +function drawPiece(piece) { + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + if (piece.y + r < 0) + continue; + drawBlock(ctx, piece.x + c, piece.y + r, BLOCK, piece.color); + } + } +} +function drawPreview() { + pctx.fillStyle = "#1a1a1a"; + pctx.fillRect(0, 0, preview.width, preview.height); + const s = next.shape; + const offsetX = (4 - s[0].length) / 2; + const offsetY = (4 - s.length) / 2; + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + drawBlock(pctx, offsetX + c, offsetY + r, PREVIEW_BLOCK, next.color); + } + } +} +function updateHUD() { + document.getElementById("score").textContent = String(score); + document.getElementById("lines").textContent = String(lines); + document.getElementById("level").textContent = String(level); +} +function drawGameOver() { + ctx.fillStyle = "rgba(0,0,0,0.65)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px monospace"; + ctx.textAlign = "center"; + ctx.fillText("GAME OVER", canvas.width / 2, canvas.height / 2 - 16); + ctx.font = "16px monospace"; + ctx.fillText("Press R to restart", canvas.width / 2, canvas.height / 2 + 20); +} +function drawPaused() { + ctx.fillStyle = "rgba(0,0,0,0.55)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px monospace"; + ctx.textAlign = "center"; + ctx.fillText("PAUSED", canvas.width / 2, canvas.height / 2); +} +// ── Game logic ─────────────────────────────────────────────────────── +function step() { + if (collides(current, 0, 1)) { + lock(current); + if (gameOver) + return; + const cleared = clearLines(); + if (cleared > 0) + addScore(cleared); + current = next; + next = spawnPiece(); + // check spawn collision → game over + if (collides(current, 0, 0)) { + gameOver = true; + } + } + else { + current.y++; + } +} +function hardDrop() { + while (!collides(current, 0, 1)) { + current.y++; + score += 2; + } + step(); // lock immediately +} +function resetGame() { + board = createEmptyBoard(); + bag = []; + score = 0; + lines = 0; + level = 1; + gameOver = false; + paused = false; + dropTimer = 0; + current = spawnPiece(); + next = spawnPiece(); +} +// ── Input ──────────────────────────────────────────────────────────── +document.addEventListener("keydown", (e) => { + if (gameOver) { + if (e.key === "r" || e.key === "R") + resetGame(); + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + paused = !paused; + return; + } + if (paused) + return; + switch (e.key) { + case "ArrowLeft": + if (!collides(current, -1, 0)) + current.x--; + break; + case "ArrowRight": + if (!collides(current, 1, 0)) + current.x++; + break; + case "ArrowDown": + if (!collides(current, 0, 1)) { + current.y++; + score += 1; + } + break; + case "ArrowUp": + tryRotate(current); + break; + case " ": + hardDrop(); + break; + } + e.preventDefault(); +}); +// ── Main loop ──────────────────────────────────────────────────────── +function gameLoop(timestamp) { + const dt = timestamp - lastTime; + lastTime = timestamp; + if (!gameOver && !paused) { + dropTimer += dt; + if (dropTimer >= dropInterval()) { + dropTimer = 0; + step(); + } + } + // Draw + drawBoard(); + if (!gameOver) { + drawGhost(current); + drawPiece(current); + } + drawPreview(); + updateHUD(); + if (gameOver) + drawGameOver(); + if (paused && !gameOver) + drawPaused(); + animFrameId = requestAnimationFrame(gameLoop); +} +// ── Start ──────────────────────────────────────────────────────────── +lastTime = performance.now(); +animFrameId = requestAnimationFrame(gameLoop); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run2/dist/tetris.js @@ -0,0 +1,415 @@ +"use strict"; +// ─── Types & Constants ─────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const CELL_SIZE = 32; +const PREVIEW_CELLS = 4; +// SRS Tetromino definitions (spawn orientation) +const TETROMINOES = [ + { shape: [[1, 1, 1, 1]], color: "#00f0f0" }, // I - cyan + { shape: [[1, 0, 0], [1, 1, 1]], color: "#0000f0" }, // J - blue + { shape: [[0, 0, 1], [1, 1, 1]], color: "#f0a000" }, // L - orange + { shape: [[1, 1], [1, 1]], color: "#f0f000" }, // O - yellow + { shape: [[0, 1, 1], [1, 1, 0]], color: "#00f000" }, // S - green + { shape: [[0, 1, 0], [1, 1, 1]], color: "#a000f0" }, // T - purple + { shape: [[1, 1, 0], [0, 1, 1]], color: "#f00000" }, // Z - red +]; +// SRS wall-kick data (for J, L, S, T, Z) +const WALL_KICKS = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// SRS wall-kick data for I piece +const I_WALL_KICKS = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// ─── Game State ────────────────────────────────────────────────────── +let grid; +let current; +let currentRotation; +let currentType; +let nextType; +let score; +let lines; +let level; +let gameOver; +let paused; +let dropInterval; +let lastDrop; +let bag; +let animatingRows = []; +let animationStart = 0; +const ANIMATION_DURATION = 300; // ms +// ─── Canvas Setup ──────────────────────────────────────────────────── +const canvas = document.getElementById("game"); +const ctx = canvas.getContext("2d"); +canvas.width = COLS * CELL_SIZE; +canvas.height = ROWS * CELL_SIZE; +const previewCanvas = document.getElementById("preview"); +const previewCtx = previewCanvas.getContext("2d"); +previewCanvas.width = PREVIEW_CELLS * CELL_SIZE; +previewCanvas.height = PREVIEW_CELLS * CELL_SIZE; +const scoreEl = document.getElementById("score"); +const linesEl = document.getElementById("lines"); +const levelEl = document.getElementById("level"); +const messageEl = document.getElementById("message"); +// ─── Helpers ───────────────────────────────────────────────────────── +function createGrid() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +/** 7-bag randomiser */ +function nextFromBag() { + if (bag.length === 0) { + bag = [0, 1, 2, 3, 4, 5, 6]; + // Fisher-Yates shuffle + for (let i = bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [bag[i], bag[j]] = [bag[j], bag[i]]; + } + } + return bag.pop(); +} +function spawnPiece(type) { + const t = TETROMINOES[type]; + return { + shape: t.shape.map((r) => [...r]), + color: t.color, + pos: { x: Math.floor((COLS - t.shape[0].length) / 2), y: 0 }, + }; +} +function rotateCW(shape) { + const rows = shape.length; + const cols = shape[0].length; + const rotated = Array.from({ length: cols }, () => Array(rows).fill(0)); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + rotated[c][rows - 1 - r] = shape[r][c]; + } + } + return rotated; +} +function rotateCCW(shape) { + const rows = shape.length; + const cols = shape[0].length; + const rotated = Array.from({ length: cols }, () => Array(rows).fill(0)); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + rotated[cols - 1 - c][r] = shape[r][c]; + } + } + return rotated; +} +function collides(shape, pos) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = pos.x + c; + const ny = pos.y + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && grid[ny][nx] !== null) + return true; + } + } + return false; +} +function lock() { + for (let r = 0; r < current.shape.length; r++) { + for (let c = 0; c < current.shape[r].length; c++) { + if (!current.shape[r][c]) + continue; + const ny = current.pos.y + r; + const nx = current.pos.x + c; + if (ny < 0) { + gameOver = true; + return; + } + grid[ny][nx] = current.color; + } + } + clearLines(); +} +function clearLines() { + const fullRows = []; + for (let r = 0; r < ROWS; r++) { + if (grid[r].every((cell) => cell !== null)) { + fullRows.push(r); + } + } + if (fullRows.length === 0) + return; + // Start animation + animatingRows = fullRows; + animationStart = performance.now(); +} +function finishClear() { + const fullRows = animatingRows; + animatingRows = []; + // Remove rows top-down (indices stay valid when splicing from top) + const sorted = [...fullRows].sort((a, b) => a - b); + for (const r of sorted) { + grid.splice(r, 1); + grid.unshift(Array(COLS).fill(null)); + } + const count = fullRows.length; + const lineScores = [0, 100, 300, 500, 800]; + score += lineScores[count] * (level + 1); + lines += count; + level = Math.floor(lines / 10); + dropInterval = Math.max(50, 1000 - level * 75); + updateHUD(); +} +function updateHUD() { + scoreEl.textContent = score.toString(); + linesEl.textContent = lines.toString(); + levelEl.textContent = level.toString(); +} +function ghostY() { + let gy = current.pos.y; + while (!collides(current.shape, { x: current.pos.x, y: gy + 1 })) + gy++; + return gy; +} +// ─── Drawing ───────────────────────────────────────────────────────── +function drawCell(context, x, y, color, alpha = 1) { + const s = CELL_SIZE; + context.globalAlpha = alpha; + context.fillStyle = color; + context.fillRect(x * s, y * s, s, s); + // highlight (top-left bevel) + context.fillStyle = "rgba(255,255,255,0.3)"; + context.fillRect(x * s, y * s, s, 2); + context.fillRect(x * s, y * s, 2, s); + // shadow (bottom-right bevel) + context.fillStyle = "rgba(0,0,0,0.3)"; + context.fillRect(x * s, y * s + s - 2, s, 2); + context.fillRect(x * s + s - 2, y * s, 2, s); + // outline + context.strokeStyle = "rgba(0,0,0,0.4)"; + context.strokeRect(x * s, y * s, s, s); + context.globalAlpha = 1; +} +function draw(now) { + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * CELL_SIZE, r * CELL_SIZE, CELL_SIZE, CELL_SIZE); + } + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c]) { + // If this row is animating, flash it + if (animatingRows.includes(r)) { + const elapsed = now - animationStart; + const flash = Math.abs(Math.sin((elapsed / ANIMATION_DURATION) * Math.PI * 3)); + drawCell(ctx, c, r, "#ffffff", flash); + } + else { + drawCell(ctx, c, r, grid[r][c]); + } + } + } + } + if (!gameOver && !paused && animatingRows.length === 0) { + // Ghost piece + const gy = ghostY(); + for (let r = 0; r < current.shape.length; r++) { + for (let c = 0; c < current.shape[r].length; c++) { + if (!current.shape[r][c]) + continue; + drawCell(ctx, current.pos.x + c, gy + r, current.color, 0.2); + } + } + // Current piece + for (let r = 0; r < current.shape.length; r++) { + for (let c = 0; c < current.shape[r].length; c++) { + if (!current.shape[r][c]) + continue; + const py = current.pos.y + r; + if (py >= 0) + drawCell(ctx, current.pos.x + c, py, current.color); + } + } + } + // Preview + drawPreview(); +} +function drawPreview() { + previewCtx.fillStyle = "#111"; + previewCtx.fillRect(0, 0, previewCanvas.width, previewCanvas.height); + const t = TETROMINOES[nextType]; + const offsetX = (PREVIEW_CELLS - t.shape[0].length) / 2; + const offsetY = (PREVIEW_CELLS - t.shape.length) / 2; + for (let r = 0; r < t.shape.length; r++) { + for (let c = 0; c < t.shape[r].length; c++) { + if (t.shape[r][c]) { + drawCell(previewCtx, offsetX + c, offsetY + r, t.color); + } + } + } +} +// ─── Game Logic ────────────────────────────────────────────────────── +function move(dx, dy) { + const newPos = { x: current.pos.x + dx, y: current.pos.y + dy }; + if (!collides(current.shape, newPos)) { + current.pos = newPos; + return true; + } + return false; +} +function tryRotate(direction) { + // O piece doesn't rotate + if (currentType === 3) + return; + const newShape = direction === 1 ? rotateCW(current.shape) : rotateCCW(current.shape); + const newRotation = ((currentRotation + direction) % 4 + 4) % 4; + const kickKey = `${currentRotation}>${newRotation}`; + const kicks = currentType === 0 ? I_WALL_KICKS[kickKey] : WALL_KICKS[kickKey]; + for (const [kx, ky] of kicks) { + const testPos = { x: current.pos.x + kx, y: current.pos.y - ky }; // SRS uses y-up + if (!collides(newShape, testPos)) { + current.shape = newShape; + current.pos = testPos; + currentRotation = newRotation; + return; + } + } +} +function hardDrop() { + while (move(0, 1)) { + score += 2; + } + lock(); + if (!gameOver) + spawnNext(); + updateHUD(); +} +function softDrop() { + if (move(0, 1)) { + score += 1; + updateHUD(); + return true; + } + return false; +} +function spawnNext() { + currentType = nextType; + nextType = nextFromBag(); + current = spawnPiece(currentType); + currentRotation = 0; + if (collides(current.shape, current.pos)) { + gameOver = true; + } +} +function init() { + grid = createGrid(); + bag = []; + score = 0; + lines = 0; + level = 0; + gameOver = false; + paused = false; + dropInterval = 1000; + lastDrop = performance.now(); + animatingRows = []; + nextType = nextFromBag(); + spawnNext(); + updateHUD(); + messageEl.textContent = ""; +} +// ─── Input ─────────────────────────────────────────────────────────── +document.addEventListener("keydown", (e) => { + if (gameOver) { + if (e.key === "Enter") { + init(); + } + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + paused = !paused; + messageEl.textContent = paused ? "PAUSED" : ""; + if (!paused) + lastDrop = performance.now(); + return; + } + if (paused || animatingRows.length > 0) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + move(-1, 0); + break; + case "ArrowRight": + case "d": + move(1, 0); + break; + case "ArrowDown": + case "s": + softDrop(); + lastDrop = performance.now(); + break; + case "ArrowUp": + case "w": + tryRotate(1); + break; + case "z": + case "Z": + tryRotate(-1); + break; + case " ": + hardDrop(); + lastDrop = performance.now(); + break; + } + e.preventDefault(); +}); +// ─── Game Loop ─────────────────────────────────────────────────────── +function loop(now) { + // Handle line-clear animation + if (animatingRows.length > 0) { + if (now - animationStart >= ANIMATION_DURATION) { + finishClear(); + } + draw(now); + requestAnimationFrame(loop); + return; + } + if (!gameOver && !paused) { + if (now - lastDrop > dropInterval) { + if (!move(0, 1)) { + lock(); + if (!gameOver) + spawnNext(); + } + lastDrop = now; + } + } + draw(now); + if (gameOver) { + messageEl.textContent = "GAME OVER — Press Enter"; + } + requestAnimationFrame(loop); +} +init(); +requestAnimationFrame(loop); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":";AAAA,wEAAwE;AAExE,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,SAAS,GAAG,EAAE,CAAC;AACrB,MAAM,aAAa,GAAG,CAAC,CAAC;AAexB,gDAAgD;AAChD,MAAM,WAAW,GAA2C;IAC1D,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAsB,WAAW;IAC5E,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAc,WAAW;IAC5E,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAc,aAAa;IAC9E,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAoB,aAAa;IAC9E,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAc,YAAY;IAC7E,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAc,aAAa;IAC9E,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAc,UAAU;CAC5E,CAAC;AAEF,yCAAyC;AACzC,MAAM,UAAU,GAAuC;IACrD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACjD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CA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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/tetris.js @@ -0,0 +1,577 @@ +"use strict"; +// ── Constants ────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const CELL = 32; // px per cell +const PREVIEW_CELLS = 4; +const LOCK_DELAY_MS = 500; +const BASE_DROP_INTERVAL = 1000; // ms at level 1 +const LINES_PER_LEVEL = 10; +const SPEED_FACTOR = 0.85; // multiplied each level +// ── Colors ───────────────────────────────────────────────────────────── +const PIECE_COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const GHOST_ALPHA = 0.25; +const BG_COLOR = "#111"; +const GRID_COLOR = "#222"; +const BORDER_COLOR = "#555"; +const SHAPES = { + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + O: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +// SRS wall-kick data +const KICKS_JLSTZ = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +const KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// ── Helpers ──────────────────────────────────────────────────────────── +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function getShape(piece) { + return SHAPES[piece.type][piece.rotation]; +} +function collides(board, piece, dx, dy, rotation) { + const shape = SHAPES[piece.type][rotation ?? piece.rotation]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = piece.x + c + dx; + const ny = piece.y + r + dy; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny < 0) + continue; // above top is ok + if (board[ny][nx]) + return true; + } + } + return false; +} +function lockPiece(board, piece) { + const shape = getShape(piece); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = piece.x + c; + const by = piece.y + r; + if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) { + board[by][bx] = piece.type; + } + } + } +} +function clearLines(board) { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every((c) => c !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check same row index + } + } + return cleared; +} +function ghostY(board, piece) { + let dy = 0; + while (!collides(board, piece, 0, dy + 1)) + dy++; + return piece.y + dy; +} +// 7-bag randomiser +function createBag() { + const types = Object.keys(SHAPES); + for (let i = types.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [types[i], types[j]] = [types[j], types[i]]; + } + return types; +} +// ── Game State ───────────────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.board = createBoard(); + this.heldPiece = null; + this.canHold = true; + this.bag = []; + this.nextQueue = []; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.dropInterval = BASE_DROP_INTERVAL; + this.lastDrop = 0; + this.lockTimer = 0; + this.locking = false; + this.animationId = 0; + this.initDOM(); + this.bindKeys(); + this.reset(); + } + // ── DOM setup ────────────────────────────────────────────────────── + initDOM() { + const gameCanvas = document.getElementById("game-canvas"); + const previewCanvas = document.getElementById("preview-canvas"); + const holdCanvas = document.getElementById("hold-canvas"); + gameCanvas.width = COLS * CELL; + gameCanvas.height = ROWS * CELL; + previewCanvas.width = PREVIEW_CELLS * CELL; + previewCanvas.height = PREVIEW_CELLS * CELL * 3 + 16; // 3 previews + holdCanvas.width = PREVIEW_CELLS * CELL; + holdCanvas.height = PREVIEW_CELLS * CELL; + this.ctx = gameCanvas.getContext("2d"); + this.previewCtx = previewCanvas.getContext("2d"); + this.holdCtx = holdCanvas.getContext("2d"); + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.overlayEl = document.getElementById("overlay"); + this.overlayTextEl = document.getElementById("overlay-text"); + } + // ── Reset / new game ────────────────────────────────────────────── + reset() { + this.board = createBoard(); + this.bag = []; + this.nextQueue = []; + this.score = 0; + this.lines = 0; + this.level = 1; + this.dropInterval = BASE_DROP_INTERVAL; + this.gameOver = false; + this.paused = false; + this.heldPiece = null; + this.canHold = true; + this.locking = false; + // Fill next queue (3 previews) + while (this.nextQueue.length < 3) { + if (this.bag.length === 0) + this.bag = createBag(); + this.nextQueue.push(this.bag.pop()); + } + this.spawnPiece(); + this.overlayEl.classList.add("hidden"); + this.lastDrop = performance.now(); + cancelAnimationFrame(this.animationId); + this.animationId = requestAnimationFrame((t) => this.loop(t)); + } + refillQueue() { + while (this.nextQueue.length < 3) { + if (this.bag.length === 0) + this.bag = createBag(); + this.nextQueue.push(this.bag.pop()); + } + } + spawnPiece() { + const type = this.nextQueue.shift(); + this.refillQueue(); + const shape = SHAPES[type][0]; + this.current = { + type, + rotation: 0, + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + }; + // Block-out: if the new piece overlaps existing blocks, game over + if (collides(this.board, this.current, 0, 0)) { + this.endGame(); + } + this.canHold = true; + this.locking = false; + } + endGame() { + this.gameOver = true; + this.overlayTextEl.textContent = "GAME OVER"; + this.overlayEl.classList.remove("hidden"); + } + // ── Input ────────────────────────────────────────────────────────── + bindKeys() { + document.addEventListener("keydown", (e) => { + if (this.gameOver) { + if (e.key === "Enter" || e.key === "r" || e.key === "R") + this.reset(); + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.togglePause(); + return; + } + if (this.paused) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + this.move(-1, 0); + e.preventDefault(); + break; + case "ArrowRight": + case "d": + this.move(1, 0); + e.preventDefault(); + break; + case "ArrowDown": + case "s": + this.softDrop(); + e.preventDefault(); + break; + case "ArrowUp": + case "w": + this.rotate(1); + e.preventDefault(); + break; + case "z": + case "Z": + this.rotate(-1); + e.preventDefault(); + break; + case " ": + this.hardDrop(); + e.preventDefault(); + break; + case "c": + case "C": + case "Shift": + this.hold(); + e.preventDefault(); + break; + } + }); + } + togglePause() { + this.paused = !this.paused; + if (this.paused) { + this.overlayTextEl.textContent = "PAUSED"; + this.overlayEl.classList.remove("hidden"); + } + else { + this.overlayEl.classList.add("hidden"); + this.lastDrop = performance.now(); + } + } + move(dx, dy) { + if (!collides(this.board, this.current, dx, dy)) { + this.current.x += dx; + this.current.y += dy; + if (this.locking) { + this.lockTimer = performance.now(); // reset lock delay on successful move + } + return true; + } + return false; + } + rotate(dir) { + const oldRot = this.current.rotation; + const newRot = (oldRot + dir + 4) % 4; + const kickTable = this.current.type === "I" ? KICKS_I : KICKS_JLSTZ; + const key = dir === 1 ? `${oldRot}>${newRot}` : `${oldRot}>${newRot}`; + const kicks = kickTable[key]; + if (!kicks) + return; + for (const [kx, ky] of kicks) { + if (!collides(this.board, this.current, kx, -ky, newRot)) { + this.current.rotation = newRot; + this.current.x += kx; + this.current.y += -ky; + if (this.locking) { + this.lockTimer = performance.now(); + } + return; + } + } + } + softDrop() { + if (this.move(0, 1)) { + this.score += 1; + this.lastDrop = performance.now(); + } + } + hardDrop() { + let dist = 0; + while (!collides(this.board, this.current, 0, 1)) { + this.current.y++; + dist++; + } + this.score += dist * 2; + this.lock(); + } + hold() { + if (!this.canHold) + return; + this.canHold = false; + const type = this.current.type; + if (this.heldPiece) { + const swap = this.heldPiece; + this.heldPiece = type; + const shape = SHAPES[swap][0]; + this.current = { + type: swap, + rotation: 0, + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + }; + } + else { + this.heldPiece = type; + this.spawnPiece(); + this.canHold = false; // spawnPiece sets true, override + } + this.locking = false; + } + // ── Lock & line clear ───────────────────────────────────────────── + lock() { + // Lock-out: if any cell of the piece is above the visible board, game over + const shape = getShape(this.current); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c] && this.current.y + r < 0) { + lockPiece(this.board, this.current); + this.endGame(); + return; + } + } + } + lockPiece(this.board, this.current); + const cleared = clearLines(this.board); + if (cleared > 0) { + this.lines += cleared; + const points = [0, 100, 300, 500, 800]; + this.score += (points[cleared] ?? 800) * this.level; + const newLevel = Math.floor(this.lines / LINES_PER_LEVEL) + 1; + if (newLevel > this.level) { + this.level = newLevel; + this.dropInterval = BASE_DROP_INTERVAL * Math.pow(SPEED_FACTOR, this.level - 1); + } + } + this.locking = false; + this.spawnPiece(); + this.lastDrop = performance.now(); + } + // ── Game loop ───────────────────────────────────────────────────── + loop(time) { + if (this.gameOver) { + this.draw(); + return; + } + if (!this.paused) { + // Gravity + if (time - this.lastDrop >= this.dropInterval) { + if (!collides(this.board, this.current, 0, 1)) { + this.current.y++; + this.lastDrop = time; + this.locking = false; + } + else { + // Start or continue lock delay + if (!this.locking) { + this.locking = true; + this.lockTimer = time; + } + } + } + // Lock delay + if (this.locking && time - this.lockTimer >= LOCK_DELAY_MS) { + this.lock(); + } + this.draw(); + } + this.animationId = requestAnimationFrame((t) => this.loop(t)); + } + // ── Drawing ─────────────────────────────────────────────────────── + draw() { + const ctx = this.ctx; + const W = COLS * CELL; + const H = ROWS * CELL; + // Background + ctx.fillStyle = BG_COLOR; + ctx.fillRect(0, 0, W, H); + // Grid + ctx.strokeStyle = GRID_COLOR; + ctx.lineWidth = 1; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * CELL, r * CELL, CELL, CELL); + } + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.board[r][c]) { + this.drawCell(ctx, c, r, PIECE_COLORS[this.board[r][c]]); + } + } + } + // Ghost piece + if (!this.gameOver) { + const gy = ghostY(this.board, this.current); + const shape = getShape(this.current); + const color = PIECE_COLORS[this.current.type]; + ctx.globalAlpha = GHOST_ALPHA; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + this.drawCell(ctx, this.current.x + c, gy + r, color); + } + } + } + ctx.globalAlpha = 1; + // Current piece + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const py = this.current.y + r; + if (py >= 0) { + this.drawCell(ctx, this.current.x + c, py, color); + } + } + } + } + } + // Border + ctx.strokeStyle = BORDER_COLOR; + ctx.lineWidth = 2; + ctx.strokeRect(0, 0, W, H); + // Sidebar + this.drawPreview(); + this.drawHold(); + this.updateHUD(); + } + drawCell(ctx, x, y, color) { + const pad = 1; + ctx.fillStyle = color; + ctx.fillRect(x * CELL + pad, y * CELL + pad, CELL - pad * 2, CELL - pad * 2); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.2)"; + ctx.fillRect(x * CELL + pad, y * CELL + pad, CELL - pad * 2, 4); + ctx.fillRect(x * CELL + pad, y * CELL + pad, 4, CELL - pad * 2); + // Shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x * CELL + pad, (y + 1) * CELL - pad - 4, CELL - pad * 2, 4); + ctx.fillRect((x + 1) * CELL - pad - 4, y * CELL + pad, 4, CELL - pad * 2); + } + drawMiniPiece(ctx, type, offsetX, offsetY, cellSize) { + const shape = SHAPES[type][0]; + const color = PIECE_COLORS[type]; + // Centre the piece + const pw = shape[0].length; + const ph = shape.length; + const ox = offsetX + (4 * cellSize - pw * cellSize) / 2; + const oy = offsetY + (4 * cellSize - ph * cellSize) / 2; + for (let r = 0; r < ph; r++) { + for (let c = 0; c < pw; c++) { + if (shape[r][c]) { + const pad = 1; + ctx.fillStyle = color; + ctx.fillRect(ox + c * cellSize + pad, oy + r * cellSize + pad, cellSize - pad * 2, cellSize - pad * 2); + ctx.fillStyle = "rgba(255,255,255,0.18)"; + ctx.fillRect(ox + c * cellSize + pad, oy + r * cellSize + pad, cellSize - pad * 2, 2); + } + } + } + } + drawPreview() { + const ctx = this.previewCtx; + const w = ctx.canvas.width; + const h = ctx.canvas.height; + ctx.fillStyle = BG_COLOR; + ctx.fillRect(0, 0, w, h); + const miniCell = 24; + for (let i = 0; i < this.nextQueue.length && i < 3; i++) { + this.drawMiniPiece(ctx, this.nextQueue[i], 8, i * (miniCell * 4 + 8), miniCell); + } + ctx.strokeStyle = BORDER_COLOR; + ctx.lineWidth = 2; + ctx.strokeRect(0, 0, w, h); + } + drawHold() { + const ctx = this.holdCtx; + const w = ctx.canvas.width; + const h = ctx.canvas.height; + ctx.fillStyle = BG_COLOR; + ctx.fillRect(0, 0, w, h); + if (this.heldPiece) { + const miniCell = 24; + ctx.globalAlpha = this.canHold ? 1 : 0.4; + this.drawMiniPiece(ctx, this.heldPiece, 8, 4, miniCell); + ctx.globalAlpha = 1; + } + ctx.strokeStyle = BORDER_COLOR; + ctx.lineWidth = 2; + ctx.strokeRect(0, 0, w, h); + } + updateHUD() { + this.scoreEl.textContent = this.score.toLocaleString(); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + } +} +// ── Boot ─────────────────────────────────────────────────────────────── +document.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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C,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;CACF,CAAC;AAEF,qBAAqB;AACrB,MAAM,WAAW,GAAuC;IACtD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js @@ -0,0 +1,596 @@ +"use strict"; +// ─── Constants ─────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 30; +const PREVIEW_BLOCK = 20; +const COLORS = [ + "#000000", // 0 = empty + "#00f0f0", // 1 = I (cyan) + "#0000f0", // 2 = J (blue) + "#f0a000", // 3 = L (orange) + "#f0f000", // 4 = O (yellow) + "#00f000", // 5 = S (green) + "#a000f0", // 6 = T (purple) + "#f00000", // 7 = Z (red) +]; +const BORDER_SHADES = [ + "#000000", + "#009999", + "#000099", + "#996600", + "#999900", + "#009900", + "#660099", + "#990000", +]; +// Standard Tetris scoring (NES-based) +const LINE_POINTS = [0, 100, 300, 500, 800]; +// Frames-per-drop by level (lower = faster). Capped at level 20. +function getDropInterval(level) { + const speeds = [ + 800, 720, 630, 550, 470, 380, 300, 220, 150, 100, + 83, 83, 83, 67, 67, 67, 50, 50, 50, 33, + 33, + ]; + return speeds[Math.min(level, 20)]; +} +const TETROMINOES = [ + { + shape: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + color: 1, + }, + { + shape: [ + [2, 0, 0], + [2, 2, 2], + [0, 0, 0], + ], + color: 2, + }, + { + shape: [ + [0, 0, 3], + [3, 3, 3], + [0, 0, 0], + ], + color: 3, + }, + { + shape: [ + [4, 4], + [4, 4], + ], + color: 4, + }, + { + shape: [ + [0, 5, 5], + [5, 5, 0], + [0, 0, 0], + ], + color: 5, + }, + { + shape: [ + [0, 6, 0], + [6, 6, 6], + [0, 0, 0], + ], + color: 6, + }, + { + shape: [ + [7, 7, 0], + [0, 7, 7], + [0, 0, 0], + ], + color: 7, + }, +]; +// SRS wall-kick data (for pieces other than I and O) +const WALL_KICKS_JLSTZ = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +const WALL_KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// ─── Piece ─────────────────────────────────────────────────────────────────── +class Piece { + constructor(typeIndex) { + const def = TETROMINOES[typeIndex]; + this.shape = def.shape.map(row => [...row]); + this.color = def.color; + this.typeIndex = typeIndex; + this.rotation = 0; + this.x = Math.floor((COLS - this.shape[0].length) / 2); + this.y = 0; + } + rotatedShape(dir) { + const n = this.shape.length; + const rotated = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + if (dir === 1) { + rotated[c][n - 1 - r] = this.shape[r][c]; + } + else { + rotated[n - 1 - c][r] = this.shape[r][c]; + } + } + } + return rotated; + } +} +// ─── Board ─────────────────────────────────────────────────────────────────── +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(0)); +} +// ─── Bag Randomiser (7-bag) ────────────────────────────────────────────────── +class Bag { + constructor() { + this.queue = []; + } + next() { + if (this.queue.length === 0) { + this.queue = [0, 1, 2, 3, 4, 5, 6]; + // Fisher-Yates shuffle + for (let i = this.queue.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.queue[i], this.queue[j]] = [this.queue[j], this.queue[i]]; + } + } + return this.queue.pop(); + } + peek() { + if (this.queue.length === 0) { + this.queue = [0, 1, 2, 3, 4, 5, 6]; + for (let i = this.queue.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.queue[i], this.queue[j]] = [this.queue[j], this.queue[i]]; + } + } + return this.queue[this.queue.length - 1]; + } +} +// ─── Game ──────────────────────────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.holdTypeIndex = null; + this.holdUsed = false; + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + this.lastDrop = 0; + this.lockDelay = 500; // ms before piece locks after landing + this.lockTimer = 0; + this.isLanding = false; + this.animationId = 0; + // ── Game Loop ─────────────────────────────────────────────────────────── + this.loop = (timestamp) => { + if (this.gameOver) { + this.draw(); + this.messageEl.textContent = "GAME OVER – Press R to restart"; + return; + } + if (this.paused) { + this.animationId = requestAnimationFrame(this.loop); + return; + } + const delta = timestamp - this.lastDrop; + // Check if the piece is sitting on something + const onGround = !this.isValid(this.currentPiece.shape, this.currentPiece.x, this.currentPiece.y + 1); + if (onGround) { + if (!this.isLanding) { + this.isLanding = true; + this.lockTimer = timestamp; + } + // Lock after delay + if (timestamp - this.lockTimer >= this.lockDelay) { + this.lockPiece(); + this.lastDrop = timestamp; + } + } + else { + this.isLanding = false; + if (delta >= this.dropInterval) { + this.move(0, 1); + this.lastDrop = timestamp; + } + } + this.draw(); + this.animationId = requestAnimationFrame(this.loop); + }; + this.canvas = document.getElementById("game-canvas"); + this.ctx = this.canvas.getContext("2d"); + this.canvas.width = COLS * BLOCK_SIZE; + this.canvas.height = ROWS * BLOCK_SIZE; + this.previewCanvas = document.getElementById("preview-canvas"); + this.previewCtx = this.previewCanvas.getContext("2d"); + this.previewCanvas.width = 4 * PREVIEW_BLOCK; + this.previewCanvas.height = 4 * PREVIEW_BLOCK; + this.holdCanvas = document.getElementById("hold-canvas"); + this.holdCtx = this.holdCanvas.getContext("2d"); + this.holdCanvas.width = 4 * PREVIEW_BLOCK; + this.holdCanvas.height = 4 * PREVIEW_BLOCK; + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.messageEl = document.getElementById("message"); + this.board = createBoard(); + this.bag = new Bag(); + this.bindKeys(); + this.init(); + } + // ── Initialisation ────────────────────────────────────────────────────── + init() { + this.board = createBoard(); + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + this.holdTypeIndex = null; + this.holdUsed = false; + this.bag = new Bag(); + this.nextTypeIndex = this.bag.next(); + this.spawnPiece(); + this.dropInterval = getDropInterval(this.level); + this.lastDrop = performance.now(); + this.messageEl.textContent = ""; + this.updateHUD(); + cancelAnimationFrame(this.animationId); + this.animationId = requestAnimationFrame(this.loop); + } + // ── Spawn / Hold ──────────────────────────────────────────────────────── + spawnPiece() { + this.currentPiece = new Piece(this.nextTypeIndex); + this.nextTypeIndex = this.bag.next(); + this.holdUsed = false; + this.isLanding = false; + if (!this.isValid(this.currentPiece.shape, this.currentPiece.x, this.currentPiece.y)) { + this.gameOver = true; + } + } + holdPiece() { + if (this.holdUsed) + return; + this.holdUsed = true; + const curType = this.currentPiece.typeIndex; + if (this.holdTypeIndex === null) { + this.holdTypeIndex = curType; + this.spawnPiece(); + } + else { + const tmp = this.holdTypeIndex; + this.holdTypeIndex = curType; + this.currentPiece = new Piece(tmp); + this.isLanding = false; + } + } + // ── Collision ─────────────────────────────────────────────────────────── + isValid(shape, px, py) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c] === 0) + continue; + const bx = px + c; + const by = py + r; + if (bx < 0 || bx >= COLS || by >= ROWS) + return false; + if (by < 0) + continue; // above the board is OK + if (this.board[by][bx] !== 0) + return false; + } + } + return true; + } + // ── Movement ──────────────────────────────────────────────────────────── + move(dx, dy) { + const nx = this.currentPiece.x + dx; + const ny = this.currentPiece.y + dy; + if (this.isValid(this.currentPiece.shape, nx, ny)) { + this.currentPiece.x = nx; + this.currentPiece.y = ny; + return true; + } + return false; + } + rotate(dir) { + const piece = this.currentPiece; + const newShape = piece.rotatedShape(dir); + const oldRot = piece.rotation; + const newRot = (oldRot + dir + 4) % 4; + const key = `${oldRot}>${newRot}`; + // Choose kick table + const isI = piece.typeIndex === 0; + const isO = piece.typeIndex === 3; + if (isO) + return; // O doesn't rotate + const kicks = isI ? WALL_KICKS_I[key] : WALL_KICKS_JLSTZ[key]; + if (!kicks) + return; + for (const [kx, ky] of kicks) { + if (this.isValid(newShape, piece.x + kx, piece.y - ky)) { + piece.shape = newShape; + piece.x += kx; + piece.y -= ky; + piece.rotation = newRot; + return; + } + } + } + hardDrop() { + let dropDistance = 0; + while (this.move(0, 1)) { + dropDistance++; + } + this.score += dropDistance * 2; + this.lockPiece(); + } + // ── Ghost Piece ───────────────────────────────────────────────────────── + ghostY() { + let gy = this.currentPiece.y; + while (this.isValid(this.currentPiece.shape, this.currentPiece.x, gy + 1)) { + gy++; + } + return gy; + } + // ── Lock & Clear ──────────────────────────────────────────────────────── + lockPiece() { + const piece = this.currentPiece; + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (piece.shape[r][c] === 0) + continue; + const bx = piece.x + c; + const by = piece.y + r; + if (by < 0) { + this.gameOver = true; + return; + } + this.board[by][bx] = piece.shape[r][c]; + } + } + this.clearLines(); + this.spawnPiece(); + } + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every(cell => cell !== 0)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(0)); + cleared++; + r++; // re-check same row index + } + } + if (cleared > 0) { + this.lines += cleared; + this.score += LINE_POINTS[cleared] * (this.level + 1); + const newLevel = Math.floor(this.lines / 10); + if (newLevel !== this.level) { + this.level = newLevel; + this.dropInterval = getDropInterval(this.level); + } + this.updateHUD(); + } + } + // ── HUD ───────────────────────────────────────────────────────────────── + updateHUD() { + this.scoreEl.textContent = this.score.toString(); + this.linesEl.textContent = this.lines.toString(); + this.levelEl.textContent = this.level.toString(); + } + // ── Drawing ───────────────────────────────────────────────────────────── + drawBlock(ctx, x, y, colorIdx, size, alpha = 1) { + const color = COLORS[colorIdx]; + const border = BORDER_SHADES[colorIdx]; + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size, y * size, size, size); + // bevel highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x * size, y * size, size, 2); + ctx.fillRect(x * size, y * size, 2, size); + // bevel shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x * size + size - 2, y * size, 2, size); + ctx.fillRect(x * size, y * size + size - 2, size, 2); + // border + ctx.strokeStyle = border; + ctx.lineWidth = 1; + ctx.strokeRect(x * size + 0.5, y * size + 0.5, size - 1, size - 1); + ctx.globalAlpha = 1; + } + drawBoard() { + const ctx = this.ctx; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(COLS * BLOCK_SIZE, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.stroke(); + } + // Locked blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.board[r][c] !== 0) { + this.drawBlock(ctx, c, r, this.board[r][c], BLOCK_SIZE); + } + } + } + } + drawGhost() { + const gy = this.ghostY(); + const piece = this.currentPiece; + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (piece.shape[r][c] === 0) + continue; + this.drawBlock(this.ctx, piece.x + c, gy + r, piece.color, BLOCK_SIZE, 0.25); + } + } + } + drawCurrentPiece() { + const piece = this.currentPiece; + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (piece.shape[r][c] === 0) + continue; + this.drawBlock(this.ctx, piece.x + c, piece.y + r, piece.color, BLOCK_SIZE); + } + } + } + drawPreview() { + const ctx = this.previewCtx; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, this.previewCanvas.width, this.previewCanvas.height); + const def = TETROMINOES[this.nextTypeIndex]; + const shape = def.shape; + const n = shape.length; + const offsetX = (4 - n) / 2; + const offsetY = (4 - n) / 2; + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + if (shape[r][c] !== 0) { + this.drawBlock(ctx, c + offsetX, r + offsetY, shape[r][c], PREVIEW_BLOCK); + } + } + } + } + drawHold() { + const ctx = this.holdCtx; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, this.holdCanvas.width, this.holdCanvas.height); + if (this.holdTypeIndex === null) + return; + const def = TETROMINOES[this.holdTypeIndex]; + const shape = def.shape; + const n = shape.length; + const offsetX = (4 - n) / 2; + const offsetY = (4 - n) / 2; + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + if (shape[r][c] !== 0) { + this.drawBlock(ctx, c + offsetX, r + offsetY, shape[r][c], PREVIEW_BLOCK, this.holdUsed ? 0.4 : 1); + } + } + } + } + draw() { + this.drawBoard(); + if (!this.gameOver) { + this.drawGhost(); + this.drawCurrentPiece(); + } + this.drawPreview(); + this.drawHold(); + this.updateHUD(); + } + // ── Input ─────────────────────────────────────────────────────────────── + bindKeys() { + document.addEventListener("keydown", (e) => { + if (this.gameOver) { + if (e.key === "r" || e.key === "R") { + this.init(); + } + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.paused = !this.paused; + this.messageEl.textContent = this.paused ? "PAUSED" : ""; + if (!this.paused) { + this.lastDrop = performance.now(); + } + return; + } + if (this.paused) + return; + switch (e.key) { + case "ArrowLeft": + e.preventDefault(); + if (this.move(-1, 0) && this.isLanding) { + this.lockTimer = performance.now(); // reset lock timer on move + } + break; + case "ArrowRight": + e.preventDefault(); + if (this.move(1, 0) && this.isLanding) { + this.lockTimer = performance.now(); + } + break; + case "ArrowDown": + e.preventDefault(); + if (this.move(0, 1)) { + this.score += 1; // soft drop bonus + this.lastDrop = performance.now(); + } + break; + case "ArrowUp": + case "x": + case "X": + e.preventDefault(); + this.rotate(1); + if (this.isLanding) + this.lockTimer = performance.now(); + break; + case "z": + case "Z": + e.preventDefault(); + this.rotate(-1); + if (this.isLanding) + this.lockTimer = performance.now(); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + case "c": + case "C": + case "Shift": + e.preventDefault(); + this.holdPiece(); + break; + } + }); + } +} +// ─── Bootstrap ─────────────────────────────────────────────────────────────── +document.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAEhF,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,UAAU,GAAG,EAAE,CAAC;AACtB,MAAM,aAAa,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,GAAsB;IAChC,SAAS,EAAE,YAAY;IACvB,SAAS,EAAE,gBAAgB;IAC3B,SAAS,EAAE,gBAAgB;IAC3B,SAAS,EAAE,kBAAkB;IAC7B,SAAS,EAAE,kBAAkB;IAC7B,SAAS,EAAE,iBAAiB;IAC5B,SAAS,EAAE,kBAAkB;IAC7B,SAAS,EAAE,eAAe;CAC3B,CAAC;AAEF,MAAM,aAAa,GAAsB;IACvC,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;CACV,CAAC;AAEF,sCAAsC;AACtC,MAAM,WAAW,GAAsB,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAE/D,iEAAiE;AACjE,SAAS,eAAe,CAAC,KAAa;IACpC,MAAM,MAAM,GAAG;QACb,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;QAC/C,EAAE,EAAG,EAAE,EAAG,EAAE,EAAG,EAAE,EAAG,EAAE,EAAG,EAAE,EAAG,EAAE,EAAG,EAAE,EAAG,EAAE,EAAG,EAAE;QAC/C,EAAE;KACJ,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;AACrC,CAAC;AAWD,MAAM,WAAW,GAA4B;IAC3C;QACE,KAAK,EAAE;YACL,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACZ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACb;QACD,KAAK,EAAE,CAAC;KACT;IACD;QACE,KAAK,EAAE;YACL,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD,KAAK,EAAE,CAAC;KACT;IACD;QACE,KAAK,EAAE;YACL,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD,KAAK,EAAE,CAAC;KACT;IACD;QACE,KAAK,EAAE;YACL,CAAC,CAAC,EAAE,CAAC,CAAC;YACN,CAAC,CAAC,EAAE,CAAC,CAAC;SACP;QACD,KAAK,EAAE,CAAC;KACT;IACD;QACE,KAAK,EAAE;YACL,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD,KAAK,EAAE,CAAC;KACT;IACD;QACE,KAAK,EAAE;YACL,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD,KAAK,EAAE,CAAC;KACT;IACD;QACE,KAAK,EAAE;YACL,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD,KAAK,EAAE,CAAC;KACT;CACF,CAAC;AAEF,qDAAqD;AACrD,MAAM,gBAAgB,GAAuC;IAC3D,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACpD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACpD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACpD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAE,CAAC,EAAE,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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/game.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/game.d.ts @@ -0,0 +1,81 @@ +type Cell = string | null; +type Board = Cell[][]; +type Shape = number[][]; +interface Position { + x: number; + y: number; +} +interface Piece { + shape: Shape; + color: string; + pos: Position; + type: TetrominoType; +} +type TetrominoType = "I" | "O" | "T" | "S" | "Z" | "J" | "L"; +declare const COLS = 10; +declare const ROWS = 20; +declare const BLOCK_SIZE = 32; +declare const PREVIEW_BLOCK = 24; +declare const COLORS: Record<TetrominoType, string>; +declare const SHAPES: Record<TetrominoType, Shape[]>; +declare const WALL_KICKS: Record<string, [number, number][]>; +declare const WALL_KICKS_I: Record<string, [number, number][]>; +declare const LINE_SCORES: number[]; +declare class TetrisGame { + private board; + private current; + private rotation; + private nextType; + private score; + private lines; + private level; + private gameOver; + private paused; + private started; + private canvas; + private ctx; + private previewCanvas; + private previewCtx; + private scoreEl; + private linesEl; + private levelEl; + private messageEl; + private dropInterval; + private lastDrop; + private lockDelay; + private lockTimer; + private locking; + private animationId; + private bag; + private softDropping; + private dasLeft; + private dasRight; + private dasTimer; + private dasDelay; + private dasInterval; + private dasActive; + private lastTimestamp; + constructor(); + private createBoard; + private fillBag; + private pullFromBag; + private spawnPiece; + private isValid; + private lockPiece; + private move; + private rotate; + private hardDrop; + private getGhostY; + private clearLines; + private drawBlock; + private drawBoard; + private drawPreview; + private updateHUD; + private showMessage; + private hideMessage; + private bindKeys; + private restart; + private pause; + private unpause; + private loop; +} diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/game.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/game.js @@ -0,0 +1,579 @@ +"use strict"; +// ============================================================ +// Types & Constants +// ============================================================ +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 32; +const PREVIEW_BLOCK = 24; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +// Each tetromino defined as a list of rotation states (row, col offsets filled) +const SHAPES = { + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + O: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +// SRS wall kick data (non-I pieces) +const WALL_KICKS = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// SRS wall kick data for I piece +const WALL_KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +const LINE_SCORES = [0, 100, 300, 500, 800]; // 0,1,2,3,4 lines +// ============================================================ +// Game class +// ============================================================ +class TetrisGame { + constructor() { + this.current = null; + this.rotation = 0; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.started = false; + this.dropInterval = 1000; + this.lastDrop = 0; + this.lockDelay = 500; + this.lockTimer = 0; + this.locking = false; + this.animationId = 0; + this.bag = []; + this.softDropping = false; + this.dasLeft = false; + this.dasRight = false; + this.dasTimer = 0; + this.dasDelay = 170; // ms before auto-repeat starts + this.dasInterval = 50; // ms between auto-repeat moves + this.dasActive = false; + this.lastTimestamp = 0; + this.loop = (timestamp) => { + if (this.gameOver || this.paused) + return; + const dt = timestamp - this.lastTimestamp; + this.lastTimestamp = timestamp; + // DAS (Delayed Auto Shift) + if (this.dasLeft || this.dasRight) { + this.dasTimer += dt; + if (!this.dasActive && this.dasTimer >= this.dasDelay) { + this.dasActive = true; + this.dasTimer = 0; + } + if (this.dasActive) { + // accumulate time and move multiple cells if needed + while (this.dasTimer >= this.dasInterval) { + this.dasTimer -= this.dasInterval; + this.move(this.dasLeft ? -1 : 1, 0); + } + } + } + // Gravity + const interval = this.softDropping ? Math.min(50, this.dropInterval) : this.dropInterval; + if (timestamp - this.lastDrop >= interval) { + if (this.current) { + if (!this.move(0, 1)) { + // Piece can't move down — start or continue lock timer + if (!this.locking) { + this.locking = true; + this.lockTimer = 0; + } + } + else { + if (this.softDropping) + this.score += 1; + this.locking = false; + this.lockTimer = 0; + } + } + this.lastDrop = timestamp; + } + // Lock delay + if (this.locking && this.current) { + this.lockTimer += dt; + if (this.lockTimer >= this.lockDelay) { + this.lockPiece(); + if (!this.gameOver) + this.spawnPiece(); + this.updateHUD(); + } + } + this.drawBoard(); + this.animationId = requestAnimationFrame(this.loop); + }; + this.canvas = document.getElementById("game-canvas"); + this.ctx = this.canvas.getContext("2d"); + this.previewCanvas = document.getElementById("preview-canvas"); + this.previewCtx = this.previewCanvas.getContext("2d"); + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.messageEl = document.getElementById("message"); + this.canvas.width = COLS * BLOCK_SIZE; + this.canvas.height = ROWS * BLOCK_SIZE; + this.previewCanvas.width = 4 * PREVIEW_BLOCK; + this.previewCanvas.height = 4 * PREVIEW_BLOCK; + this.board = this.createBoard(); + this.nextType = this.pullFromBag(); + this.bindKeys(); + this.showMessage("Press ENTER to start"); + this.drawBoard(); + } + // --- Board helpers --- + createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); + } + // --- Bag randomizer (7-bag) --- + fillBag() { + const types = ["I", "O", "T", "S", "Z", "J", "L"]; + // Fisher-Yates shuffle + for (let i = types.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [types[i], types[j]] = [types[j], types[i]]; + } + this.bag = types; + } + pullFromBag() { + if (this.bag.length === 0) + this.fillBag(); + return this.bag.pop(); + } + // --- Piece helpers --- + spawnPiece() { + const type = this.nextType; + this.nextType = this.pullFromBag(); + this.rotation = 0; + const shape = SHAPES[type][0]; + const pos = { + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + }; + this.current = { shape, color: COLORS[type], pos, type }; + // If spawn position is blocked, game over + if (!this.isValid(this.current.shape, pos)) { + this.current.pos = pos; + this.lockPiece(); // place partially visible + this.gameOver = true; + this.showMessage("GAME OVER — press ENTER to restart"); + cancelAnimationFrame(this.animationId); + } + this.locking = false; + this.lockTimer = 0; + this.drawPreview(); + } + isValid(shape, pos) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const x = pos.x + c; + const y = pos.y + r; + if (x < 0 || x >= COLS || y >= ROWS) + return false; + if (y < 0) + continue; // allow above top + if (this.board[y][x]) + return false; + } + } + return true; + } + lockPiece() { + if (!this.current) + return; + const { shape, color, pos } = this.current; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const y = pos.y + r; + const x = pos.x + c; + if (y >= 0 && y < ROWS && x >= 0 && x < COLS) { + this.board[y][x] = color; + } + } + } + this.clearLines(); + this.current = null; + this.locking = false; + } + // --- Movement --- + move(dx, dy) { + if (!this.current) + return false; + const newPos = { x: this.current.pos.x + dx, y: this.current.pos.y + dy }; + if (this.isValid(this.current.shape, newPos)) { + this.current.pos = newPos; + // Reset lock delay on successful move if we're in lock phase + if (this.locking) { + this.lockTimer = 0; + } + return true; + } + return false; + } + rotate(dir) { + if (!this.current) + return; + const type = this.current.type; + if (type === "O") + return; // O doesn't rotate + const oldRot = this.rotation; + const newRot = (this.rotation + dir + 4) % 4; + const newShape = SHAPES[type][newRot]; + const kickTable = type === "I" ? WALL_KICKS_I : WALL_KICKS; + const key = `${oldRot}>${newRot}`; + const kicks = kickTable[key] || [[0, 0]]; + for (const [kx, ky] of kicks) { + const newPos = { + x: this.current.pos.x + kx, + y: this.current.pos.y - ky, // SRS kick y is inverted relative to our coord system + }; + if (this.isValid(newShape, newPos)) { + this.current.shape = newShape; + this.current.pos = newPos; + this.rotation = newRot; + if (this.locking) { + this.lockTimer = 0; + } + return; + } + } + } + hardDrop() { + if (!this.current) + return; + let dropped = 0; + while (this.move(0, 1)) { + dropped++; + } + this.score += dropped * 2; + this.lockPiece(); + if (!this.gameOver) + this.spawnPiece(); + this.updateHUD(); + } + getGhostY() { + if (!this.current) + return 0; + let ghostY = this.current.pos.y; + while (this.isValid(this.current.shape, { x: this.current.pos.x, y: ghostY + 1 })) { + ghostY++; + } + return ghostY; + } + // --- Line clearing --- + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every((cell) => cell !== null)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check same row index + } + } + if (cleared > 0) { + this.lines += cleared; + this.score += LINE_SCORES[cleared] * this.level; + this.level = Math.floor(this.lines / 10) + 1; + this.dropInterval = Math.max(50, 1000 - (this.level - 1) * 80); + this.updateHUD(); + } + } + // --- Rendering --- + drawBlock(ctx, x, y, color, size, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size + 1, y * size + 1, size - 2, size - 2); + // Highlight (top-left bevel) + ctx.fillStyle = "rgba(255,255,255,0.3)"; + ctx.fillRect(x * size + 1, y * size + 1, size - 2, 3); + ctx.fillRect(x * size + 1, y * size + 1, 3, size - 2); + // Shadow (bottom-right bevel) + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(x * size + 1, y * size + size - 4, size - 2, 3); + ctx.fillRect(x * size + size - 4, y * size + 1, 3, size - 2); + ctx.globalAlpha = 1; + } + drawBoard() { + const { ctx } = this; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(COLS * BLOCK_SIZE, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.stroke(); + } + // Placed blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.board[r][c]) { + this.drawBlock(ctx, c, r, this.board[r][c], BLOCK_SIZE); + } + } + } + // Ghost piece + if (this.current && !this.gameOver) { + const ghostY = this.getGhostY(); + const { shape, color, pos } = this.current; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const y = ghostY + r; + const x = pos.x + c; + if (y >= 0) { + this.drawBlock(ctx, x, y, color, BLOCK_SIZE, 0.2); + } + } + } + } + // Current piece + if (this.current && !this.gameOver) { + const { shape, color, pos } = this.current; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const y = pos.y + r; + const x = pos.x + c; + if (y >= 0) { + this.drawBlock(ctx, x, y, color, BLOCK_SIZE); + } + } + } + } + } + drawPreview() { + const { previewCtx: ctx } = this; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, this.previewCanvas.width, this.previewCanvas.height); + const shape = SHAPES[this.nextType][0]; + const color = COLORS[this.nextType]; + const offsetX = (4 - shape[0].length) / 2; + const offsetY = (4 - shape.length) / 2; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + this.drawBlock(ctx, c + offsetX, r + offsetY, color, PREVIEW_BLOCK); + } + } + } + } + updateHUD() { + this.scoreEl.textContent = this.score.toString(); + this.linesEl.textContent = this.lines.toString(); + this.levelEl.textContent = this.level.toString(); + } + showMessage(text) { + this.messageEl.textContent = text; + this.messageEl.style.display = "block"; + } + hideMessage() { + this.messageEl.style.display = "none"; + } + // --- Input --- + bindKeys() { + document.addEventListener("keydown", (e) => { + if (e.key === "Enter") { + if (this.gameOver || !this.started) { + this.restart(); + return; + } + if (this.paused) { + this.unpause(); + } + else { + this.pause(); + } + return; + } + if (e.key === "Escape") { + if (!this.gameOver && this.started) { + this.paused ? this.unpause() : this.pause(); + } + return; + } + if (this.gameOver || this.paused || !this.started) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + e.preventDefault(); + if (!this.dasLeft) { + this.move(-1, 0); + this.dasLeft = true; + this.dasRight = false; + this.dasTimer = 0; + this.dasActive = false; + } + break; + case "ArrowRight": + case "d": + e.preventDefault(); + if (!this.dasRight) { + this.move(1, 0); + this.dasRight = true; + this.dasLeft = false; + this.dasTimer = 0; + this.dasActive = false; + } + break; + case "ArrowDown": + case "s": + e.preventDefault(); + this.softDropping = true; + break; + case "ArrowUp": + case "w": + e.preventDefault(); + this.rotate(1); + break; + case "z": + e.preventDefault(); + this.rotate(-1); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + } + }); + document.addEventListener("keyup", (e) => { + switch (e.key) { + case "ArrowLeft": + case "a": + this.dasLeft = false; + this.dasActive = false; + break; + case "ArrowRight": + case "d": + this.dasRight = false; + this.dasActive = false; + break; + case "ArrowDown": + case "s": + this.softDropping = false; + break; + } + }); + } + // --- Game loop --- + restart() { + this.board = this.createBoard(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.dropInterval = 1000; + this.gameOver = false; + this.paused = false; + this.started = true; + this.current = null; + this.bag = []; + this.nextType = this.pullFromBag(); + this.softDropping = false; + this.dasLeft = false; + this.dasRight = false; + this.updateHUD(); + this.hideMessage(); + this.spawnPiece(); + this.lastDrop = performance.now(); + this.lastTimestamp = performance.now(); + cancelAnimationFrame(this.animationId); + this.loop(performance.now()); + } + pause() { + this.paused = true; + this.showMessage("PAUSED — press ENTER or ESC"); + cancelAnimationFrame(this.animationId); + } + unpause() { + this.paused = false; + this.hideMessage(); + this.lastDrop = performance.now(); + this.lastTimestamp = performance.now(); + this.loop(performance.now()); + } +} +// ============================================================ +// Bootstrap +// ============================================================ +document.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=game.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/game.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/game.js.map @@ -0,0 +1 @@ +{"version":3,"file":"game.js","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"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C,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC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AAE,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run3/dist/tetris.js @@ -0,0 +1,430 @@ +"use strict"; +// ─── Constants ─────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const CELL_SIZE = 32; +const PREVIEW_CELLS = 4; +const LINES_PER_LEVEL = 10; +const BASE_DROP_INTERVAL = 800; // ms at level 1 +const MIN_DROP_INTERVAL = 50; +const SPEED_FACTOR = 0.75; // multiplied each level +// ─── Colors ────────────────────────────────────────────────────────── +const PIECE_COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const GHOST_ALPHA = 0.25; +const BOARD_BG = "#111"; +const GRID_LINE = "#222"; +function buildRotations(shape) { + const size = shape.length; + const rots = []; + let cur = shape; + for (let r = 0; r < 4; r++) { + const cells = []; + for (let row = 0; row < size; row++) { + for (let col = 0; col < size; col++) { + if (cur[row][col]) + cells.push([row, col]); + } + } + rots.push(cells); + // rotate 90° clockwise + const next = Array.from({ length: size }, () => Array(size).fill(0)); + for (let row = 0; row < size; row++) + for (let col = 0; col < size; col++) + next[col][size - 1 - row] = cur[row][col]; + cur = next; + } + return rots; +} +const PIECES = [ + { name: "I", rotations: buildRotations([[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]]) }, + { name: "O", rotations: buildRotations([[1, 1], [1, 1]]) }, + { name: "T", rotations: buildRotations([[0, 1, 0], [1, 1, 1], [0, 0, 0]]) }, + { name: "S", rotations: buildRotations([[0, 1, 1], [1, 1, 0], [0, 0, 0]]) }, + { name: "Z", rotations: buildRotations([[1, 1, 0], [0, 1, 1], [0, 0, 0]]) }, + { name: "J", rotations: buildRotations([[1, 0, 0], [1, 1, 1], [0, 0, 0]]) }, + { name: "L", rotations: buildRotations([[0, 0, 1], [1, 1, 1], [0, 0, 0]]) }, +]; +// SRS wall-kick data (for pieces other than O and I) +const WALL_KICKS_JLSTZ = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +const WALL_KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// ─── Score values ──────────────────────────────────────────────────── +const LINE_SCORES = [0, 100, 300, 500, 800]; // index = lines cleared at once +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +// 7-bag randomiser +function refillBag() { + const arr = [...PIECES]; + for (let i = arr.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [arr[i], arr[j]] = [arr[j], arr[i]]; + } + return arr; +} +function pullFromBag(bag) { + if (bag.length === 0) + bag = refillBag(); + const piece = bag[bag.length - 1]; + return { piece, bag: bag.slice(0, -1) }; +} +function spawnPiece(def) { + return { def, rot: 0, row: 0, col: Math.floor((COLS - 4) / 2) }; +} +function cells(p) { + return p.def.rotations[p.rot].map(([r, c]) => [p.row + r, p.col + c]); +} +function collides(board, p) { + for (const [r, c] of cells(p)) { + if (r < 0 || r >= ROWS || c < 0 || c >= COLS) + return true; + if (board[r][c]) + return true; + } + return false; +} +function lockPiece(board, p) { + const color = PIECE_COLORS[p.def.name]; + for (const [r, c] of cells(p)) { + if (r >= 0 && r < ROWS && c >= 0 && c < COLS) { + board[r][c] = color; + } + } +} +function clearLines(board) { + const full = []; + for (let r = 0; r < ROWS; r++) { + if (board[r].every((c) => c !== null)) + full.push(r); + } + return full; +} +function removeRows(board, rows) { + // remove from bottom to keep indices stable + const sorted = [...rows].sort((a, b) => b - a); + for (const r of sorted) { + board.splice(r, 1); + } + while (board.length < ROWS) { + board.unshift(Array(COLS).fill(null)); + } +} +function dropIntervalForLevel(level) { + return Math.max(MIN_DROP_INTERVAL, BASE_DROP_INTERVAL * Math.pow(SPEED_FACTOR, level - 1)); +} +function ghostRow(board, p) { + let test = { ...p }; + while (!collides(board, { ...test, row: test.row + 1 })) { + test.row++; + } + return test.row; +} +// ─── Rotation with SRS wall kicks ──────────────────────────────────── +function tryRotate(board, p, dir) { + const newRot = ((p.rot + dir) % 4 + 4) % 4; + const kickTable = p.def.name === "I" ? WALL_KICKS_I : WALL_KICKS_JLSTZ; + if (p.def.name === "O") { + // O piece doesn't rotate meaningfully, but let's allow it + return { ...p, rot: newRot }; + } + const key = `${p.rot}>${newRot}`; + const kicks = kickTable[key] || [[0, 0]]; + for (const [dc, dr] of kicks) { + const test = { ...p, rot: newRot, row: p.row - dr, col: p.col + dc }; + if (!collides(board, test)) + return test; + } + return null; +} +// ─── Initialise ────────────────────────────────────────────────────── +function initGame() { + let bag = refillBag(); + const { piece: firstDef, bag: bag2 } = pullFromBag(bag); + const { piece: nextDef, bag: bag3 } = pullFromBag(bag2); + return { + board: createBoard(), + piece: spawnPiece(firstDef), + nextDef, + score: 0, + level: 1, + lines: 0, + gameOver: false, + paused: false, + dropInterval: dropIntervalForLevel(1), + lastDrop: performance.now(), + bag: bag3, + animatingRows: [], + animStart: 0, + }; +} +// ─── Canvas Setup ──────────────────────────────────────────────────── +const canvas = document.getElementById("game-canvas"); +const ctx = canvas.getContext("2d"); +canvas.width = COLS * CELL_SIZE; +canvas.height = ROWS * CELL_SIZE; +const previewCanvas = document.getElementById("preview-canvas"); +const previewCtx = previewCanvas.getContext("2d"); +previewCanvas.width = PREVIEW_CELLS * CELL_SIZE; +previewCanvas.height = PREVIEW_CELLS * CELL_SIZE; +const scoreEl = document.getElementById("score"); +const levelEl = document.getElementById("level"); +const linesEl = document.getElementById("lines"); +const overlayEl = document.getElementById("overlay"); +const overlayTextEl = document.getElementById("overlay-text"); +// ─── Drawing ───────────────────────────────────────────────────────── +function drawCell(context, x, y, color, alpha = 1) { + context.globalAlpha = alpha; + context.fillStyle = color; + context.fillRect(x + 1, y + 1, CELL_SIZE - 2, CELL_SIZE - 2); + // highlight + context.fillStyle = "rgba(255,255,255,0.18)"; + context.fillRect(x + 1, y + 1, CELL_SIZE - 2, 4); + context.fillRect(x + 1, y + 1, 4, CELL_SIZE - 2); + // shadow + context.fillStyle = "rgba(0,0,0,0.25)"; + context.fillRect(x + 1, y + CELL_SIZE - 5, CELL_SIZE - 2, 4); + context.fillRect(x + CELL_SIZE - 5, y + 1, 4, CELL_SIZE - 2); + context.globalAlpha = 1; +} +function drawBoard(state) { + const { board, piece, animatingRows } = state; + // background + ctx.fillStyle = BOARD_BG; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // grid lines + ctx.strokeStyle = GRID_LINE; + ctx.lineWidth = 1; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL_SIZE); + ctx.lineTo(COLS * CELL_SIZE, r * CELL_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL_SIZE, 0); + ctx.lineTo(c * CELL_SIZE, ROWS * CELL_SIZE); + ctx.stroke(); + } + // locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c]) { + let alpha = 1; + if (animatingRows.includes(r)) { + const elapsed = performance.now() - state.animStart; + alpha = Math.max(0, 1 - elapsed / 200); + } + drawCell(ctx, c * CELL_SIZE, r * CELL_SIZE, board[r][c], alpha); + } + } + } + if (state.gameOver || animatingRows.length > 0) + return; + // ghost + const gr = ghostRow(board, piece); + if (gr !== piece.row) { + const ghostPiece = { ...piece, row: gr }; + const color = PIECE_COLORS[piece.def.name]; + for (const [r, c] of cells(ghostPiece)) { + drawCell(ctx, c * CELL_SIZE, r * CELL_SIZE, color, GHOST_ALPHA); + } + } + // active piece + const color = PIECE_COLORS[piece.def.name]; + for (const [r, c] of cells(piece)) { + if (r >= 0) + drawCell(ctx, c * CELL_SIZE, r * CELL_SIZE, color); + } +} +function drawPreview(def) { + previewCtx.fillStyle = BOARD_BG; + previewCtx.fillRect(0, 0, previewCanvas.width, previewCanvas.height); + const color = PIECE_COLORS[def.name]; + const rot = def.rotations[0]; + // centre the piece in the 4×4 preview + const minR = Math.min(...rot.map(([r]) => r)); + const maxR = Math.max(...rot.map(([r]) => r)); + const minC = Math.min(...rot.map(([, c]) => c)); + const maxC = Math.max(...rot.map(([, c]) => c)); + const h = maxR - minR + 1; + const w = maxC - minC + 1; + const offR = Math.floor((PREVIEW_CELLS - h) / 2) - minR; + const offC = Math.floor((PREVIEW_CELLS - w) / 2) - minC; + for (const [r, c] of rot) { + drawCell(previewCtx, (c + offC) * CELL_SIZE, (r + offR) * CELL_SIZE, color); + } +} +function updateHUD(state) { + scoreEl.textContent = state.score.toString(); + levelEl.textContent = state.level.toString(); + linesEl.textContent = state.lines.toString(); +} +// ─── Game Logic ────────────────────────────────────────────────────── +let state = initGame(); +function movePiece(dr, dc) { + const test = { ...state.piece, row: state.piece.row + dr, col: state.piece.col + dc }; + if (!collides(state.board, test)) { + state.piece = test; + return true; + } + return false; +} +function hardDrop() { + const gr = ghostRow(state.board, state.piece); + state.score += (gr - state.piece.row) * 2; + state.piece = { ...state.piece, row: gr }; + placePiece(); +} +function placePiece() { + lockPiece(state.board, state.piece); + const full = clearLines(state.board); + if (full.length > 0) { + state.animatingRows = full; + state.animStart = performance.now(); + } + else { + spawnNext(); + } +} +function spawnNext() { + const { piece: nextDef, bag } = pullFromBag(state.bag); + state.bag = bag; + state.piece = spawnPiece(state.nextDef); + state.nextDef = nextDef; + if (collides(state.board, state.piece)) { + state.gameOver = true; + showOverlay("GAME OVER<br><small>Press R to restart</small>"); + } + state.lastDrop = performance.now(); +} +function finishLineClear() { + const count = state.animatingRows.length; + removeRows(state.board, state.animatingRows); + state.animatingRows = []; + state.lines += count; + state.score += (LINE_SCORES[count] || 0) * state.level; + const newLevel = Math.floor(state.lines / LINES_PER_LEVEL) + 1; + if (newLevel !== state.level) { + state.level = newLevel; + state.dropInterval = dropIntervalForLevel(newLevel); + } + spawnNext(); +} +function showOverlay(html) { + overlayTextEl.innerHTML = html; + overlayEl.style.display = "flex"; +} +function hideOverlay() { + overlayEl.style.display = "none"; +} +function restart() { + state = initGame(); + hideOverlay(); +} +// ─── Input ─────────────────────────────────────────────────────────── +document.addEventListener("keydown", (e) => { + if (state.gameOver) { + if (e.key === "r" || e.key === "R") + restart(); + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + state.paused = !state.paused; + if (state.paused) { + showOverlay("PAUSED<br><small>Press P to resume</small>"); + } + else { + hideOverlay(); + state.lastDrop = performance.now(); + } + return; + } + if (state.paused) + return; + if (state.animatingRows.length > 0) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + movePiece(0, -1); + break; + case "ArrowRight": + case "d": + movePiece(0, 1); + break; + case "ArrowDown": + case "s": + if (movePiece(1, 0)) + state.score += 1; // soft-drop bonus + state.lastDrop = performance.now(); + break; + case "ArrowUp": + case "w": { + const rotated = tryRotate(state.board, state.piece, 1); + if (rotated) + state.piece = rotated; + break; + } + case "z": + case "Z": { + const rotated = tryRotate(state.board, state.piece, -1); + if (rotated) + state.piece = rotated; + break; + } + case " ": + hardDrop(); + break; + } + e.preventDefault(); +}); +// ─── Game Loop ─────────────────────────────────────────────────────── +function gameLoop(now) { + // line-clear animation + if (state.animatingRows.length > 0) { + const elapsed = now - state.animStart; + if (elapsed >= 200) { + finishLineClear(); + } + } + if (!state.gameOver && !state.paused && state.animatingRows.length === 0) { + if (now - state.lastDrop >= state.dropInterval) { + if (!movePiece(1, 0)) { + placePiece(); + } + state.lastDrop = now; + } + } + drawBoard(state); + drawPreview(state.nextDef); + updateHUD(state); + requestAnimationFrame(gameLoop); +} +requestAnimationFrame(gameLoop); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run3/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run3/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":";AAAA,wEAAwE;AACxE,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,SAAS,GAAG,EAAE,CAAC;AACrB,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,kBAAkB,GAAG,GAAG,CAAC,CAAC,gBAAgB;AAChD,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,CAAC,wBAAwB;AAEnD,wEAAwE;AACxE,MAAM,YAAY,GAA2B;IAC3C,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;CACb,CAAC;AAEF,MAAM,WAAW,GAAG,IAAI,CAAC;AACzB,MAAM,QAAQ,GAAG,MAAM,CAAC;AACxB,MAAM,SAAS,GAAG,MAAM,CAAC;AAUzB,SAAS,cAAc,CAAC,KAAiB;IACvC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC;IAC1B,MAAM,IAAI,GAAe,EAAE,CAAC;IAC5B,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;YACpC,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;gBACpC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;oBAAE,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjB,uBAAuB;QACvB,MAAM,IAAI,GAAe,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACjF,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE;YACjC,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE;gBACjC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QAC9C,GAAG,GAAG,IAAI,CAAC;IACb,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,MAAM,GAAe;IACzB,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC,EAAE;IACnF,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC,EAAE;IACvD,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC,EAAE;IACnE,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC,EAAE;IACnE,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC,EAAE;IACnE,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC,EAAE;IACnE,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC,EAAE;CACpE,CAAC;AAEF,qDAAqD;AACrD,MAAM,gBAAgB,GAAuC;IAC3D,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACvC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACvC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACxC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IAC1C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IAC1C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;CACzC,CAAC;AAEF,MAAM,YAAY,GAAuC;IACvD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;CAC1C,CAAC;AAEF,wEA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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,613 @@ +"use strict"; +// ── Types ────────────────────────────────────────────────────────────────── +// ── Constants ────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 30; +const PREVIEW_BLOCK = 20; +const TETROMINOES = [ + { + shapes: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + color: "#00f0f0", + }, + { + shapes: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + color: "#f0f000", + }, + { + shapes: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + color: "#a000f0", + }, + { + shapes: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + color: "#00f000", + }, + { + shapes: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + color: "#f00000", + }, + { + shapes: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + color: "#0000f0", + }, + { + shapes: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], + color: "#f0a000", + }, +]; +const LINE_POINTS = [0, 100, 300, 500, 800]; +const SOFT_DROP_POINTS = 1; +const HARD_DROP_POINTS = 2; +// ── Wall Kick Data (SRS) ────────────────────────────────────────────────── +const WALL_KICKS = { + "0>1": [[-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[1, 0], [1, 1], [0, -2], [1, -2]], +}; +const I_WALL_KICKS = { + "0>1": [[-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// ── Game Class ───────────────────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.current = null; + this.currentRotation = 0; + this.currentTetrominoIndex = -1; + this.nextTetrominoIndex = -1; + this.heldTetrominoIndex = -1; + this.canHold = true; + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameOver = false; + this.paused = false; + this.started = false; + this.dropInterval = 1000; + this.lastDrop = 0; + this.lockDelay = 500; + this.lockTimer = 0; + this.isLocking = false; + this.animatingRows = []; + this.animationStart = 0; + this.ANIMATION_DURATION = 300; + this.bag = []; + this.canvas = document.getElementById("game-canvas"); + this.ctx = this.canvas.getContext("2d"); + this.canvas.width = COLS * BLOCK_SIZE; + this.canvas.height = ROWS * BLOCK_SIZE; + this.previewCanvas = document.getElementById("preview-canvas"); + this.previewCtx = this.previewCanvas.getContext("2d"); + this.previewCanvas.width = 4 * PREVIEW_BLOCK; + this.previewCanvas.height = 4 * PREVIEW_BLOCK; + this.holdCanvas = document.getElementById("hold-canvas"); + this.holdCtx = this.holdCanvas.getContext("2d"); + this.holdCanvas.width = 4 * PREVIEW_BLOCK; + this.holdCanvas.height = 4 * PREVIEW_BLOCK; + this.scoreEl = document.getElementById("score"); + this.levelEl = document.getElementById("level"); + this.linesEl = document.getElementById("lines"); + this.messageEl = document.getElementById("message"); + this.board = this.createBoard(); + this.bindKeys(); + this.showMessage("Press ENTER to start"); + this.drawBoard(); + } + // ── Board helpers ────────────────────────────────────────────────────── + createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); + } + // ── 7-bag randomiser ────────────────────────────────────────────────── + refillBag() { + const indices = [0, 1, 2, 3, 4, 5, 6]; + for (let i = indices.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [indices[i], indices[j]] = [indices[j], indices[i]]; + } + this.bag.push(...indices); + } + nextFromBag() { + if (this.bag.length < 2) + this.refillBag(); + return this.bag.shift(); + } + // ── Piece management ────────────────────────────────────────────────── + spawnPiece(tetrominoIndex) { + const idx = tetrominoIndex ?? this.nextTetrominoIndex; + this.nextTetrominoIndex = this.nextFromBag(); + const t = TETROMINOES[idx]; + this.currentTetrominoIndex = idx; + this.currentRotation = 0; + this.current = { + shape: t.shapes[0], + color: t.color, + x: Math.floor((COLS - t.shapes[0][0].length) / 2), + y: 0, + }; + this.isLocking = false; + this.canHold = true; + if (this.collides(this.current.shape, this.current.x, this.current.y)) { + this.gameOver = true; + this.showMessage("GAME OVER — press ENTER"); + } + } + // ── Collision detection ─────────────────────────────────────────────── + collides(shape, px, py) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = px + c; + const by = py + r; + if (bx < 0 || bx >= COLS || by >= ROWS) + return true; + if (by >= 0 && this.board[by][bx]) + return true; + } + } + return false; + } + // ── Movement ────────────────────────────────────────────────────────── + moveLeft() { + if (!this.current || this.gameOver || this.paused) + return; + if (!this.collides(this.current.shape, this.current.x - 1, this.current.y)) { + this.current.x--; + if (this.isLocking) + this.lockTimer = performance.now(); + } + } + moveRight() { + if (!this.current || this.gameOver || this.paused) + return; + if (!this.collides(this.current.shape, this.current.x + 1, this.current.y)) { + this.current.x++; + if (this.isLocking) + this.lockTimer = performance.now(); + } + } + moveDown() { + if (!this.current || this.gameOver || this.paused) + return false; + if (!this.collides(this.current.shape, this.current.x, this.current.y + 1)) { + this.current.y++; + this.isLocking = false; + return true; + } + return false; + } + softDrop() { + if (this.moveDown()) { + this.score += SOFT_DROP_POINTS; + this.updateScore(); + } + } + hardDrop() { + if (!this.current || this.gameOver || this.paused) + return; + let dropped = 0; + while (!this.collides(this.current.shape, this.current.x, this.current.y + 1)) { + this.current.y++; + dropped++; + } + this.score += dropped * HARD_DROP_POINTS; + this.updateScore(); + this.lockPiece(); + } + getGhostY() { + if (!this.current) + return 0; + let gy = this.current.y; + while (!this.collides(this.current.shape, this.current.x, gy + 1)) { + gy++; + } + return gy; + } + // ── Rotation with SRS wall kicks ────────────────────────────────────── + rotate(dir) { + if (!this.current || this.gameOver || this.paused) + return; + const t = TETROMINOES[this.currentTetrominoIndex]; + const from = this.currentRotation; + const to = (from + dir + 4) % 4; + const newShape = t.shapes[to]; + // Basic rotation + if (!this.collides(newShape, this.current.x, this.current.y)) { + this.current.shape = newShape; + this.currentRotation = to; + if (this.isLocking) + this.lockTimer = performance.now(); + return; + } + // Wall kicks + const kickKey = `${from}>${to}`; + const kicks = this.currentTetrominoIndex === 0 ? I_WALL_KICKS[kickKey] : WALL_KICKS[kickKey]; + if (!kicks) + return; + for (const [dx, dy] of kicks) { + if (!this.collides(newShape, this.current.x + dx, this.current.y - dy)) { + this.current.x += dx; + this.current.y -= dy; + this.current.shape = newShape; + this.currentRotation = to; + if (this.isLocking) + this.lockTimer = performance.now(); + return; + } + } + } + // ── Hold ────────────────────────────────────────────────────────────── + holdPiece() { + if (!this.current || !this.canHold || this.gameOver || this.paused) + return; + this.canHold = false; + const prev = this.heldTetrominoIndex; + this.heldTetrominoIndex = this.currentTetrominoIndex; + if (prev === -1) { + this.spawnPiece(); + } + else { + this.spawnPiece(prev); + } + } + // ── Lock & clear ───────────────────────────────────────────────────── + lockPiece() { + if (!this.current) + return; + const { shape, color, x, y } = this.current; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const by = y + r; + const bx = x + c; + if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) { + this.board[by][bx] = color; + } + } + } + this.current = null; + this.clearLines(); + } + clearLines() { + const fullRows = []; + for (let r = 0; r < ROWS; r++) { + if (this.board[r].every((c) => c !== null)) { + fullRows.push(r); + } + } + if (fullRows.length === 0) { + this.spawnPiece(); + return; + } + // Start line-clear animation + this.animatingRows = fullRows; + this.animationStart = performance.now(); + } + finishClear() { + const fullRows = this.animatingRows; + this.animatingRows = []; + // Remove rows top-to-bottom so indices stay stable when shifting + for (const row of fullRows.sort((a, b) => a - b)) { + this.board.splice(row, 1); + this.board.unshift(Array(COLS).fill(null)); + } + const cleared = fullRows.length; + this.lines += cleared; + this.score += LINE_POINTS[cleared] * this.level; + this.level = Math.floor(this.lines / 10) + 1; + this.dropInterval = Math.max(50, 1000 - (this.level - 1) * 80); + this.updateScore(); + this.spawnPiece(); + } + // ── Rendering ───────────────────────────────────────────────────────── + drawBlock(ctx, x, y, color, size, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size, y * size, size, size); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x * size, y * size, size, size * 0.15); + ctx.fillRect(x * size, y * size, size * 0.15, size); + // Shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x * size, y * size + size * 0.85, size, size * 0.15); + ctx.fillRect(x * size + size * 0.85, y * size, size * 0.15, size); + // Border + ctx.strokeStyle = "rgba(0,0,0,0.4)"; + ctx.lineWidth = 1; + ctx.strokeRect(x * size + 0.5, y * size + 0.5, size - 1, size - 1); + ctx.globalAlpha = 1; + } + drawBoard() { + const ctx = this.ctx; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + ctx.lineWidth = 1; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(COLS * BLOCK_SIZE, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.stroke(); + } + // Compute animation flash alpha + const now = performance.now(); + let flashAlpha = 1; + if (this.animatingRows.length > 0) { + const elapsed = now - this.animationStart; + flashAlpha = 0.3 + 0.7 * Math.abs(Math.sin((elapsed / this.ANIMATION_DURATION) * Math.PI * 3)); + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.board[r][c]) { + const alpha = this.animatingRows.includes(r) ? flashAlpha : 1; + this.drawBlock(ctx, c, r, this.board[r][c], BLOCK_SIZE, alpha); + } + } + } + if (this.current && this.animatingRows.length === 0) { + // Ghost piece + const gy = this.getGhostY(); + for (let r = 0; r < this.current.shape.length; r++) { + for (let c = 0; c < this.current.shape[r].length; c++) { + if (!this.current.shape[r][c]) + continue; + this.drawBlock(ctx, this.current.x + c, gy + r, this.current.color, BLOCK_SIZE, 0.2); + } + } + // Active piece + for (let r = 0; r < this.current.shape.length; r++) { + for (let c = 0; c < this.current.shape[r].length; c++) { + if (!this.current.shape[r][c]) + continue; + const py = this.current.y + r; + if (py >= 0) { + this.drawBlock(ctx, this.current.x + c, py, this.current.color, BLOCK_SIZE); + } + } + } + } + } + drawPreview() { + const ctx = this.previewCtx; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, this.previewCanvas.width, this.previewCanvas.height); + if (this.nextTetrominoIndex < 0) + return; + const t = TETROMINOES[this.nextTetrominoIndex]; + const shape = t.shapes[0]; + const ox = (4 - shape[0].length) / 2; + const oy = (4 - shape.length) / 2; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + this.drawBlock(ctx, ox + c, oy + r, t.color, PREVIEW_BLOCK); + } + } + } + } + drawHold() { + const ctx = this.holdCtx; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, this.holdCanvas.width, this.holdCanvas.height); + if (this.heldTetrominoIndex < 0) + return; + const t = TETROMINOES[this.heldTetrominoIndex]; + const shape = t.shapes[0]; + const ox = (4 - shape[0].length) / 2; + const oy = (4 - shape.length) / 2; + const alpha = this.canHold ? 1 : 0.35; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + this.drawBlock(ctx, ox + c, oy + r, t.color, PREVIEW_BLOCK, alpha); + } + } + } + } + // ── HUD helpers ─────────────────────────────────────────────────────── + updateScore() { + this.scoreEl.textContent = this.score.toString(); + this.levelEl.textContent = this.level.toString(); + this.linesEl.textContent = this.lines.toString(); + } + showMessage(msg) { + this.messageEl.textContent = msg; + this.messageEl.style.display = "block"; + } + hideMessage() { + this.messageEl.style.display = "none"; + } + // ── Input ───────────────────────────────────────────────────────────── + bindKeys() { + document.addEventListener("keydown", (e) => { + if (e.key === "Enter") { + if (this.gameOver || !this.started) { + this.reset(); + return; + } + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + if (!this.gameOver && this.started) { + this.paused = !this.paused; + if (this.paused) { + this.showMessage("PAUSED — press P"); + } + else { + this.hideMessage(); + this.lastDrop = performance.now(); + } + } + return; + } + if (this.paused || this.gameOver || !this.started) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + e.preventDefault(); + this.moveLeft(); + break; + case "ArrowRight": + case "d": + e.preventDefault(); + this.moveRight(); + break; + case "ArrowDown": + case "s": + e.preventDefault(); + this.softDrop(); + break; + case "ArrowUp": + case "x": + e.preventDefault(); + this.rotate(1); + break; + case "z": + case "Control": + e.preventDefault(); + this.rotate(-1); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + case "Shift": + case "c": + e.preventDefault(); + this.holdPiece(); + break; + } + }); + } + // ── Game loop ───────────────────────────────────────────────────────── + reset() { + this.board = this.createBoard(); + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameOver = false; + this.paused = false; + this.dropInterval = 1000; + this.lastDrop = performance.now(); + this.isLocking = false; + this.heldTetrominoIndex = -1; + this.canHold = true; + this.bag = []; + this.animatingRows = []; + this.nextTetrominoIndex = this.nextFromBag(); + this.spawnPiece(); + this.updateScore(); + this.hideMessage(); + if (!this.started) { + this.started = true; + requestAnimationFrame((t) => this.loop(t)); + } + } + loop(now) { + if (!this.gameOver) { + requestAnimationFrame((t) => this.loop(t)); + } + if (this.paused) { + this.drawBoard(); + this.drawPreview(); + this.drawHold(); + return; + } + // Handle line-clear animation + if (this.animatingRows.length > 0) { + if (now - this.animationStart >= this.ANIMATION_DURATION) { + this.finishClear(); + } + this.drawBoard(); + this.drawPreview(); + this.drawHold(); + return; + } + // Gravity + if (this.current) { + if (!this.collides(this.current.shape, this.current.x, this.current.y + 1)) { + if (now - this.lastDrop >= this.dropInterval) { + this.current.y++; + this.lastDrop = now; + this.isLocking = false; + } + } + else { + // Piece is resting – start / check lock delay + if (!this.isLocking) { + this.isLocking = true; + this.lockTimer = now; + } + else if (now - this.lockTimer >= this.lockDelay) { + this.lockPiece(); + this.lastDrop = now; + } + } + } + this.drawBoard(); + this.drawPreview(); + this.drawHold(); + } +} +// ── Bootstrap ────────────────────────────────────────────────────────────── +window.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,482 @@ +"use strict"; +// ============================================================ +// Tetris – full browser game in TypeScript +// ============================================================ +// ----- Constants -------------------------------------------- +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 32; +const PREVIEW_BLOCK = 24; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const GHOST_ALPHA = 0.25; +function rotateMatrix(coords) { + // 90° clockwise: (r,c) → (c, -r) then normalise to 0-origin + const rotated = coords.map(([r, c]) => [c, -r]); + const minR = Math.min(...rotated.map(([r]) => r)); + const minC = Math.min(...rotated.map(([, c]) => c)); + return rotated.map(([r, c]) => [r - minR, c - minC]); +} +function buildRotations(base) { + const states = [base]; + let current = base; + for (let i = 0; i < 3; i++) { + current = rotateMatrix(current); + states.push(current); + } + return states; +} +const TETROMINOS = { + I: { shape: buildRotations([[0, 0], [0, 1], [0, 2], [0, 3]]), color: COLORS.I }, + O: { shape: [[[0, 0], [0, 1], [1, 0], [1, 1]]], color: COLORS.O }, + T: { shape: buildRotations([[0, 1], [1, 0], [1, 1], [1, 2]]), color: COLORS.T }, + S: { shape: buildRotations([[0, 1], [0, 2], [1, 0], [1, 1]]), color: COLORS.S }, + Z: { shape: buildRotations([[0, 0], [0, 1], [1, 1], [1, 2]]), color: COLORS.Z }, + J: { shape: buildRotations([[0, 0], [1, 0], [1, 1], [1, 2]]), color: COLORS.J }, + L: { shape: buildRotations([[0, 2], [1, 0], [1, 1], [1, 2]]), color: COLORS.L }, +}; +// SRS wall-kick offsets (JLSTZ and I have different tables) +const WALL_KICKS_JLSTZ = [ + // 0→1 + [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + // 1→2 + [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + // 2→3 + [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + // 3→0 + [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], +]; +const WALL_KICKS_I = [ + [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], +]; +// Scoring (original Nintendo scoring) +const LINE_SCORES = [0, 100, 300, 500, 800]; +const SOFT_DROP_SCORE = 1; +const HARD_DROP_SCORE = 2; +class Board { + constructor() { + this.grid = []; + for (let r = 0; r < ROWS; r++) { + this.grid.push(new Array(COLS).fill(null)); + } + } + isInside(r, c) { + return r >= 0 && r < ROWS && c >= 0 && c < COLS; + } + isEmpty(r, c) { + return this.isInside(r, c) && this.grid[r][c] === null; + } + /** Returns true if all cells occupied by the shape are valid (inside + empty) */ + isValid(shape, row, col) { + for (const [dr, dc] of shape) { + const nr = row + dr; + const nc = col + dc; + if (!this.isInside(nr, nc) || this.grid[nr][nc] !== null) + return false; + } + return true; + } + lock(shape, row, col, color) { + for (const [dr, dc] of shape) { + this.grid[row + dr][col + dc] = color; + } + } + /** Clears completed lines, returns number cleared */ + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.grid[r].every(c => c !== null)) { + this.grid.splice(r, 1); + this.grid.unshift(new Array(COLS).fill(null)); + cleared++; + r++; // re-check this row index + } + } + return cleared; + } +} +// ----- Piece ------------------------------------------------ +class Piece { + constructor(type) { + this.type = type; + this.def = TETROMINOS[type]; + this.rotation = 0; + this.row = 0; + this.col = Math.floor((COLS - this.width()) / 2); + } + get shape() { + return this.def.shape[this.rotation % this.def.shape.length]; + } + get color() { + return this.def.color; + } + width() { + return Math.max(...this.shape.map(([, c]) => c)) + 1; + } +} +// ----- Game ------------------------------------------------- +class TetrisGame { + constructor() { + this.nextTypes = []; + this.heldType = null; + this.canHold = true; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.bag = []; + this.dropInterval = 1000; + this.lastDrop = 0; + this.lockDelay = 500; + this.lockTimer = null; + this.animationId = 0; + // ---- game loop ---- + this.loop = (now) => { + this.animationId = requestAnimationFrame(this.loop); + if (this.gameOver) { + this.render(); + this.messageEl.textContent = "GAME OVER – Press R to restart"; + return; + } + if (this.paused) { + this.render(); + this.messageEl.textContent = "PAUSED"; + return; + } + this.messageEl.textContent = ""; + // Gravity + const elapsed = now - this.lastDrop; + if (elapsed >= this.dropInterval) { + if (!this.move(1, 0)) { + // Can't move down — engage lock delay + if (this.lockTimer === null) { + this.lockTimer = now; + } + else if (now - this.lockTimer >= this.lockDelay) { + this.lockPiece(); + this.lockTimer = null; + } + } + else { + this.lockTimer = null; + } + this.lastDrop = now; + } + this.render(); + }; + this.board = new Board(); + this.grabDOM(); + this.fillQueue(); + this.spawnPiece(); + this.bindKeys(); + this.lastDrop = performance.now(); + this.animationId = requestAnimationFrame(this.loop); + } + // ---- helpers ---- + grabDOM() { + this.canvas = document.getElementById("game-canvas"); + this.ctx = this.canvas.getContext("2d"); + this.canvas.width = COLS * BLOCK_SIZE; + this.canvas.height = ROWS * BLOCK_SIZE; + this.previewCanvas = document.getElementById("preview-canvas"); + this.previewCtx = this.previewCanvas.getContext("2d"); + this.previewCanvas.width = 5 * PREVIEW_BLOCK; + this.previewCanvas.height = 14 * PREVIEW_BLOCK; + this.holdCanvas = document.getElementById("hold-canvas"); + this.holdCtx = this.holdCanvas.getContext("2d"); + this.holdCanvas.width = 5 * PREVIEW_BLOCK; + this.holdCanvas.height = 3 * PREVIEW_BLOCK; + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.messageEl = document.getElementById("message"); + } + randomBag() { + const types = Object.keys(TETROMINOS); + // Fisher-Yates + for (let i = types.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [types[i], types[j]] = [types[j], types[i]]; + } + return types; + } + fillQueue() { + while (this.nextTypes.length < 5) { + if (this.bag.length === 0) + this.bag = this.randomBag(); + this.nextTypes.push(this.bag.pop()); + } + } + spawnPiece() { + const type = this.nextTypes.shift(); + this.fillQueue(); + this.current = new Piece(type); + this.canHold = true; + this.lockTimer = null; + if (!this.board.isValid(this.current.shape, this.current.row, this.current.col)) { + this.gameOver = true; + } + } + getSpeed() { + // Frames → ms per drop. Classic NES-like curve. + const speeds = [1000, 900, 800, 700, 600, 500, 400, 300, 200, 150, 100, 80, 60, 50, 40, 30]; + const idx = Math.min(this.level - 1, speeds.length - 1); + return speeds[idx]; + } + // ---- movement ---- + move(dr, dc) { + if (this.board.isValid(this.current.shape, this.current.row + dr, this.current.col + dc)) { + this.current.row += dr; + this.current.col += dc; + return true; + } + return false; + } + rotate(dir) { + const piece = this.current; + const oldRot = piece.rotation; + const numStates = piece.def.shape.length; + const newRot = ((oldRot + dir) % numStates + numStates) % numStates; + const newShape = piece.def.shape[newRot]; + // Determine kick table + let kicks; + if (piece.type === "O") { + kicks = [[0, 0]]; + } + else if (piece.type === "I") { + const kickIdx = dir === 1 ? oldRot : ((newRot) % 4); + kicks = dir === 1 ? WALL_KICKS_I[kickIdx] : WALL_KICKS_I[kickIdx].map(([r, c]) => [-r, -c]); + } + else { + const kickIdx = dir === 1 ? oldRot : ((newRot) % 4); + kicks = dir === 1 ? WALL_KICKS_JLSTZ[kickIdx] : WALL_KICKS_JLSTZ[kickIdx].map(([r, c]) => [-r, -c]); + } + for (const [kc, kr] of kicks) { + if (this.board.isValid(newShape, piece.row + kr, piece.col + kc)) { + piece.rotation = newRot; + piece.row += kr; + piece.col += kc; + return; + } + } + } + hardDrop() { + let distance = 0; + while (this.move(1, 0)) + distance++; + this.score += distance * HARD_DROP_SCORE; + this.lockPiece(); + } + softDrop() { + if (this.move(1, 0)) { + this.score += SOFT_DROP_SCORE; + return true; + } + return false; + } + ghostRow() { + let r = this.current.row; + while (this.board.isValid(this.current.shape, r + 1, this.current.col)) + r++; + return r; + } + lockPiece() { + this.board.lock(this.current.shape, this.current.row, this.current.col, this.current.color); + const cleared = this.board.clearLines(); + this.lines += cleared; + this.score += LINE_SCORES[cleared] * this.level; + this.level = Math.floor(this.lines / 10) + 1; + this.dropInterval = this.getSpeed(); + this.spawnPiece(); + this.lastDrop = performance.now(); + } + hold() { + if (!this.canHold) + return; + const type = this.current.type; + if (this.heldType) { + this.current = new Piece(this.heldType); + } + else { + this.spawnPiece(); + } + this.heldType = type; + this.canHold = false; + this.lockTimer = null; + } + // ---- input ---- + bindKeys() { + document.addEventListener("keydown", (e) => { + if (this.gameOver) { + if (e.key === "r" || e.key === "R") + this.restart(); + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.paused = !this.paused; + if (!this.paused) { + this.lastDrop = performance.now(); + } + return; + } + if (this.paused) + return; + switch (e.key) { + case "ArrowLeft": + this.move(0, -1); + break; + case "ArrowRight": + this.move(0, 1); + break; + case "ArrowDown": + this.softDrop(); + this.lastDrop = performance.now(); + break; + case "ArrowUp": + this.rotate(1); + break; + case "z": + case "Z": + this.rotate(-1); + break; + case " ": + this.hardDrop(); + break; + case "c": + case "C": + case "Shift": + this.hold(); + break; + } + e.preventDefault(); + }); + } + // ---- rendering ---- + drawBlock(ctx, r, c, color, size, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(c * size, r * size, size, size); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(c * size, r * size, size, size * 0.15); + ctx.fillRect(c * size, r * size, size * 0.15, size); + // Shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(c * size, r * size + size * 0.85, size, size * 0.15); + ctx.fillRect(c * size + size * 0.85, r * size, size * 0.15, size); + // Border + ctx.strokeStyle = "rgba(0,0,0,0.4)"; + ctx.lineWidth = 1; + ctx.strokeRect(c * size + 0.5, r * size + 0.5, size - 1, size - 1); + ctx.globalAlpha = 1; + } + render() { + const ctx = this.ctx; + const bs = BLOCK_SIZE; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * bs); + ctx.lineTo(COLS * bs, r * bs); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * bs, 0); + ctx.lineTo(c * bs, ROWS * bs); + ctx.stroke(); + } + // Locked blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const cell = this.board.grid[r][c]; + if (cell) + this.drawBlock(ctx, r, c, cell, bs); + } + } + if (!this.gameOver) { + // Ghost piece + const ghostR = this.ghostRow(); + for (const [dr, dc] of this.current.shape) { + this.drawBlock(ctx, ghostR + dr, this.current.col + dc, this.current.color, bs, GHOST_ALPHA); + } + // Active piece + for (const [dr, dc] of this.current.shape) { + this.drawBlock(ctx, this.current.row + dr, this.current.col + dc, this.current.color, bs); + } + } + // HUD + this.scoreEl.textContent = this.score.toString(); + this.linesEl.textContent = this.lines.toString(); + this.levelEl.textContent = this.level.toString(); + // Preview (next 5 pieces) + this.renderPreview(); + // Hold piece + this.renderHold(); + } + renderSmallPiece(ctx, type, offsetR, offsetC) { + const def = TETROMINOS[type]; + const shape = def.shape[0]; + const maxC = Math.max(...shape.map(([, c]) => c)) + 1; + const maxR = Math.max(...shape.map(([r]) => r)) + 1; + const padC = (4 - maxC) / 2; + const padR = (2 - maxR) / 2; + for (const [dr, dc] of shape) { + this.drawBlock(ctx, offsetR + padR + dr, offsetC + padC + dc, def.color, PREVIEW_BLOCK); + } + } + renderPreview() { + const ctx = this.previewCtx; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, this.previewCanvas.width, this.previewCanvas.height); + for (let i = 0; i < Math.min(5, this.nextTypes.length); i++) { + this.renderSmallPiece(ctx, this.nextTypes[i], i * 3 + 0.2, 0.3); + } + } + renderHold() { + const ctx = this.holdCtx; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, this.holdCanvas.width, this.holdCanvas.height); + if (this.heldType) { + this.renderSmallPiece(ctx, this.heldType, 0.3, 0.3); + } + } + restart() { + this.board = new Board(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.heldType = null; + this.canHold = true; + this.bag = []; + this.nextTypes = []; + this.dropInterval = 1000; + this.lockTimer = null; + this.fillQueue(); + this.spawnPiece(); + this.lastDrop = performance.now(); + } +} +// ----- Bootstrap -------------------------------------------- +window.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,473 @@ +"use strict"; +// ── Types ────────────────────────────────────────────────────────────────── +// ── Constants ────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 32; +const PREVIEW_BLOCK = 20; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const SHAPES = { + I: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + O: [ + [1, 1], + [1, 1], + ], + T: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + S: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + Z: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + J: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + L: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], +}; +const PIECE_NAMES = Object.keys(SHAPES); +// SRS wall-kick data (non-I pieces) +const WALL_KICKS = { + "0>1": [{ x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "1>0": [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], + "1>2": [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], + "2>1": [{ x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "2>3": [{ x: 1, y: 0 }, { x: 1, y: -1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], + "3>2": [{ x: -1, y: 0 }, { x: -1, y: 1 }, { x: 0, y: -2 }, { x: -1, y: -2 }], + "3>0": [{ x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "0>3": [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], +}; +// SRS wall-kick data (I piece) +const WALL_KICKS_I = { + "0>1": [{ x: -2, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 1 }, { x: 1, y: -2 }], + "1>0": [{ x: 2, y: 0 }, { x: -1, y: 0 }, { x: 2, y: -1 }, { x: -1, y: 2 }], + "1>2": [{ x: -1, y: 0 }, { x: 2, y: 0 }, { x: -1, y: -2 }, { x: 2, y: 1 }], + "2>1": [{ x: 1, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 2 }, { x: -2, y: -1 }], + "2>3": [{ x: 2, y: 0 }, { x: -1, y: 0 }, { x: 2, y: -1 }, { x: -1, y: 2 }], + "3>2": [{ x: -2, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 1 }, { x: 1, y: -2 }], + "3>0": [{ x: 1, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 2 }, { x: -2, y: -1 }], + "0>3": [{ x: -1, y: 0 }, { x: 2, y: 0 }, { x: -1, y: -2 }, { x: 2, y: 1 }], +}; +const POINTS = [0, 100, 300, 500, 800]; +// ── Game State ───────────────────────────────────────────────────────────── +let board; +let current; +let currentType; +let currentRotation; +let next; +let score; +let lines; +let level; +let gameOver; +let paused; +let dropInterval; +let lastDrop; +let animationId; +let lockDelay; +let lockTimer; +let softDropping; +// ── Canvas Setup ─────────────────────────────────────────────────────────── +const canvas = document.getElementById("game-canvas"); +const ctx = canvas.getContext("2d"); +canvas.width = COLS * BLOCK_SIZE; +canvas.height = ROWS * BLOCK_SIZE; +const previewCanvas = document.getElementById("preview-canvas"); +const previewCtx = previewCanvas.getContext("2d"); +previewCanvas.width = 6 * PREVIEW_BLOCK; +previewCanvas.height = 6 * PREVIEW_BLOCK; +const scoreEl = document.getElementById("score"); +const linesEl = document.getElementById("lines"); +const levelEl = document.getElementById("level"); +// ── Helper Functions ─────────────────────────────────────────────────────── +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function randomPiece() { + const type = PIECE_NAMES[Math.floor(Math.random() * PIECE_NAMES.length)]; + return { type, shape: SHAPES[type].map((r) => [...r]), color: COLORS[type] }; +} +function rotateCW(matrix) { + const n = matrix.length; + const result = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + result[c][n - 1 - r] = matrix[r][c]; + } + } + return result; +} +function rotateCCW(matrix) { + const n = matrix.length; + const result = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + result[n - 1 - c][r] = matrix[r][c]; + } + } + return result; +} +function collides(shape, pos) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const nx = pos.x + c; + const ny = pos.y + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && board[ny][nx] !== null) + return true; + } + } + } + return false; +} +function lock() { + for (let r = 0; r < current.shape.length; r++) { + for (let c = 0; c < current.shape[r].length; c++) { + if (current.shape[r][c]) { + const ny = current.pos.y + r; + const nx = current.pos.x + c; + if (ny < 0) { + gameOver = true; + return; + } + board[ny][nx] = current.color; + } + } + } + clearLines(); + spawn(); +} +function clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every((cell) => cell !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // recheck this row + } + } + if (cleared > 0) { + lines += cleared; + score += POINTS[cleared] * (level + 1); + const newLevel = Math.floor(lines / 10); + if (newLevel > level) { + level = newLevel; + dropInterval = Math.max(50, 1000 - level * 80); + } + updateHUD(); + } +} +function spawn() { + currentType = next.type; + currentRotation = 0; + current = { + shape: next.shape, + color: next.color, + pos: { x: Math.floor((COLS - next.shape[0].length) / 2), y: -1 }, + }; + next = randomPiece(); + // If spawn position collides, game over + if (collides(current.shape, current.pos)) { + // Try one row up + current.pos.y = -2; + if (collides(current.shape, current.pos)) { + gameOver = true; + } + } + lockTimer = 0; +} +function ghostY() { + let gy = current.pos.y; + while (!collides(current.shape, { x: current.pos.x, y: gy + 1 })) { + gy++; + } + return gy; +} +function tryRotate(direction) { + const oldShape = current.shape; + const oldRotation = currentRotation; + const newShape = direction === 1 ? rotateCW(oldShape) : rotateCCW(oldShape); + const newRotation = (oldRotation + direction + 4) % 4; + // Try basic rotation first + if (!collides(newShape, current.pos)) { + current.shape = newShape; + currentRotation = newRotation; + resetLockTimer(); + return; + } + // Wall kicks + const kickKey = `${oldRotation}>${newRotation}`; + const kicks = currentType === "I" ? WALL_KICKS_I[kickKey] : WALL_KICKS[kickKey]; + if (kicks) { + for (const kick of kicks) { + const testPos = { x: current.pos.x + kick.x, y: current.pos.y - kick.y }; + if (!collides(newShape, testPos)) { + current.shape = newShape; + current.pos = testPos; + currentRotation = newRotation; + resetLockTimer(); + return; + } + } + } +} +function resetLockTimer() { + if (collides(current.shape, { x: current.pos.x, y: current.pos.y + 1 })) { + lockTimer = performance.now(); + } +} +// ── Drawing ──────────────────────────────────────────────────────────────── +function drawBlock(context, x, y, color, size, alpha = 1) { + context.globalAlpha = alpha; + context.fillStyle = color; + context.fillRect(x * size, y * size, size, size); + // Highlight + context.fillStyle = "rgba(255,255,255,0.3)"; + context.fillRect(x * size, y * size, size, 2); + context.fillRect(x * size, y * size, 2, size); + // Shadow + context.fillStyle = "rgba(0,0,0,0.3)"; + context.fillRect(x * size + size - 2, y * size, 2, size); + context.fillRect(x * size, y * size + size - 2, size, 2); + // Outline + context.strokeStyle = "rgba(0,0,0,0.5)"; + context.strokeRect(x * size, y * size, size, size); + context.globalAlpha = 1; +} +function drawBoard() { + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + ctx.lineWidth = 1; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK_SIZE, r * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); + } + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c]) { + drawBlock(ctx, c, r, board[r][c], BLOCK_SIZE); + } + } + } + // Ghost piece + if (!gameOver && !paused) { + const gy = ghostY(); + for (let r = 0; r < current.shape.length; r++) { + for (let c = 0; c < current.shape[r].length; c++) { + if (current.shape[r][c]) { + const py = gy + r; + const px = current.pos.x + c; + if (py >= 0) { + drawBlock(ctx, px, py, current.color, BLOCK_SIZE, 0.25); + } + } + } + } + } + // Current piece + if (!gameOver && !paused) { + for (let r = 0; r < current.shape.length; r++) { + for (let c = 0; c < current.shape[r].length; c++) { + if (current.shape[r][c]) { + const py = current.pos.y + r; + const px = current.pos.x + c; + if (py >= 0) { + drawBlock(ctx, px, py, current.color, BLOCK_SIZE); + } + } + } + } + } + // Overlay for pause / game over + if (paused && !gameOver) { + ctx.fillStyle = "rgba(0,0,0,0.6)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px monospace"; + ctx.textAlign = "center"; + ctx.fillText("PAUSED", canvas.width / 2, canvas.height / 2); + } + if (gameOver) { + ctx.fillStyle = "rgba(0,0,0,0.7)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "#f44"; + ctx.font = "bold 32px monospace"; + ctx.textAlign = "center"; + ctx.fillText("GAME OVER", canvas.width / 2, canvas.height / 2 - 20); + ctx.fillStyle = "#fff"; + ctx.font = "18px monospace"; + ctx.fillText("Press R to restart", canvas.width / 2, canvas.height / 2 + 20); + } +} +function drawPreview() { + previewCtx.fillStyle = "#1a1a2e"; + previewCtx.fillRect(0, 0, previewCanvas.width, previewCanvas.height); + const shape = next.shape; + const offsetX = (6 - shape[0].length) / 2; + const offsetY = (6 - shape.length) / 2; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + drawBlock(previewCtx, offsetX + c, offsetY + r, next.color, PREVIEW_BLOCK); + } + } + } +} +function updateHUD() { + scoreEl.textContent = score.toString(); + linesEl.textContent = lines.toString(); + levelEl.textContent = level.toString(); +} +// ── Game Loop ────────────────────────────────────────────────────────────── +function gameLoop(now) { + animationId = requestAnimationFrame(gameLoop); + if (gameOver || paused) { + drawBoard(); + drawPreview(); + return; + } + // Gravity + const effectiveInterval = softDropping ? Math.max(30, dropInterval / 15) : dropInterval; + if (now - lastDrop > effectiveInterval) { + if (!collides(current.shape, { x: current.pos.x, y: current.pos.y + 1 })) { + current.pos.y++; + if (softDropping) + score += 1; + lastDrop = now; + lockTimer = 0; + } + else { + // Piece is resting on something — start lock delay + if (lockTimer === 0) { + lockTimer = now; + } + else if (now - lockTimer > lockDelay) { + lock(); + lastDrop = now; + } + } + } + drawBoard(); + drawPreview(); + updateHUD(); +} +// ── Input ────────────────────────────────────────────────────────────────── +document.addEventListener("keydown", (e) => { + if (gameOver) { + if (e.key === "r" || e.key === "R") { + init(); + } + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + paused = !paused; + if (!paused) + lastDrop = performance.now(); + return; + } + if (paused) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + if (!collides(current.shape, { x: current.pos.x - 1, y: current.pos.y })) { + current.pos.x--; + resetLockTimer(); + } + e.preventDefault(); + break; + case "ArrowRight": + case "d": + if (!collides(current.shape, { x: current.pos.x + 1, y: current.pos.y })) { + current.pos.x++; + resetLockTimer(); + } + e.preventDefault(); + break; + case "ArrowDown": + case "s": + softDropping = true; + e.preventDefault(); + break; + case "ArrowUp": + case "w": + tryRotate(1); + e.preventDefault(); + break; + case "z": + case "Z": + tryRotate(-1); + e.preventDefault(); + break; + case " ": + // Hard drop + while (!collides(current.shape, { x: current.pos.x, y: current.pos.y + 1 })) { + current.pos.y++; + score += 2; + } + lock(); + lastDrop = performance.now(); + e.preventDefault(); + break; + } +}); +document.addEventListener("keyup", (e) => { + if (e.key === "ArrowDown" || e.key === "s") { + softDropping = false; + } +}); +// ── Initialization ───────────────────────────────────────────────────────── +function init() { + board = createBoard(); + score = 0; + lines = 0; + level = 0; + gameOver = false; + paused = false; + dropInterval = 1000; + lastDrop = performance.now(); + lockDelay = 500; + lockTimer = 0; + softDropping = false; + next = randomPiece(); + spawn(); + updateHUD(); + if (animationId) + cancelAnimationFrame(animationId); + animationId = requestAnimationFrame(gameLoop); +} +init(); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;CAC3E,CAAC;AAEF,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAEvC,8EAA8E;AAE9E,IAAI,KAAY,CAAC;AACjB,IAAI,OAAc,CAAC;AACnB,IAAI,WAAmB,CAAC;AACxB,IAAI,eAAuB,CAAC;AAC5B,IAAI,IAAwD,CAAC;AAC7D,IAAI,KAAa,CAAC;AAClB,IAAI,KAAa,CAAC;AAClB,IAAI,KAAa,CAAC;AAClB,IAAI,QAAiB,CAAC;AACtB,IAAI,MAAe,CAAC;AACpB,IAAI,YAAoB,CAAC;AACzB,IAAI,QAAgB,CAAC;AACrB,IAAI,WAAmB,CAAC;AACxB,IAAI,SAAiB,CAAC;AACtB,IAAI,SAAiB,CAAC;AACtB,IAAI,YAAqB,CAAC;AAE1B,8EAA8E;AAE9E,MAAM,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAsB,CAAC;AAC3E,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;AACrC,MAAM,CAAC,KAAK,GAAG,IAAI,GAAG,UAAU,CAAC;AACjC,MAAM,CAAC,MAAM,GAAG,IAAI,GAAG,UAAU,CAAC;AAElC,MAAM,aAAa,GAAG,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAsB,CAAC;AACrF,MAAM,UAAU,GAAG,aAAa,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;AACnD,aAAa,CAAC,KAAK,GAAG,CAAC,GAAG,aAAa,CAAC;AACxC,aAAa,CAAC,MAAM,GAAG,CAAC,GAAG,aAAa,CAAC;AAEzC,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC;AAClD,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC;AAClD,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC;AAElD,8EAA8E;AAE9E,SAAS,WAAW;IAClB,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,SAAS,WAAW;IAClB,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IACzE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;AAC/E,CAAC;AAED,SAAS,QAAQ,CAAC,MAAkB;IAClC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;IACxB,MAAM,MAAM,GAAe,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,SAAS,CAAC,MAAkB;IACnC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;IACxB,MAAM,MAAM,GAAe,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,QAAQ,CAAC,KAAiB,EAAE,GAAa;IAChD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChB,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;gBACrB,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;gBACrB,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI;oBAAE,OAAO,IAAI,CAAC;gBACpD,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI;oBAAE,OAAO,IAAI,CAAC;YACrD,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,IAAI;IACX,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACjD,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxB,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;gBAC7B,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;gBAC7B,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;oBACX,QAAQ,GAAG,IAAI,CAAC;oBAChB,OAAO;gBACT,CAAC;gBACD,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC;IACD,UAAU,EAAE,CAAC;IACb,KAAK,EAAE,CAAC;AACV,CAAC;AAED,SAAS,UAAU;IACjB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YAC5C,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACnB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YACtC,OAAO,EAAE,CAAC;YACV,CAAC,EAAE,CAAC,CAAC,mBAAmB;QAC1B,CAAC;IACH,CAAC;IACD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,KAAK,IAAI,OAAO,CAAC;QACjB,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;QACxC,IAAI,QAAQ,GAAG,KAAK,EAAE,CAAC;YACrB,KAAK,GAAG,QAAQ,CAAC;YACjB,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC;QACjD,CAAC;QACD,SAAS,EAAE,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,KAAK;IACZ,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC;IACxB,eAAe,GAAG,CAAC,CAAC;IACpB,OAAO,GAAG;QACR,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,GAAG,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE;KACjE,CAAC;IACF,IAAI,GAAG,WAAW,EAAE,CAAC;IAErB,wCAAwC;IACxC,IAAI,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,iBAAiB;QACjB,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACnB,IAAI,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACzC,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;IACH,CAAC;IACD,SAAS,GAAG,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,MAAM;IACb,IAAI,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;QACjE,EAAE,EAAE,CAAC;IACP,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,SAAS,CAAC,SAAiB;IAClC,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC;IAC/B,MAAM,WAAW,GAAG,eAAe,CAAC;IACpC,MAAM,QAAQ,GAAG,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC5E,MAAM,WAAW,GAAG,CAAC,WAAW,GAAG,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IAEtD,2BAA2B;IAC3B,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC;QACzB,eAAe,GAAG,WAAW,CAAC;QAC9B,cAAc,EAAE,CAAC;QACjB,OAAO;IACT,CAAC;IAED,aAAa;IACb,MAAM,OAAO,GAAG,GAAG,WAAW,IAAI,WAAW,EAAE,CAAC;IAChD,MAAM,KAAK,GAAG,WAAW,KAAK,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAChF,IAAI,KAAK,EAAE,CAAC;QACV,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC;YACzE,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;gBACjC,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC;gBACzB,OAAO,CAAC,GAAG,GAAG,OAAO,CAAC;gBACtB,eAAe,GAAG,WAAW,CAAC;gBAC9B,cAAc,EAAE,CAAC;gBACjB,OAAO;YACT,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,cAAc;IACrB,IAAI,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;QACxE,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAChC,CAAC;AACH,CAAC;AAED,8EAA8E;AAE9E,SAAS,SAAS,CAChB,OAAiC,EACjC,CAAS,EACT,CAAS,EACT,KAAa,EACb,IAAY,EACZ,QAAgB,CAAC;IAEjB,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC;IAC5B,OAAO,CAAC,SAAS,GAAG,KAAK,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAEjD,YAAY;IACZ,OAAO,CAAC,SAAS,GAAG,uBAAuB,CAAC;IAC5C,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9C,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;IAE9C,SAAS;IACT,OAAO,CAAC,SAAS,GAAG,iBAAiB,CAAC;IACtC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;IACzD,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAEzD,UAAU;IACV,OAAO,CAAC,WAAW,GAAG,iBAAiB,CAAC;IACxC,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACnD,OAAO,CAAC,WAAW,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,SAAS;IAChB,aAAa;IACb,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC;IACvB,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAEhD,aAAa;IACb,GAAG,CAAC,WAAW,GAAG,wBAAwB,CAAC;IAC3C,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,GAAG,CAAC,UAAU,CAAC,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IAED,eAAe;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChB,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,EAAE,UAAU,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;IACH,CAAC;IAED,cAAc;IACd,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACjD,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBACxB,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;oBAClB,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;oBAC7B,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;wBACZ,SAAS,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;oBAC1D,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,gBAAgB;IAChB,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACjD,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBACxB,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;oBAC7B,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;oBAC7B,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;wBACZ,SAAS,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;oBACpD,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,IAAI,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACxB,GAAG,CAAC,SAAS,GAAG,iBAAiB,CAAC;QAClC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAChD,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC;QACvB,GAAG,CAAC,IAAI,GAAG,qBAAqB,CAAC;QACjC,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAC;QACzB,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,QAAQ,EAAE,CAAC;QACb,GAAG,CAAC,SAAS,GAAG,iBAAiB,CAAC;QAClC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAChD,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC;QACvB,GAAG,CAAC,IAAI,GAAG,qBAAqB,CAAC;QACjC,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAC;QACzB,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QACpE,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC;QACvB,GAAG,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC5B,GAAG,CAAC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/E,CAAC;AACH,CAAC;AAED,SAAS,WAAW;IAClB,UAAU,CAAC,SAAS,GAAG,SAAS,CAAC;IACjC,UAAU,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAErE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACzB,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChB,SAAS,CAAC,UAAU,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;YAC7E,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;IACvC,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;IACvC,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;AACzC,CAAC;AAED,8EAA8E;AAE9E,SAAS,QAAQ,CAAC,GAAW;IAC3B,WAAW,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAE9C,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;QACvB,SAAS,EAAE,CAAC;QACZ,WAAW,EAAE,CAAC;QACd,OAAO;IACT,CAAC;IAED,UAAU;IACV,MAAM,iBAAiB,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,YAAY,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;IACxF,IAAI,GAAG,GAAG,QAAQ,GAAG,iBAAiB,EAAE,CAAC;QACvC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACzE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAChB,IAAI,YAAY;gBAAE,KAAK,IAAI,CAAC,CAAC;YAC7B,QAAQ,GAAG,GAAG,CAAC;YACf,SAAS,GAAG,CAAC,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,mDAAmD;YACnD,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;gBACpB,SAAS,GAAG,GAAG,CAAC;YAClB,CAAC;iBAAM,IAAI,GAAG,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC;gBACvC,IAAI,EAAE,CAAC;gBACP,QAAQ,GAAG,GAAG,CAAC;YACjB,CAAC;QACH,CAAC;IACH,CAAC;IAED,SAAS,EAAE,CAAC;IACZ,WAAW,EAAE,CAAC;IACd,SAAS,EAAE,CAAC;AACd,CAAC;AAED,8EAA8E;AAE9E,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAgB,EAAE,EAAE;IACxD,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;YACnC,IAAI,EAAE,CAAC;QACT,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;QACzD,MAAM,GAAG,CAAC,MAAM,CAAC;QACjB,IAAI,CAAC,MAAM;YAAE,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC1C,OAAO;IACT,CAAC;IAED,IAAI,MAAM;QAAE,OAAO;IAEnB,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC;QACd,KAAK,WAAW,CAAC;QACjB,KAAK,GAAG;YACN,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;gBACzE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBAChB,cAAc,EAAE,CAAC;YACnB,CAAC;YACD,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,MAAM;QACR,KAAK,YAAY,CAAC;QAClB,KAAK,GAAG;YACN,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;gBACzE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBAChB,cAAc,EAAE,CAAC;YACnB,CAAC;YACD,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,MAAM;QACR,KAAK,WAAW,CAAC;QACjB,KAAK,GAAG;YACN,YAAY,GAAG,IAAI,CAAC;YACpB,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,MAAM;QACR,KAAK,SAAS,CAAC;QACf,KAAK,GAAG;YACN,SAAS,CAAC,CAAC,CAAC,CAAC;YACb,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,MAAM;QACR,KAAK,GAAG,CAAC;QACT,KAAK,GAAG;YACN,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;YACd,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,MAAM;QACR,KAAK,GAAG;YACN,YAAY;YACZ,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC5E,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBAChB,KAAK,IAAI,CAAC,CAAC;YACb,CAAC;YACD,IAAI,EAAE,CAAC;YACP,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;YAC7B,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,MAAM;IACV,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAgB,EAAE,EAAE;IACtD,IAAI,CAAC,CAAC,GAAG,KAAK,WAAW,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;QAC3C,YAAY,GAAG,KAAK,CAAC;IACvB,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,8EAA8E;AAE9E,SAAS,IAAI;IACX,KAAK,GAAG,WAAW,EAAE,CAAC;IACtB,KAAK,GAAG,CAAC,CAAC;IACV,KAAK,GAAG,CAAC,CAAC;IACV,KAAK,GAAG,CAAC,CAAC;IACV,QAAQ,GAAG,KAAK,CAAC;IACjB,MAAM,GAAG,KAAK,CAAC;IACf,YAAY,GAAG,IAAI,CAAC;IACpB,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAC7B,SAAS,GAAG,GAAG,CAAC;IAChB,SAAS,GAAG,CAAC,CAAC;IACd,YAAY,GAAG,KAAK,CAAC;IAErB,IAAI,GAAG,WAAW,EAAE,CAAC;IACrB,KAAK,EAAE,CAAC;IACR,SAAS,EAAE,CAAC;IAEZ,IAAI,WAAW;QAAE,oBAAoB,CAAC,WAAW,CAAC,CAAC;IACnD,WAAW,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;AAChD,CAAC;AAED,IAAI,EAAE,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,439 @@ +"use strict"; +// ─── Constants ──────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell on the main board +const PREVIEW_BLOCK = 24; // px per cell in the preview box +// Colours for each tetromino (index 0 = empty) +const COLORS = [ + "transparent", // 0 – empty + "#00CFCF", // 1 – I (cyan) + "#1E90FF", // 2 – J (blue) + "#FF8C00", // 3 – L (orange) + "#FFD700", // 4 – O (yellow) + "#32CD32", // 5 – S (green) + "#A020F0", // 6 – T (purple) + "#FF3030", // 7 – Z (red) +]; +function rotateCW(cells) { + // Rotate 90° clockwise: (r, c) → (c, -r) + return cells.map(([r, c]) => [c, -r]); +} +function normalise(cells) { + const minR = Math.min(...cells.map(([r]) => r)); + const minC = Math.min(...cells.map(([, c]) => c)); + return cells.map(([r, c]) => [r - minR, c - minC]); +} +function buildRotations(base) { + const rots = [normalise(base)]; + for (let i = 0; i < 3; i++) { + rots.push(normalise(rotateCW(rots[rots.length - 1]))); + } + return rots; +} +const PIECES = [ + // I + { rotations: buildRotations([[0, 0], [0, 1], [0, 2], [0, 3]]), colorIndex: 1 }, + // J + { rotations: buildRotations([[0, 0], [1, 0], [1, 1], [1, 2]]), colorIndex: 2 }, + // L + { rotations: buildRotations([[0, 2], [1, 0], [1, 1], [1, 2]]), colorIndex: 3 }, + // O + { rotations: buildRotations([[0, 0], [0, 1], [1, 0], [1, 1]]), colorIndex: 4 }, + // S + { rotations: buildRotations([[0, 1], [0, 2], [1, 0], [1, 1]]), colorIndex: 5 }, + // T + { rotations: buildRotations([[0, 1], [1, 0], [1, 1], [1, 2]]), colorIndex: 6 }, + // Z + { rotations: buildRotations([[0, 0], [0, 1], [1, 1], [1, 2]]), colorIndex: 7 }, +]; +// Scoring table (points per lines cleared simultaneously) +const SCORE_TABLE = [0, 100, 300, 500, 800]; +// Initial drop interval in ms +const BASE_INTERVAL = 800; +// Interval decrease per level (ms) +const LEVEL_SPEED = 60; +// Minimum interval +const MIN_INTERVAL = 80; +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(0)); +} +function randomPiece() { + const def = PIECES[Math.floor(Math.random() * PIECES.length)]; + const cells = def.rotations[0]; + const maxCol = Math.max(...cells.map(([, c]) => c)); + const col = Math.floor((COLS - maxCol - 1) / 2); + return { def, rotIdx: 0, row: 0, col }; +} +function pieceCells(p) { + return p.def.rotations[p.rotIdx].map(([r, c]) => [r + p.row, c + p.col]); +} +function collides(board, cells) { + for (const [r, c] of cells) { + if (r >= ROWS || c < 0 || c >= COLS) + return true; + if (r >= 0 && board[r][c] !== 0) + return true; + } + return false; +} +// ─── Renderer ───────────────────────────────────────────────────────────────── +class Renderer { + constructor(canvas, previewCanvas) { + this.canvas = canvas; + this.previewCanvas = previewCanvas; + this.ctx = canvas.getContext("2d"); + this.pCtx = previewCanvas.getContext("2d"); + } + drawBlock(ctx, r, c, color, size) { + const x = c * size; + const y = r * size; + const inset = 2; + ctx.fillStyle = color; + ctx.fillRect(x, y, size, size); + // Highlight top-left + ctx.fillStyle = "rgba(255,255,255,0.35)"; + ctx.fillRect(x + inset, y + inset, size - inset * 2, inset); + ctx.fillRect(x + inset, y + inset, inset, size - inset * 2); + // Shadow bottom-right + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x + inset, y + size - inset * 2, size - inset * 2, inset); + ctx.fillRect(x + size - inset * 2, y + inset, inset, size - inset * 2); + } + drawBoard(board) { + const { ctx } = this; + ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + // Grid background + ctx.fillStyle = "#111827"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Subtle grid lines + ctx.strokeStyle = "rgba(255,255,255,0.05)"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(COLS * BLOCK, r * BLOCK); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, ROWS * BLOCK); + ctx.stroke(); + } + // Locked blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c] !== 0) { + this.drawBlock(ctx, r, c, COLORS[board[r][c]], BLOCK); + } + } + } + } + drawGhost(board, piece) { + // Find lowest valid position + let ghostPiece = { ...piece }; + while (true) { + const next = { ...ghostPiece, row: ghostPiece.row + 1 }; + if (collides(board, pieceCells(next))) + break; + ghostPiece = next; + } + if (ghostPiece.row === piece.row) + return; + const { ctx } = this; + for (const [r, c] of pieceCells(ghostPiece)) { + if (r < 0) + continue; + const x = c * BLOCK; + const y = r * BLOCK; + ctx.strokeStyle = COLORS[piece.def.colorIndex]; + ctx.lineWidth = 2; + ctx.strokeRect(x + 1, y + 1, BLOCK - 2, BLOCK - 2); + } + } + drawPiece(piece) { + const { ctx } = this; + for (const [r, c] of pieceCells(piece)) { + if (r < 0) + continue; + this.drawBlock(ctx, r, c, COLORS[piece.def.colorIndex], BLOCK); + } + } + drawPreview(next) { + const { pCtx, previewCanvas } = this; + const size = PREVIEW_BLOCK; + pCtx.clearRect(0, 0, previewCanvas.width, previewCanvas.height); + pCtx.fillStyle = "#111827"; + pCtx.fillRect(0, 0, previewCanvas.width, previewCanvas.height); + const cells = next.def.rotations[0]; + const maxR = Math.max(...cells.map(([r]) => r)); + const maxC = Math.max(...cells.map(([, c]) => c)); + const offR = Math.floor((previewCanvas.height / size - maxR - 1) / 2); + const offC = Math.floor((previewCanvas.width / size - maxC - 1) / 2); + for (const [r, c] of cells) { + this.drawBlock(pCtx, r + offR, c + offC, COLORS[next.def.colorIndex], size); + } + } +} +class TetrisGame { + constructor() { + this.board = createBoard(); + this.current = randomPiece(); + this.next = randomPiece(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.state = "idle"; + this.lastDrop = 0; + this.animId = 0; + const canvas = document.getElementById("board"); + const preview = document.getElementById("preview"); + this.renderer = new Renderer(canvas, preview); + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.overlayEl = document.getElementById("overlay"); + this.overlayTitleEl = document.getElementById("overlay-title"); + this.overlayMsgEl = document.getElementById("overlay-msg"); + this.startBtn = document.getElementById("start-btn"); + this.startBtn.addEventListener("click", () => this.startOrRestart()); + document.addEventListener("keydown", (e) => this.handleKey(e)); + this.showOverlay("TETRIS", "Press Start or Enter to play"); + } + get dropInterval() { + return Math.max(MIN_INTERVAL, BASE_INTERVAL - (this.level - 1) * LEVEL_SPEED); + } + showOverlay(title, msg) { + this.overlayTitleEl.textContent = title; + this.overlayMsgEl.textContent = msg; + this.overlayEl.style.display = "flex"; + } + hideOverlay() { + this.overlayEl.style.display = "none"; + } + startOrRestart() { + if (this.state === "gameover" || this.state === "idle") { + this.board = createBoard(); + this.current = randomPiece(); + this.next = randomPiece(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.updateUI(); + } + if (this.state === "paused") { + this.resume(); + return; + } + this.state = "playing"; + this.hideOverlay(); + this.lastDrop = performance.now(); + cancelAnimationFrame(this.animId); + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + pause() { + if (this.state !== "playing") + return; + this.state = "paused"; + cancelAnimationFrame(this.animId); + this.showOverlay("PAUSED", "Press P or Start to resume"); + } + resume() { + if (this.state !== "paused") + return; + this.state = "playing"; + this.hideOverlay(); + this.lastDrop = performance.now(); + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + loop(timestamp) { + if (this.state !== "playing") + return; + if (timestamp - this.lastDrop >= this.dropInterval) { + this.lastDrop = timestamp; + this.drop(); + } + this.render(); + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + render() { + this.renderer.drawBoard(this.board); + this.renderer.drawGhost(this.board, this.current); + this.renderer.drawPiece(this.current); + this.renderer.drawPreview(this.next); + } + drop() { + const moved = { ...this.current, row: this.current.row + 1 }; + if (collides(this.board, pieceCells(moved))) { + this.lock(); + } + else { + this.current = moved; + } + } + lock() { + for (const [r, c] of pieceCells(this.current)) { + if (r < 0) { + this.gameOver(); + return; + } + this.board[r][c] = this.current.def.colorIndex; + } + this.clearLines(); + this.current = this.next; + this.next = randomPiece(); + this.renderer.drawPreview(this.next); + // Check if new piece immediately collides → game over + if (collides(this.board, pieceCells(this.current))) { + this.gameOver(); + } + } + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every((v) => v !== 0)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(0)); + cleared++; + r++; // re-check same row index + } + } + if (cleared > 0) { + this.score += SCORE_TABLE[cleared] * this.level; + this.lines += cleared; + this.level = Math.floor(this.lines / 10) + 1; + this.updateUI(); + } + } + gameOver() { + this.state = "gameover"; + cancelAnimationFrame(this.animId); + this.render(); + this.showOverlay("GAME OVER", `Score: ${this.score} — Press Start to play again`); + this.startBtn.textContent = "Restart"; + } + updateUI() { + this.scoreEl.textContent = String(this.score); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + } + moveLeft() { + const moved = { ...this.current, col: this.current.col - 1 }; + if (!collides(this.board, pieceCells(moved))) + this.current = moved; + } + moveRight() { + const moved = { ...this.current, col: this.current.col + 1 }; + if (!collides(this.board, pieceCells(moved))) + this.current = moved; + } + rotate() { + const nextRotIdx = (this.current.rotIdx + 1) % this.current.def.rotations.length; + const rotated = { ...this.current, rotIdx: nextRotIdx }; + // Wall-kick: try offsets 0, -1, +1, -2, +2 + const kicks = [0, -1, 1, -2, 2]; + for (const kick of kicks) { + const candidate = { ...rotated, col: rotated.col + kick }; + if (!collides(this.board, pieceCells(candidate))) { + this.current = candidate; + return; + } + } + } + rotateCCW() { + const len = this.current.def.rotations.length; + const nextRotIdx = (this.current.rotIdx + len - 1) % len; + const rotated = { ...this.current, rotIdx: nextRotIdx }; + const kicks = [0, -1, 1, -2, 2]; + for (const kick of kicks) { + const candidate = { ...rotated, col: rotated.col + kick }; + if (!collides(this.board, pieceCells(candidate))) { + this.current = candidate; + return; + } + } + } + hardDrop() { + while (true) { + const moved = { ...this.current, row: this.current.row + 1 }; + if (collides(this.board, pieceCells(moved))) + break; + this.current = moved; + this.score += 2; + } + this.updateUI(); + this.lock(); + } + softDrop() { + const moved = { ...this.current, row: this.current.row + 1 }; + if (!collides(this.board, pieceCells(moved))) { + this.current = moved; + this.score += 1; + this.updateUI(); + this.lastDrop = performance.now(); // reset auto-drop timer + } + } + handleKey(e) { + if (e.key === "Enter") { + if (this.state === "idle" || this.state === "gameover") { + this.startOrRestart(); + return; + } + } + if (e.key === "p" || e.key === "P") { + if (this.state === "playing") { + this.pause(); + return; + } + if (this.state === "paused") { + this.resume(); + return; + } + } + if (this.state !== "playing") + return; + switch (e.key) { + case "ArrowLeft": + case "a": + case "A": + e.preventDefault(); + this.moveLeft(); + break; + case "ArrowRight": + case "d": + case "D": + e.preventDefault(); + this.moveRight(); + break; + case "ArrowDown": + case "s": + case "S": + e.preventDefault(); + this.softDrop(); + break; + case "ArrowUp": + case "w": + case "W": + case "x": + case "X": + e.preventDefault(); + this.rotate(); + break; + case "z": + case "Z": + e.preventDefault(); + this.rotateCCW(); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + } + this.render(); + } +} +// ─── Bootstrap ──────────────────────────────────────────────────────────────── +window.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,679 @@ +"use strict"; +// ============================================================= +// TETRIS – Full browser implementation in TypeScript +// ============================================================= +// ── Constants ────────────────────────────────────────────── +const BOARD_W = 10; +const BOARD_H = 20; +const CELL = 30; // px per cell on main board +const PREVIEW_W = 120; // px wide of hold / next canvas +const PREVIEW_H = 120; +// ── Colours ──────────────────────────────────────────────── +const COLORS = { + I: '#00f0f0', + O: '#f0f000', + T: '#a020f0', + S: '#00e000', + Z: '#f00000', + J: '#2040f0', + L: '#f0a000', +}; +// Slightly darker shade used for 3-D inner shadow +const DARK = { + I: '#009090', + O: '#909000', + T: '#601890', + S: '#008000', + Z: '#900000', + J: '#102080', + L: '#905800', +}; +// ── Shapes (4 rotations each) ────────────────────────────── +// 1 = filled, 0 = empty +const SHAPES = { + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + O: [ + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]], + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]], + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]], + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]], + ], + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +// ── SRS Wall-kick tables ─────────────────────────────────── +// Offsets are [dx, dy] in canvas coords (positive-Y = DOWN) +// Derived from the Tetris Guideline with Y axis flipped. +const KICKS_JLSTZ = { + '0>1': [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + '1>0': [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + '1>2': [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + '2>1': [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + '2>3': [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + '3>2': [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + '3>0': [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + '0>3': [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], +}; +const KICKS_I = { + '0>1': [[0, 0], [-2, 0], [1, 0], [-2, 1], [1, -2]], + '1>0': [[0, 0], [2, 0], [-1, 0], [2, -1], [-1, 2]], + '1>2': [[0, 0], [-1, 0], [2, 0], [-1, -2], [2, 1]], + '2>1': [[0, 0], [1, 0], [-2, 0], [1, 2], [-2, -1]], + '2>3': [[0, 0], [2, 0], [-1, 0], [2, -1], [-1, 2]], + '3>2': [[0, 0], [-2, 0], [1, 0], [-2, 1], [1, -2]], + '3>0': [[0, 0], [1, 0], [-2, 0], [1, 2], [-2, -1]], + '0>3': [[0, 0], [-1, 0], [2, 0], [-1, -2], [2, 1]], +}; +// ── Scoring ──────────────────────────────────────────────── +const LINE_SCORE = [0, 100, 300, 500, 800]; // 0–4 lines +/** Drop interval in ms for a given level (Tetris guideline formula). */ +function dropInterval(level) { + const sec = Math.pow(0.8 - (level - 1) * 0.007, level - 1); + return Math.max(50, Math.floor(sec * 1000)); +} +// ── Helpers ──────────────────────────────────────────────── +const ALL_TYPES = ['I', 'O', 'T', 'S', 'Z', 'J', 'L']; +function getShape(type, rotation) { + return SHAPES[type][((rotation % 4) + 4) % 4]; +} +/** Returns [boardX, boardY] for every filled cell of the piece. */ +function cells(p) { + const out = []; + const shape = getShape(p.type, p.rotation); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) + out.push([p.x + c, p.y + r]); + } + } + return out; +} +// ── 7-bag randomiser ─────────────────────────────────────── +class Bag { + constructor() { + this.pool = []; + } + refill() { + this.pool = [...ALL_TYPES]; + for (let i = this.pool.length - 1; i > 0; i--) { + const j = (Math.random() * (i + 1)) | 0; + [this.pool[i], this.pool[j]] = [this.pool[j], this.pool[i]]; + } + } + next() { + if (!this.pool.length) + this.refill(); + return this.pool.pop(); + } + peek() { + if (!this.pool.length) + this.refill(); + return this.pool[this.pool.length - 1]; + } +} +// ══════════════════════════════════════════════════════════ +// Main Game Class +// ══════════════════════════════════════════════════════════ +class TetrisGame { + // ── Constructor ────────────────────────────────────────── + constructor() { + // Board + this.board = this.emptyBoard(); + // Pieces + this.current = null; + this.nextType = 'I'; + this.heldType = null; + this.canHold = true; + this.bag = new Bag(); + // Stats + this.score = 0; + this.level = 1; + this.lines = 0; + // Game loop + this.state = 'idle'; + this.animId = 0; + this.lastTime = 0; + this.dropCtr = 0; // accumulated ms toward next gravity drop + this.softDrop = false; + // DAS (Delayed Auto-Shift) + this.dasDir = 0; // -1 | 0 | 1 + this.dasTimer = 0; + this.dasRepeat = 0; + this.DAS_DELAY = 133; + this.DAS_PERIOD = 50; + // Key state + this.held = new Set(); + // ── Input ──────────────────────────────────────────────── + this.GAME_KEYS = new Set([ + 'ArrowLeft', 'ArrowRight', 'ArrowDown', 'ArrowUp', + 'Space', 'KeyZ', 'KeyX', 'KeyC', 'KeyP', 'Escape', + ]); + this.ctx = this.getCtx('game-canvas'); + this.nextCtx = this.getCtx('next-canvas'); + this.holdCtx = this.getCtx('hold-canvas'); + this.nextType = this.bag.next(); + document.addEventListener('keydown', e => this.onKeyDown(e)); + document.addEventListener('keyup', e => this.onKeyUp(e)); + document.getElementById('start-btn') + .addEventListener('click', () => this.onStartBtn()); + this.showOverlay('TETRIS', 'Press Space to start'); + this.drawIdleBoard(); + this.drawPreview(this.nextCtx, null); + this.drawPreview(this.holdCtx, null); + } + getCtx(id) { + return document.getElementById(id) + .getContext('2d'); + } + // ── Overlay helpers ────────────────────────────────────── + showOverlay(title, msg) { + document.getElementById('overlay').style.display = 'flex'; + document.getElementById('ov-title').textContent = title; + // handle literal \n line breaks in msg + const msgEl = document.getElementById('ov-msg'); + msgEl.innerHTML = msg.split('\n').map(l => `<span>${l}</span>`).join('<br>'); + } + hideOverlay() { + document.getElementById('overlay').style.display = 'none'; + } + setBtn(txt) { + document.getElementById('start-btn').textContent = txt; + } + updateStats() { + document.getElementById('score').textContent = this.score.toLocaleString(); + document.getElementById('level').textContent = String(this.level); + document.getElementById('lines').textContent = String(this.lines); + } + // ── Button / start flow ────────────────────────────────── + onStartBtn() { + if (this.state === 'idle' || this.state === 'gameover') + this.startGame(); + else if (this.state === 'playing') + this.pauseGame(); + else if (this.state === 'paused') + this.resumeGame(); + } + startGame() { + this.board = this.emptyBoard(); + this.score = 0; + this.level = 1; + this.lines = 0; + this.heldType = null; + this.canHold = true; + this.bag = new Bag(); + this.nextType = this.bag.next(); + this.dropCtr = 0; + this.softDrop = false; + this.dasDir = 0; + this.updateStats(); + this.drawPreview(this.holdCtx, null); + this.spawnPiece(); + if (this.state === 'playing') + cancelAnimationFrame(this.animId); + this.state = 'playing'; + this.hideOverlay(); + this.setBtn('PAUSE'); + this.lastTime = performance.now(); + this.animId = requestAnimationFrame(t => this.loop(t)); + } + pauseGame() { + this.state = 'paused'; + cancelAnimationFrame(this.animId); + this.showOverlay('PAUSED', 'Press P or Space to resume'); + this.setBtn('RESUME'); + } + resumeGame() { + this.state = 'playing'; + this.hideOverlay(); + this.setBtn('PAUSE'); + this.lastTime = performance.now(); + this.animId = requestAnimationFrame(t => this.loop(t)); + } + endGame() { + this.state = 'gameover'; + cancelAnimationFrame(this.animId); + this.showOverlay('GAME OVER', `Score: ${this.score.toLocaleString()}\nLines: ${this.lines} Level: ${this.level}\nPress Space to play again`); + this.setBtn('RESTART'); + } + // ── Board helpers ──────────────────────────────────────── + emptyBoard() { + return Array.from({ length: BOARD_H }, () => new Array(BOARD_W).fill(null)); + } + isValid(p) { + for (const [x, y] of cells(p)) { + if (x < 0 || x >= BOARD_W || y >= BOARD_H) + return false; + if (y >= 0 && this.board[y][x] !== null) + return false; + } + return true; + } + lock() { + if (!this.current) + return; + const color = COLORS[this.current.type]; + for (const [x, y] of cells(this.current)) { + if (y >= 0) + this.board[y][x] = color; + } + this.clearLines(); + this.canHold = true; + this.spawnPiece(); + } + clearLines() { + let cleared = 0; + for (let r = BOARD_H - 1; r >= 0; r--) { + if (this.board[r].every(c => c !== null)) { + this.board.splice(r, 1); + this.board.unshift(new Array(BOARD_W).fill(null)); + cleared++; + r++; // recheck the row that slid into position r + } + } + if (cleared) { + this.lines += cleared; + this.score += LINE_SCORE[cleared] * this.level; + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel > this.level) { + this.level = newLevel; + } + this.updateStats(); + } + } + // ── Spawn ──────────────────────────────────────────────── + spawnPiece() { + const type = this.nextType; + this.nextType = this.bag.next(); + const shape = getShape(type, 0); + const w = shape[0].length; + const spawnX = Math.floor((BOARD_W - w) / 2); + // I piece rotation-0 has an empty top row → spawn 1 row higher + const spawnY = type === 'I' ? -1 : 0; + this.current = { type, x: spawnX, y: spawnY, rotation: 0 }; + if (!this.isValid(this.current)) { + this.current.y--; + if (!this.isValid(this.current)) { + this.current = null; + this.endGame(); + return; + } + } + this.dropCtr = 0; + this.drawPreview(this.nextCtx, this.nextType); + } + // ── Movement ───────────────────────────────────────────── + tryShift(dx, dy) { + if (!this.current) + return false; + const moved = { ...this.current, x: this.current.x + dx, y: this.current.y + dy }; + if (this.isValid(moved)) { + this.current = moved; + return true; + } + return false; + } + /** Gravity tick – returns false if piece locked. */ + gravityDrop() { + if (!this.current) + return false; + if (!this.tryShift(0, 1)) { + this.lock(); + return false; + } + return true; + } + hardDrop() { + if (!this.current) + return; + let rows = 0; + while (this.tryShift(0, 1)) + rows++; + this.score += rows * 2; + this.updateStats(); + this.lock(); + } + rotate(dir) { + if (!this.current) + return; + const from = this.current.rotation; + const to = ((from + dir + 4) % 4); + const key = `${from}>${to}`; + const kicks = this.current.type === 'I' ? KICKS_I[key] : + this.current.type === 'O' ? [[0, 0]] : + KICKS_JLSTZ[key]; + for (const [dx, dy] of kicks) { + const attempt = { ...this.current, rotation: to, + x: this.current.x + dx, + y: this.current.y + dy }; + if (this.isValid(attempt)) { + this.current = attempt; + return; + } + } + } + holdPiece() { + if (!this.current || !this.canHold) + return; + const type = this.current.type; + if (this.heldType === null) { + this.heldType = type; + this.spawnPiece(); + } + else { + const swap = this.heldType; + this.heldType = type; + const shape = getShape(swap, 0); + const w = shape[0].length; + this.current = { type: swap, + x: Math.floor((BOARD_W - w) / 2), + y: swap === 'I' ? -1 : 0, + rotation: 0 }; + this.dropCtr = 0; + } + this.canHold = false; + this.drawPreview(this.holdCtx, this.heldType); + } + // Ghost: lowest valid position of current piece + ghost() { + if (!this.current) + return null; + let g = { ...this.current }; + while (true) { + const down = { ...g, y: g.y + 1 }; + if (this.isValid(down)) + g = down; + else + break; + } + return g; + } + onKeyDown(e) { + if (this.GAME_KEYS.has(e.code)) + e.preventDefault(); + if (this.held.has(e.code)) + return; // ignore key-repeat from OS + this.held.add(e.code); + if (e.code === 'KeyP' || e.code === 'Escape') { + if (this.state === 'playing') + this.pauseGame(); + else if (this.state === 'paused') + this.resumeGame(); + return; + } + if (e.code === 'Space') { + if (this.state === 'idle' || this.state === 'gameover') + this.startGame(); + else if (this.state === 'paused') + this.resumeGame(); + else if (this.state === 'playing') + this.hardDrop(); + return; + } + if (this.state !== 'playing') + return; + switch (e.code) { + case 'ArrowLeft': + this.tryShift(-1, 0); + this.startDAS(-1); + break; + case 'ArrowRight': + this.tryShift(1, 0); + this.startDAS(1); + break; + case 'ArrowDown': + this.softDrop = true; + break; + case 'ArrowUp': + case 'KeyX': + this.rotate(1); + break; + case 'KeyZ': + this.rotate(-1); + break; + case 'KeyC': + this.holdPiece(); + break; + } + } + onKeyUp(e) { + this.held.delete(e.code); + if (e.code === 'ArrowLeft' && this.dasDir === -1) + this.stopDAS(); + if (e.code === 'ArrowRight' && this.dasDir === 1) + this.stopDAS(); + if (e.code === 'ArrowDown') + this.softDrop = false; + } + startDAS(dir) { + this.dasDir = dir; + this.dasTimer = 0; + this.dasRepeat = 0; + } + stopDAS() { + // Re-engage for the other direction if still held + if (this.held.has('ArrowLeft') && this.dasDir !== -1) + this.startDAS(-1); + else if (this.held.has('ArrowRight') && this.dasDir !== 1) + this.startDAS(1); + else { + this.dasDir = 0; + this.dasTimer = 0; + this.dasRepeat = 0; + } + } + // ── Game loop ──────────────────────────────────────────── + loop(ts) { + const dt = Math.min(ts - this.lastTime, 100); // cap to avoid spiral after tab-switch + this.lastTime = ts; + // DAS + if (this.dasDir !== 0) { + this.dasTimer += dt; + if (this.dasTimer >= this.DAS_DELAY) { + this.dasRepeat += dt; + while (this.dasRepeat >= this.DAS_PERIOD) { + this.dasRepeat -= this.DAS_PERIOD; + this.tryShift(this.dasDir, 0); + } + } + } + // Gravity + const interval = this.softDrop + ? Math.max(dropInterval(this.level) / 20, 33) + : dropInterval(this.level); + this.dropCtr += dt; + while (this.dropCtr >= interval && this.state === 'playing') { + this.dropCtr -= interval; + if (this.softDrop && this.current) { + this.score += 1; + document.getElementById('score').textContent = this.score.toLocaleString(); + } + if (!this.gravityDrop()) + break; // piece locked → new piece spawned + } + this.draw(); + if (this.state === 'playing') + this.animId = requestAnimationFrame(t => this.loop(t)); + } + // ── Rendering ──────────────────────────────────────────── + /** Draw one cell at grid coords (gx, gy) using given pixel size. */ + drawCell(ctx, gx, gy, type, size, alpha = 1) { + const px = gx * size; + const py = gy * size; + const s = size; + const b = Math.max(2, (s / 10) | 0); // border/bevel thickness + ctx.globalAlpha = alpha; + // Fill + ctx.fillStyle = COLORS[type]; + ctx.fillRect(px, py, s, s); + // Inner bevel – bright top/left + ctx.fillStyle = 'rgba(255,255,255,0.45)'; + ctx.fillRect(px, py, s, b); // top strip + ctx.fillRect(px, py, b, s); // left strip + // Inner bevel – dark bottom/right + ctx.fillStyle = DARK[type]; + ctx.fillRect(px, py + s - b, s, b); // bottom + ctx.fillRect(px + s - b, py, b, s); // right + // Inset highlight square + ctx.fillStyle = COLORS[type]; + ctx.fillRect(px + b, py + b, s - b * 2, s - b * 2); + // Subtle inner shine + ctx.fillStyle = 'rgba(255,255,255,0.18)'; + ctx.fillRect(px + b, py + b, s - b * 2, Math.max(1, (s - b * 2) / 2 | 0)); + ctx.globalAlpha = 1; + } + /** Main board render. */ + draw() { + const ctx = this.ctx; + const W = BOARD_W * CELL; + const H = BOARD_H * CELL; + // ── Background ── + ctx.fillStyle = '#111122'; + ctx.fillRect(0, 0, W, H); + // ── Grid lines ── + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let c = 0; c <= BOARD_W; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, H); + ctx.stroke(); + } + for (let r = 0; r <= BOARD_H; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(W, r * CELL); + ctx.stroke(); + } + // ── Locked cells ── + for (let r = 0; r < BOARD_H; r++) { + for (let c = 0; c < BOARD_W; c++) { + const color = this.board[r][c]; + if (color) { + // find which type this color belongs to + const type = Object.keys(COLORS) + .find(k => COLORS[k] === color) ?? 'I'; + this.drawCell(ctx, c, r, type, CELL); + } + } + } + // ── Ghost piece ── + const gh = this.ghost(); + if (gh && this.current && gh.y !== this.current.y) { + for (const [x, y] of cells(gh)) { + if (y >= 0) + this.drawCell(ctx, x, y, gh.type, CELL, 0.18); + } + } + // ── Current piece ── + if (this.current) { + for (const [x, y] of cells(this.current)) { + if (y >= 0) + this.drawCell(ctx, x, y, this.current.type, CELL); + } + } + } + /** Draw a piece centred inside the given small canvas context. */ + drawPreview(ctx, type) { + ctx.fillStyle = '#111122'; + ctx.fillRect(0, 0, PREVIEW_W, PREVIEW_H); + if (!type) + return; + const shape = getShape(type, 0); + const rows = shape.length; + const cols = shape[0].length; + // Compute the tightest bounding box of filled cells + let minR = rows, maxR = 0, minC = cols, maxC = 0; + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (shape[r][c]) { + if (r < minR) + minR = r; + if (r > maxR) + maxR = r; + if (c < minC) + minC = c; + if (c > maxC) + maxC = c; + } + } + } + const bRows = maxR - minR + 1; + const bCols = maxC - minC + 1; + const cellSz = Math.min(Math.floor((PREVIEW_W - 16) / bCols), Math.floor((PREVIEW_H - 16) / bRows), 28); + const offX = Math.floor((PREVIEW_W - bCols * cellSz) / 2) - minC * cellSz; + const offY = Math.floor((PREVIEW_H - bRows * cellSz) / 2) - minR * cellSz; + ctx.save(); + ctx.translate(offX, offY); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (shape[r][c]) + this.drawCell(ctx, c, r, type, cellSz); + } + } + ctx.restore(); + } + /** Idle screen: a partially-filled board with random blocks. */ + drawIdleBoard() { + const ctx = this.ctx; + ctx.fillStyle = '#111122'; + ctx.fillRect(0, 0, BOARD_W * CELL, BOARD_H * CELL); + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let c = 0; c <= BOARD_W; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, BOARD_H * CELL); + ctx.stroke(); + } + for (let r = 0; r <= BOARD_H; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(BOARD_W * CELL, r * CELL); + ctx.stroke(); + } + for (let r = 14; r < BOARD_H; r++) { + for (let c = 0; c < BOARD_W; c++) { + if (Math.random() > 0.35) { + const t = ALL_TYPES[(Math.random() * ALL_TYPES.length) | 0]; + this.drawCell(ctx, c, r, t, CELL); + } + } + } + } +} +// ── Bootstrap ───────────────────────────────────────────── +window.addEventListener('DOMContentLoaded', () => { new TetrisGame(); }); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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AAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;CACF,CAAC;AAEF,8DAA8D;AAC9D,6DAA6D;AAC7D,0DAA0D;AAE1D,MAAM,WAAW,GAAgD;IAC/D,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,OAAO,GAAgD;IAC3D,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,CAAC;CAChD,CAAC;AAEF,8DAA8D;AAC9D,MAAM,UAAU,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAE,YAAY;AAEzD,wEAAwE;AACxE,SAAS,YAAY,CAAC,KAAa;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;IAC3D,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,8DAA8D;AAC9D,MAAM,SAAS,GAAgB,CAAC,GAAG,EAAC,GAAG,EAAC,GAAG,EAAC,GAAG,EAAC,GAAG,EAAC,GAAG,EAAC,GAAG,CAAC,CAAC;AAE7D,SAAS,QAAQ,CAAC,IAAe,EAAE,QAAgB;IACjD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,mEAAmE;AACnE,SAAS,KAAK,CAAC,CAAQ;IACrB,MAAM,GAAG,GAAuB,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,8DAA8D;AAC9D,MAAM,GAAG;IAAT;QACU,SAAI,GAAgB,EAAE,CAAC;IAmBjC,CAAC;IAjBS,MAAM;QACZ,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC;QAC3B,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACxC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,IAAI;QACF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,IAAI,CAAC,MAAM,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAG,CAAC;IAC1B,CAAC;IAED,IAAI;QACF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,IAAI,CAAC,MAAM,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzC,CAAC;CACF;AAED,6DAA6D;AAC7D,mBAAmB;AACnB,6DAA6D;AAC7D,MAAM,UAAU;IAuCd,4DAA4D;IAC5D;QAjCA,QAAQ;QACA,UAAK,GAAU,IAAI,CAAC,UAAU,EAAE,CAAC;QAEzC,SAAS;QACD,YAAO,GAAkB,IAAI,CAAC;QAC9B,aAAQ,GAAiB,GAAG,CAAC;QAC7B,aAAQ,GAAqB,IAAI,CAAC;QAClC,YAAO,GAAK,IAAI,CAAC;QACjB,QAAG,GAAS,IAAI,GAAG,EAAE,CAAC;QAE9B,QAAQ;QACA,UAAK,GAAG,CAAC,CAAC;QACV,UAAK,GAAG,CAAC,CAAC;QACV,UAAK,GAAG,CAAC,CAAC;QAElB,YAAY;QACJ,UAAK,GAAoB,MAAM,CAAC;QAChC,WAAM,GAAmB,CAAC,CAAC;QAC3B,aAAQ,GAAO,CAAC,CAAC;QACjB,YAAO,GAAQ,CAAC,CAAC,CAAG,0CAA0C;QAC9D,aAAQ,GAAO,KAAK,CAAC;QAE7B,2BAA2B;QACnB,WAAM,GAAO,CAAC,CAAC,CAAG,aAAa;QAC/B,aAAQ,GAAK,CAAC,CAAC;QACf,cAAS,GAAI,CAAC,CAAC;QACN,cAAS,GAAI,GAAG,CAAC;QACjB,eAAU,GAAG,EAAE,CAAC;QAEjC,YAAY;QACJ,SAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAgQjC,4DAA4D;QAC3C,cAAS,GAAG,IAAI,GAAG,CAAC;YACnC,WAAW,EAAC,YAAY,EAAC,WAAW,EAAC,SAAS;YAC9C,OAAO,EAAC,MAAM,EAAC,MAAM,EAAC,MAAM,EAAC,MAAM,EAAC,QAAQ;SAC7C,CAAC,CAAC;QAhQD,IAAI,CAAC,GAAG,GAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAC1C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAC1C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAE1C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QAEhC,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7D,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAE;aAClC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;QAEtD,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC;QACnD,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACvC,CAAC;IAEO,MAAM,CAAC,EAAU;QACvB,OAAQ,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAuB;aACtD,UAAU,CAAC,IAAI,CAAE,CAAC;IACvB,CAAC;IAED,4DAA4D;IACpD,WAAW,CAAC,KAAa,EAAE,GAAW;QAC5C,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAE,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QAC3D,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAE,CAAC,WAAW,GAAI,KAAK,CAAC;QAC1D,uCAAuC;QACvC,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAE,CAAC;QACjD,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/E,CAAC;IAEO,WAAW;QACjB,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAE,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;IAC7D,CAAC;IAEO,MAAM,CAAC,GAAW;QACvB,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAuB,CAAC,WAAW,GAAG,GAAG,CAAC;IAChF,CAAC;IAEO,WAAW;QACjB,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;QAC5E,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnE,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrE,CAAC;IAED,4DAA4D;IACpD,UAAU;QAChB,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,KAAK,UAAU;YAAE,IAAI,CAAC,SAAS,EAAE,CAAC;aACpE,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAG,IAAI,CAAC,SAAS,EAAE,CAAC;aAChD,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ;YAAI,IAAI,CAAC,UAAU,EAAE,CAAC;IACxD,CAAC;IAED,SAAS;QACP,IAAI,CAAC,KAAK,GAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAClC,IAAI,CAAC,KAAK,GAAM,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,GAAM,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,GAAM,CAAC,CAAC;QAClB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,OAAO,GAAI,IAAI,CAAC;QACrB,IAAI,CAAC,GAAG,GAAQ,IAAI,GAAG,EAAE,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,CAAC,OAAO,GAAI,CAAC,CAAC;QAClB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,MAAM,GAAK,CAAC,CAAC;QAElB,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,UAAU,EAAE,CAAC;QAElB,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChE,IAAI,CAAC,KAAK,GAAM,SAAS,CAAC;QAC1B,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAErB,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAClC,IAAI,CAAC,MAAM,GAAK,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,SAAS;QACP,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;QACtB,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,4BAA4B,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACxB,CAAC;IAED,UAAU;QACR,IAAI,CAAC,KAAK,GAAM,SAAS,CAAC;QAC1B,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAClC,IAAI,CAAC,MAAM,GAAK,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC;IAEO,OAAO;QACb,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC;QACxB,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,CAAC,WAAW,CACd,WAAW,EACX,UAAU,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,YAAY,IAAI,CAAC,KAAK,YAAY,IAAI,CAAC,KAAK,6BAA6B,CAC/G,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACzB,CAAC;IAED,4DAA4D;IACpD,UAAU;QAChB,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,KAAK,CAAO,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACpF,CAAC;IAEO,OAAO,CAAC,CAAQ;QACtB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,IAAI,OAAO;gBAAE,OAAO,KAAK,CAAC;YACxD,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI;gBAAK,OAAO,KAAK,CAAC;QAC3D,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,IAAI;QACV,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC,IAAI,CAAC;gBAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;QACvC,CAAC;QACD,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAEO,UAAU;QAChB,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,IAAI,CAAC,GAAG,OAAO,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;gBACzC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACxB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,CAAO,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBACxD,OAAO,EAAE,CAAC;gBACV,CAAC,EAAE,CAAC,CAAC,4CAA4C;YACnD,CAAC;QACH,CAAC;QACD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC;YACtB,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;YAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;YACjD,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC1B,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;YACxB,CAAC;YACD,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED,4DAA4D;IACpD,UAAU;QAChB,MAAM,IAAI,GAAK,IAAI,CAAC,QAAQ,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QAEhC,MAAM,KAAK,GAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,GAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7C,+DAA+D;QAC/D,MAAM,MAAM,GAAG,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAErC,IAAI,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QAE3D,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAChC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YACjB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAChC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;gBACpB,IAAI,CAAC,OAAO,EAAE,CAAC;gBACf,OAAO;YACT,CAAC;QACH,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChD,CAAC;IAED,4DAA4D;IACpD,QAAQ,CAAC,EAAU,EAAE,EAAU;QACrC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAChC,MAAM,KAAK,GAAU,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC;QACzF,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAAC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YAAC,OAAO,IAAI,CAAC;QAAC,CAAC;QAC/D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,oDAAoD;IAC5C,WAAW;QACjB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,EAAE,CAAC;YACZ,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,QAAQ;QACd,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;YAAE,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAEO,MAAM,CAAC,GAAW;QACxB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;QACnC,MAAM,EAAE,GAAK,CAAC,CAAC,IAAI,GAAG,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAY,CAAC;QAC/C,MAAM,GAAG,GAAI,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC;QAE7B,MAAM,KAAK,GACT,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1C,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAO,CAAC;gBAC3C,WAAW,CAAC,GAAG,CAAC,CAAC;QAEnB,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAU,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE;gBAC7B,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE;gBACtB,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC;YAClD,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBAAC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;gBAAC,OAAO;YAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAEO,SAAS;QACf,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;QAC/B,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YAC3B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,GAAQ,IAAI,CAAC,QAAQ,CAAC;YAChC,IAAI,CAAC,QAAQ,GAAK,IAAI,CAAC;YACvB,MAAM,KAAK,GAAO,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACpC,MAAM,CAAC,GAAW,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YAClC,IAAI,CAAC,OAAO,GAAM,EAAE,IAAI,EAAE,IAAI;gBACV,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;gBAChC,CAAC,EAAE,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACxB,QAAQ,EAAE,CAAC,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,GAAM,CAAC,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChD,CAAC;IAED,gDAAgD;IACxC,KAAK;QACX,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC/B,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;YAClC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;gBAAE,CAAC,GAAG,IAAI,CAAC;;gBAAM,MAAM;QAC/C,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAQO,SAAS,CAAC,CAAgB;QAChC,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,CAAC,CAAC,cAAc,EAAE,CAAC;QACnD,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,OAAO,CAAG,4BAA4B;QACjE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAEtB,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7C,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;gBAAG,IAAI,CAAC,SAAS,EAAE,CAAC;iBAC3C,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ;gBAAE,IAAI,CAAC,UAAU,EAAE,CAAC;YACpD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACvB,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,KAAK,UAAU;gBAAE,IAAI,CAAC,SAAS,EAAE,CAAC;iBACpE,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ;gBAAG,IAAI,CAAC,UAAU,EAAE,CAAC;iBAChD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;gBAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnD,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,OAAO;QAErC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;YACf,KAAK,WAAW;gBACd,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACrB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;gBAClB,MAAM;YACR,KAAK,YAAY;gBACf,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACpB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACjB,MAAM;YACR,KAAK,WAAW;gBACd,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACrB,MAAM;YACR,KAAK,SAAS,CAAC;YACf,KAAK,MAAM;gBACT,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBACf,MAAM;YACR,KAAK,MAAM;gBACT,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChB,MAAM;YACR,KAAK,MAAM;gBACT,IAAI,CAAC,SAAS,EAAE,CAAC;gBACjB,MAAM;QACV,CAAC;IACH,CAAC;IAEO,OAAO,CAAC,CAAgB;QAC9B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAK,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;YAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QAClE,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,MAAM,KAAM,CAAC;YAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QAClE,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW;YAAG,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;IACrD,CAAC;IAEO,QAAQ,CAAC,GAAW;QAC1B,IAAI,CAAC,MAAM,GAAM,GAAG,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAI,CAAC,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;IACrB,CAAC;IAEO,OAAO;QACb,kDAAkD;QAClD,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAK,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;YAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;aACpE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;aACvE,CAAC;YAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;YAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;YAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QAAC,CAAC;IAClE,CAAC;IAED,4DAA4D;IACpD,IAAI,CAAC,EAAU;QACrB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,uCAAuC;QACrF,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QAEnB,MAAM;QACN,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;YACpB,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACpC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;gBACrB,OAAO,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;oBACzC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,UAAU,CAAC;oBAClC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;QAED,UAAU;QACV,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ;YAC5B,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC;YAC7C,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE7B,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC,OAAO,IAAI,QAAQ,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC5D,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC;YACzB,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;gBAChB,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAE,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;YAC9E,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;gBAAE,MAAM,CAAC,mCAAmC;QACrE,CAAC;QAED,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACvF,CAAC;IAED,4DAA4D;IAE5D,oEAAoE;IAC5D,QAAQ,CACd,GAA6B,EAC7B,EAAU,EAAE,EAAU,EACtB,IAAe,EACf,IAAY,EACZ,KAAK,GAAG,CAAC;QAET,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QACrB,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QACrB,MAAM,CAAC,GAAI,IAAI,CAAC;QAChB,MAAM,CAAC,GAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,yBAAyB;QAE/D,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC;QAExB,OAAO;QACP,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7B,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAE3B,gCAAgC;QAChC,GAAG,CAAC,SAAS,GAAG,wBAAwB,CAAC;QACzC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAM,EAAE,EAAM,CAAC,EAAM,CAAC,CAAC,CAAC,CAAG,YAAY;QACtD,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAM,EAAE,EAAM,CAAC,EAAM,CAAC,CAAC,CAAC,CAAG,aAAa;QAEvD,kCAAkC;QAClC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAU,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAG,CAAC,CAAC,CAAC,CAAE,SAAS;QACvD,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,EAAU,CAAC,EAAG,CAAC,CAAC,CAAC,CAAE,QAAQ;QAEtD,yBAAyB;QACzB,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7B,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAEnD,qBAAqB;QACrB,GAAG,CAAC,SAAS,GAAG,wBAAwB,CAAC;QACzC,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAE1E,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC;IACtB,CAAC;IAED,yBAAyB;IACjB,IAAI;QACV,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACrB,MAAM,CAAC,GAAK,OAAO,GAAG,IAAI,CAAC;QAC3B,MAAM,CAAC,GAAK,OAAO,GAAG,IAAI,CAAC;QAE3B,mBAAmB;QACnB,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC1B,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAEzB,mBAAmB;QACnB,GAAG,CAAC,WAAW,GAAG,wBAAwB,CAAC;QAC3C,GAAG,CAAC,SAAS,GAAK,CAAC,CAAC;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,GAAG,CAAC,SAAS,EAAE,CAAC;YAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;YAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;YAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QAClF,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,GAAG,CAAC,SAAS,EAAE,CAAC;YAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;YAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;YAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QAClF,CAAC;QAED,qBAAqB;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;YACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;gBACjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC/B,IAAI,KAAK,EAAE,CAAC;oBACV,wCAAwC;oBACxC,MAAM,IAAI,GAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAiB;yBAC9C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,GAAG,CAAC;oBACzC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;gBACvC,CAAC;YACH,CAAC;QACH,CAAC;QAED,oBAAoB;QACpB,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QACxB,IAAI,EAAE,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YAClD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC/B,IAAI,CAAC,IAAI,CAAC;oBAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;QAED,sBAAsB;QACtB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzC,IAAI,CAAC,IAAI,CAAC;oBAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;IACH,CAAC;IAED,kEAAkE;IAC1D,WAAW,CAAC,GAA6B,EAAE,IAAsB;QACvE,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC1B,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAEzC,IAAI,CAAC,IAAI;YAAE,OAAO;QAElB,MAAM,KAAK,GAAK,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAClC,MAAM,IAAI,GAAM,KAAK,CAAC,MAAM,CAAC;QAC7B,MAAM,IAAI,GAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAEhC,oDAAoD;QACpD,IAAI,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC;QACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC9B,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBAChB,IAAI,CAAC,GAAG,IAAI;wBAAE,IAAI,GAAG,CAAC,CAAC;oBAAC,IAAI,CAAC,GAAG,IAAI;wBAAE,IAAI,GAAG,CAAC,CAAC;oBAC/C,IAAI,CAAC,GAAG,IAAI;wBAAE,IAAI,GAAG,CAAC,CAAC;oBAAC,IAAI,CAAC,GAAG,IAAI;wBAAE,IAAI,GAAG,CAAC,CAAC;gBACjD,CAAC;YACH,CAAC;QACH,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC;QAC9B,MAAM,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC;QAE9B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CACrB,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,EAAE,CAAC,GAAG,KAAK,CAAC,EACpC,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,EAAE,CAAC,GAAG,KAAK,CAAC,EACpC,EAAE,CACH,CAAC;QAEF,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,MAAM,CAAC;QAC1E,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,MAAM,CAAC;QAE1E,GAAG,CAAC,IAAI,EAAE,CAAC;QACX,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC9B,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;QACD,GAAG,CAAC,OAAO,EAAE,CAAC;IAChB,CAAC;IAED,gEAAgE;IACxD,aAAa;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACrB,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC1B,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,GAAG,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC;QAEnD,GAAG,CAAC,WAAW,GAAG,wBAAwB,CAAC;QAC3C,GAAG,CAAC,SAAS,GAAK,CAAC,CAAC;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,GAAG,CAAC,SAAS,EAAE,CAAC;YAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;YAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC;YAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QAC/F,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,GAAG,CAAC,SAAS,EAAE,CAAC;YAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;YAAC,GAAG,CAAC,MAAM,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;YAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QAC/F,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;gBACjC,IAAI,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC;oBACzB,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;oBAC5D,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAED,6DAA6D;AAC7D,MAAM,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE,GAAG,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=off_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js @@ -0,0 +1,599 @@ +"use strict"; +// ───────────────────────────────────────────────────────────────────────────── +// Constants +// ───────────────────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const CELL = 32; // board cell size in px +const PCELL = 28; // preview cell size in px +// Delayed Auto-Shift settings +const DAS_DELAY = 150; // ms before repeat starts +const ARR_RATE = 50; // ms between repeats while held +// Lines-per-level threshold +const LINES_PER_LEVEL = 10; +// Scoring table: index = number of lines cleared at once +const LINE_SCORES = [0, 100, 300, 500, 800]; +// Drop interval (ms) per level, clamped at index 13+ +const DROP_INTERVALS = [ + 800, 717, 633, 550, 467, 383, 300, 217, 133, 100, 83, 67, 50, 33, +]; +const PIECES = { + I: { + rotations: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + color: '#00f0f0', + }, + J: { + rotations: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + color: '#4040ff', + }, + L: { + rotations: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], + color: '#ff8800', + }, + O: { + rotations: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + color: '#f0f000', + }, + S: { + rotations: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + ], + color: '#00e000', + }, + T: { + rotations: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + color: '#c000f0', + }, + Z: { + rotations: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + color: '#f00030', + }, +}; +const PIECE_KEYS = Object.keys(PIECES); +// ───────────────────────────────────────────────────────────────────────────── +// 7-bag randomiser +// ───────────────────────────────────────────────────────────────────────────── +function newBag() { + const bag = [...PIECE_KEYS]; + for (let i = bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [bag[i], bag[j]] = [bag[j], bag[i]]; + } + return bag; +} +// ───────────────────────────────────────────────────────────────────────────── +// Helpers +// ───────────────────────────────────────────────────────────────────────────── +function getShape(p) { + return PIECES[p.key].rotations[p.rot]; +} +/** Returns [row, col] pairs for all filled cells of a piece. */ +function getCells(p) { + const shape = getShape(p); + const cells = []; + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c]) + cells.push([p.y + r, p.x + c]); + return cells; +} +function isValid(board, p) { + for (const [r, c] of getCells(p)) { + if (c < 0 || c >= COLS || r >= ROWS) + return false; + if (r >= 0 && board[r][c] !== null) + return false; + } + return true; +} +function spawnPiece(key) { + const width = PIECES[key].rotations[0][0].length; + return { key, rot: 0, x: Math.floor((COLS - width) / 2), y: 0 }; +} +function getGhost(board, p) { + let g = { ...p }; + while (isValid(board, { ...g, y: g.y + 1 })) + g = { ...g, y: g.y + 1 }; + return g; +} +/** + * Attempt to rotate by dir (+1 CW, -1 CCW). + * Falls back through a series of wall-kick offsets. + */ +function tryRotate(board, p, dir) { + const newRot = ((p.rot + dir) % 4 + 4) % 4; + const rotated = { ...p, rot: newRot }; + if (isValid(board, rotated)) + return rotated; + // Wall-kick table (dx, dy pairs to try) + const kicks = p.key === 'I' + ? [[0, -1], [0, -2], [0, 1], [0, 2], [1, 0], [-1, 0]] + : [[0, -1], [0, 1], [1, -1], [1, 1], [-1, 0], [0, -2]]; + for (const [dx, dy] of kicks) { + const kicked = { ...rotated, x: rotated.x + dx, y: rotated.y + dy }; + if (isValid(board, kicked)) + return kicked; + } + return null; +} +function lockPiece(board, p) { + const color = PIECES[p.key].color; + for (const [r, c] of getCells(p)) + if (r >= 0 && r < ROWS && c >= 0 && c < COLS) + board[r][c] = color; +} +/** Clears complete lines, returns count cleared. */ +function clearLines(board) { + let count = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every(cell => cell !== null)) { + board.splice(r, 1); + board.unshift(new Array(COLS).fill(null)); + count++; + r++; // recheck same index + } + } + return count; +} +function emptyBoard() { + return Array.from({ length: ROWS }, () => new Array(COLS).fill(null)); +} +// ───────────────────────────────────────────────────────────────────────────── +// Colour helpers +// ───────────────────────────────────────────────────────────────────────────── +function parseHex(hex) { + return [ + parseInt(hex.slice(1, 3), 16), + parseInt(hex.slice(3, 5), 16), + parseInt(hex.slice(5, 7), 16), + ]; +} +function toHex(r, g, b) { + const clamp = (v) => Math.min(255, Math.max(0, Math.round(v))); + return `#${clamp(r).toString(16).padStart(2, '0')}${clamp(g).toString(16).padStart(2, '0')}${clamp(b).toString(16).padStart(2, '0')}`; +} +function lighten(hex, t) { + const [r, g, b] = parseHex(hex); + return toHex(r + (255 - r) * t, g + (255 - g) * t, b + (255 - b) * t); +} +function darken(hex, t) { + const [r, g, b] = parseHex(hex); + return toHex(r * (1 - t), g * (1 - t), b * (1 - t)); +} +// ───────────────────────────────────────────────────────────────────────────── +// Rendering helpers +// ───────────────────────────────────────────────────────────────────────────── +/** Draw a single cell with a 3-D bevel effect. */ +function drawCell(ctx, col, row, color, cellSize, alpha = 1) { + const px = col * cellSize; + const py = row * cellSize; + const pad = 1; + const bevel = Math.max(2, Math.round(cellSize * 0.09)); + ctx.save(); + ctx.globalAlpha = alpha; + // Main fill + ctx.fillStyle = color; + ctx.fillRect(px + pad, py + pad, cellSize - pad * 2, cellSize - pad * 2); + // Top / left highlight + ctx.fillStyle = lighten(color, 0.55); + ctx.fillRect(px + pad, py + pad, cellSize - pad * 2, bevel); + ctx.fillRect(px + pad, py + pad, bevel, cellSize - pad * 2); + // Bottom / right shadow + ctx.fillStyle = darken(color, 0.40); + ctx.fillRect(px + pad, py + cellSize - pad - bevel, cellSize - pad * 2, bevel); + ctx.fillRect(px + cellSize - pad - bevel, py + pad, bevel, cellSize - pad * 2); + ctx.restore(); +} +/** Draw a ghost-piece cell (outline only). */ +function drawGhostCell(ctx, col, row, color, cellSize) { + const px = col * cellSize + 1; + const py = row * cellSize + 1; + const sz = cellSize - 2; + ctx.save(); + ctx.strokeStyle = lighten(color, 0.1); + ctx.lineWidth = 2; + ctx.globalAlpha = 0.45; + ctx.strokeRect(px + 1, py + 1, sz - 2, sz - 2); + ctx.restore(); +} +function drawPieceOnCanvas(ctx, key, rot, cellSize) { + const shape = PIECES[key].rotations[rot]; + const color = PIECES[key].color; + const width = ctx.canvas.width / cellSize; + const height = ctx.canvas.height / cellSize; + // Centre the shape + const offsetC = Math.floor((width - shape[0].length) / 2); + const offsetR = Math.floor((height - shape.length) / 2); + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c]) + drawCell(ctx, offsetC + c, offsetR + r, color, cellSize); +} +// ───────────────────────────────────────────────────────────────────────────── +// Game class +// ───────────────────────────────────────────────────────────────────────────── +class TetrisGame { + // ── Constructor ──────────────────────────────────────────────────────────── + constructor() { + // ── Board state ──────────────────────────────────────────────────────────── + this.board = emptyBoard(); + this.bag = []; + this.nextPieces = []; // show next 3 + this.held = null; + this.canHold = true; + // ── Score / progress ─────────────────────────────────────────────────────── + this.score = 0; + this.lines = 0; + this.level = 1; + // ── Game-flow flags ──────────────────────────────────────────────────────── + this.gameOver = false; + this.paused = false; + this.animId = 0; + // ── Timing ───────────────────────────────────────────────────────────────── + this.lastTime = 0; + this.dropAccum = 0; // accumulated ms since last gravity step + this.lockDelay = 0; // ms spent touching ground before lock + this.onGround = false; + this.LOCK_DELAY = 500; // ms before auto-lock when on ground + // ── Input / DAS ──────────────────────────────────────────────────────────── + this.keysDown = new Set(); + this.dasLeft = 0; // 0 = not held; >0 = time of initial press + this.dasRight = 0; + this.arrLeft = 0; // time of last repeat + this.arrRight = 0; + const gc = (id) => document.getElementById(id); + const ctx = (id) => gc(id).getContext('2d'); + this.boardCtx = ctx('board'); + this.next1Ctx = ctx('next1'); + this.next2Ctx = ctx('next2'); + this.next3Ctx = ctx('next3'); + this.heldCtx = ctx('held'); + this.scoreEl = gc('score'); + this.linesEl = gc('lines'); + this.levelEl = gc('level'); + this.overlayEl = gc('overlay'); + this.overlayMsg = gc('overlay-msg'); + this.overlaySub = gc('overlay-sub'); + // Size canvases + gc('board').width = COLS * CELL; + gc('board').height = ROWS * CELL; + for (const id of ['next1', 'next2', 'next3', 'held']) { + const cv = gc(id); + cv.width = 4 * PCELL; + cv.height = 3 * PCELL; + } + document.addEventListener('keydown', this.onKeyDown.bind(this)); + document.addEventListener('keyup', this.onKeyUp.bind(this)); + this.initGame(); + this.animId = requestAnimationFrame(this.loop.bind(this)); + } + // ── Initialise / restart ─────────────────────────────────────────────────── + initGame() { + this.board = emptyBoard(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.held = null; + this.canHold = true; + this.gameOver = false; + this.paused = false; + this.dropAccum = 0; + this.lockDelay = 0; + this.onGround = false; + this.bag = newBag(); + this.nextPieces = []; + for (let i = 0; i < 3; i++) + this.nextPieces.push(this.drawFromBag()); + this.spawnNext(); + this.overlayEl.style.display = 'none'; + } + drawFromBag() { + if (this.bag.length === 0) + this.bag = newBag(); + return this.bag.shift(); + } + spawnNext() { + const key = this.nextPieces.shift(); + this.nextPieces.push(this.drawFromBag()); + this.current = spawnPiece(key); + this.canHold = true; + this.onGround = false; + this.lockDelay = 0; + if (!isValid(this.board, this.current)) { + this.gameOver = true; + this.showOverlay('GAME OVER', 'Press Enter to restart'); + } + } + // ── Input handlers ───────────────────────────────────────────────────────── + onKeyDown(e) { + if (this.gameOver) { + if (e.code === 'Enter' || e.code === 'Space') + this.initGame(); + return; + } + if (e.code === 'Escape' || e.code === 'KeyP') { + this.paused = !this.paused; + if (this.paused) + this.showOverlay('PAUSED', 'Press P or Esc to resume'); + else + this.overlayEl.style.display = 'none'; + e.preventDefault(); + return; + } + if (this.paused) + return; + // Prevent browser scroll on arrow / space + if (['ArrowLeft', 'ArrowRight', 'ArrowDown', 'ArrowUp', 'Space'].includes(e.code)) + e.preventDefault(); + if (!this.keysDown.has(e.code)) { + // First press + this.keysDown.add(e.code); + switch (e.code) { + case 'ArrowLeft': + this.shiftPiece(-1); + this.dasLeft = performance.now(); + this.arrLeft = performance.now(); + break; + case 'ArrowRight': + this.shiftPiece(1); + this.dasRight = performance.now(); + this.arrRight = performance.now(); + break; + case 'ArrowDown': + this.softDrop(); + break; + case 'ArrowUp': + case 'KeyX': + this.rotatePiece(1); + break; + case 'KeyZ': + this.rotatePiece(-1); + break; + case 'Space': + this.hardDrop(); + break; + case 'ShiftLeft': + case 'ShiftRight': + case 'KeyC': + this.holdPiece(); + break; + } + } + } + onKeyUp(e) { + this.keysDown.delete(e.code); + if (e.code === 'ArrowLeft') + this.dasLeft = 0; + if (e.code === 'ArrowRight') + this.dasRight = 0; + } + // ── Piece manipulation ───────────────────────────────────────────────────── + shiftPiece(dx) { + const moved = { ...this.current, x: this.current.x + dx }; + if (isValid(this.board, moved)) { + this.current = moved; + // Reset lock delay on successful shift while on ground + if (this.onGround) + this.lockDelay = 0; + } + } + rotatePiece(dir) { + const rotated = tryRotate(this.board, this.current, dir); + if (rotated) { + this.current = rotated; + if (this.onGround) + this.lockDelay = 0; + } + } + softDrop() { + const moved = { ...this.current, y: this.current.y + 1 }; + if (isValid(this.board, moved)) { + this.current = moved; + this.score += 1; + this.dropAccum = 0; + } + } + hardDrop() { + const ghost = getGhost(this.board, this.current); + const delta = ghost.y - this.current.y; + this.score += delta * 2; + this.current = ghost; + this.lock(); + } + holdPiece() { + if (!this.canHold) + return; + const key = this.current.key; + if (this.held !== null) { + this.current = spawnPiece(this.held); + } + else { + this.spawnNext(); + } + this.held = key; + this.canHold = false; + } + lock() { + lockPiece(this.board, this.current); + const cleared = clearLines(this.board); + if (cleared > 0) { + this.score += LINE_SCORES[cleared] * this.level; + this.lines += cleared; + this.level = Math.floor(this.lines / LINES_PER_LEVEL) + 1; + } + this.dropAccum = 0; + this.lockDelay = 0; + this.onGround = false; + this.spawnNext(); + } + // ── Main loop ────────────────────────────────────────────────────────────── + loop(timestamp) { + const dt = Math.min(timestamp - this.lastTime, 100); // cap at 100 ms + this.lastTime = timestamp; + if (!this.paused && !this.gameOver) { + this.update(dt, timestamp); + } + this.render(); + this.animId = requestAnimationFrame(this.loop.bind(this)); + } + update(dt, now) { + // ── DAS / ARR for left/right ───────────────────────────────────────────── + if (this.dasLeft > 0) { + if (now - this.dasLeft > DAS_DELAY && now - this.arrLeft > ARR_RATE) { + this.shiftPiece(-1); + this.arrLeft = now; + } + } + if (this.dasRight > 0) { + if (now - this.dasRight > DAS_DELAY && now - this.arrRight > ARR_RATE) { + this.shiftPiece(1); + this.arrRight = now; + } + } + // ── Soft drop held ─────────────────────────────────────────────────────── + if (this.keysDown.has('ArrowDown')) { + this.dropAccum += dt * 8; // 8× gravity + } + else { + this.dropAccum += dt; + } + const interval = DROP_INTERVALS[Math.min(this.level - 1, DROP_INTERVALS.length - 1)]; + while (this.dropAccum >= interval) { + this.dropAccum -= interval; + const moved = { ...this.current, y: this.current.y + 1 }; + if (isValid(this.board, moved)) { + this.current = moved; + this.onGround = false; + this.lockDelay = 0; + } + else { + this.onGround = true; + } + } + // ── Lock delay ─────────────────────────────────────────────────────────── + if (this.onGround) { + this.lockDelay += dt; + if (this.lockDelay >= this.LOCK_DELAY) { + // Confirm still on ground before locking + const stillOnGround = !isValid(this.board, { ...this.current, y: this.current.y + 1 }); + if (stillOnGround) + this.lock(); + } + } + } + // ── Rendering ────────────────────────────────────────────────────────────── + render() { + this.drawBoard(); + this.drawNextPreviews(); + this.drawHeld(); + this.updateHUD(); + } + drawBoard() { + const ctx = this.boardCtx; + const W = COLS * CELL; + const H = ROWS * CELL; + // Background + ctx.fillStyle = '#0e0e1a'; + ctx.fillRect(0, 0, W, H); + // Subtle grid + ctx.strokeStyle = '#1c1c30'; + ctx.lineWidth = 0.5; + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, H); + ctx.stroke(); + } + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(W, r * CELL); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < ROWS; r++) + for (let c = 0; c < COLS; c++) + if (this.board[r][c]) + drawCell(ctx, c, r, this.board[r][c], CELL); + if (!this.gameOver) { + // Ghost piece + const ghost = getGhost(this.board, this.current); + if (ghost.y !== this.current.y) { + for (const [r, c] of getCells(ghost)) + if (r >= 0) + drawGhostCell(ctx, c, r, PIECES[this.current.key].color, CELL); + } + // Active piece + for (const [r, c] of getCells(this.current)) + if (r >= 0) + drawCell(ctx, c, r, PIECES[this.current.key].color, CELL); + } + } + clearPreviewCanvas(ctx) { + ctx.fillStyle = '#111120'; + ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); + } + drawNextPreviews() { + const ctxs = [this.next1Ctx, this.next2Ctx, this.next3Ctx]; + for (let i = 0; i < 3; i++) { + this.clearPreviewCanvas(ctxs[i]); + if (this.nextPieces[i]) + drawPieceOnCanvas(ctxs[i], this.nextPieces[i], 0, PCELL); + } + } + drawHeld() { + this.clearPreviewCanvas(this.heldCtx); + // Use CSS opacity so it works regardless of ctx.save/restore inside drawCell + this.heldCtx.canvas.style.opacity = (this.held && !this.canHold) ? '0.38' : '1'; + if (this.held) + drawPieceOnCanvas(this.heldCtx, this.held, 0, PCELL); + } + updateHUD() { + this.scoreEl.textContent = this.score.toLocaleString(); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + } + // ── Overlay ──────────────────────────────────────────────────────────────── + showOverlay(msg, sub) { + this.overlayMsg.textContent = msg; + this.overlaySub.textContent = sub; + this.overlayEl.style.display = 'flex'; + } +} +// ───────────────────────────────────────────────────────────────────────────── +// Bootstrap +// ───────────────────────────────────────────────────────────────────────────── +window.addEventListener('DOMContentLoaded', () => new TetrisGame()); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=detailed_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=detailed_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,547 @@ +"use strict"; +// ============================================================ +// Tetris — TypeScript implementation +// Compiled and inlined into a single HTML file. +// No external runtime dependencies. +// ============================================================ +// ---- Board dimensions & rendering constants ---------------- +const COLS = 10; +const ROWS = 20; +const CELL = 30; // pixel size of one board cell +// ---- Tetromino colours (Tetris Guideline palette) ---------- +const COLORS = { + I: '#00CFCF', + O: '#F0C000', + T: '#A000F0', + S: '#00B800', + Z: '#D00000', + J: '#0000F0', + L: '#F0A000', +}; +// ---- Piece shape definitions (4 rotations each) ------------ +// Each rotation is an array of rows; 1 = filled, 0 = empty. +// Using the standard Tetris Guideline piece shapes. +const SHAPES = { + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + O: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +const PIECE_TYPES = ['I', 'O', 'T', 'S', 'Z', 'J', 'L']; +/** Points awarded for clearing n lines (before level multiplier). */ +const LINE_POINTS = [0, 100, 300, 500, 800]; +/** Milliseconds between gravity ticks at a given level. */ +function gravityMs(level) { + return Math.max(50, 800 - (level - 1) * 70); +} +// ============================================================ +// Main Game Class +// ============================================================ +class Tetris { + // ---- Constructor ----------------------------------------- + constructor() { + this.bag = []; + this.score = 0; + this.level = 1; + this.lines = 0; + this.over = false; + this.elapsed = 0; // ms since last gravity tick + this.lastTs = 0; // last rAF timestamp + // ---- Line-clear flash state ------------------------------ + // We run a brief clearing phase: the full rows are stored, the piece + // is locked, but the rows are NOT yet removed. Once flashTimer expires + // we remove the rows and spawn the next piece. + this.clearingRows = []; // rows waiting to be removed + this.flashTimer = 0; // counts down to 0 (ms) + this.FLASH_MS = 140; // duration of the flash animation + this.boardCanvas = document.getElementById('board'); + this.boardCtx = this.boardCanvas.getContext('2d'); + this.nextCanvas = document.getElementById('next'); + this.nextCtx = this.nextCanvas.getContext('2d'); + this.scoreEl = document.getElementById('score-val'); + this.levelEl = document.getElementById('level-val'); + this.linesEl = document.getElementById('lines-val'); + this.overlayEl = document.getElementById('overlay'); + this.finalScEl = document.getElementById('final-score'); + this.board = this.newBoard(); + this.nextType = this.pullBag(); + this.spawnNext(); + document.addEventListener('keydown', this.onKey.bind(this)); + document.getElementById('btn-restart') + .addEventListener('click', () => this.restart()); + requestAnimationFrame(ts => { this.lastTs = ts; this.frame(ts); }); + } + // ============================================================ + // Board / bag helpers + // ============================================================ + newBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); + } + /** Pull one piece type from the 7-bag randomiser (Fisher-Yates). */ + pullBag() { + if (this.bag.length === 0) { + this.bag = [...PIECE_TYPES]; + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop(); + } + /** Build a fresh Piece at its spawn position. */ + makePiece(type) { + const shape = SHAPES[type][0]; + const x = Math.floor((COLS - shape[0].length) / 2); + // Shift up so the piece's first filled row lands at board row 0 + let topFilled = 0; + for (let r = 0; r < shape.length; r++) { + if (shape[r].some(v => v !== 0)) { + topFilled = r; + break; + } + } + return { type, rot: 0, x, y: -topFilled }; + } + /** Make the queued piece active; draw a new one into the queue. */ + spawnNext() { + this.current = this.makePiece(this.nextType); + this.nextType = this.pullBag(); + this.elapsed = 0; + if (!this.valid(this.current)) + this.endGame(); + } + /** Return the shape grid for a piece at a given rotation. */ + shapeOf(p, rot = p.rot) { + return SHAPES[p.type][rot]; + } + // ============================================================ + // Collision detection + // ============================================================ + valid(p, dx = 0, dy = 0, rot) { + const shape = this.shapeOf(p, rot ?? p.rot); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = p.x + c + dx; + const ny = p.y + r + dy; + if (nx < 0 || nx >= COLS) + return false; + if (ny >= ROWS) + return false; + if (ny >= 0 && this.board[ny][nx] !== null) + return false; + } + } + return true; + } + // ============================================================ + // Core game actions + // ============================================================ + /** + * Lock the current piece onto the board. + * If full rows exist, start the flash animation instead of clearing immediately. + */ + lock() { + const shape = this.shapeOf(this.current); + let lockedAbove = false; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const ny = this.current.y + r; + const nx = this.current.x + c; + if (ny < 0) { + lockedAbove = true; + continue; + } + this.board[ny][nx] = COLORS[this.current.type]; + } + } + if (lockedAbove) { + this.endGame(); + return; + } + // Detect full rows + const full = []; + for (let r = 0; r < ROWS; r++) { + if (this.board[r].every(c => c !== null)) + full.push(r); + } + if (full.length > 0) { + // Enter clearing phase: animate flash, then resolve + this.clearingRows = full; + this.flashTimer = this.FLASH_MS; + } + else { + this.spawnNext(); + } + } + /** + * Commit the pending row clears (called after flash animation ends). + * Iterates bottom-to-top so indices stay valid after each removal. + */ + commitClear() { + const n = this.clearingRows.length; + // Sort descending so we always splice from the bottom up — + // splicing a higher row doesn't shift the indices of lower rows. + const sorted = [...this.clearingRows].sort((a, b) => b - a); + for (const r of sorted) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(null)); + } + this.lines += n; + this.score += LINE_POINTS[Math.min(n, 4)] * this.level; + this.level = Math.floor(this.lines / 10) + 1; + this.clearingRows = []; + this.spawnNext(); + } + endGame() { + this.over = true; + this.finalScEl.textContent = this.score.toLocaleString(); + this.overlayEl.style.display = 'flex'; + } + /** Y-coordinate of ghost piece (where current piece would land). */ + ghostY() { + let gy = this.current.y; + while (this.valid(this.current, 0, gy - this.current.y + 1)) + gy++; + return gy; + } + /** Try to rotate current piece CW (+1) or CCW (-1) with wall kicks. */ + rotate(dir) { + const n = SHAPES[this.current.type].length; + const rot = ((this.current.rot + dir) + n) % n; + const kicks = [0, 1, -1, 2, -2]; + for (const k of kicks) { + if (this.valid(this.current, k, 0, rot)) { + this.current.rot = rot; + this.current.x += k; + return; + } + } + } + /** Hard-drop: instantly fall to lowest valid row and lock. */ + hardDrop() { + let dist = 0; + while (this.valid(this.current, 0, 1)) { + this.current.y++; + dist++; + } + this.score += dist * 2; + this.lock(); + } + // ============================================================ + // Input + // ============================================================ + onKey(e) { + if (this.over) { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + this.restart(); + } + return; + } + // Prevent page scrolling with game keys + if (['ArrowLeft', 'ArrowRight', 'ArrowDown', 'ArrowUp', ' '].includes(e.key)) { + e.preventDefault(); + } + // Block input during clearing animation + if (this.clearingRows.length > 0) + return; + switch (e.key) { + case 'ArrowLeft': + if (this.valid(this.current, -1)) + this.current.x--; + break; + case 'ArrowRight': + if (this.valid(this.current, 1)) + this.current.x++; + break; + case 'ArrowDown': + if (this.valid(this.current, 0, 1)) { + this.current.y++; + this.score++; + this.elapsed = 0; + } + else { + this.lock(); + } + break; + case 'ArrowUp': + this.rotate(1); + break; + case 'z': + case 'Z': + this.rotate(-1); + break; + case ' ': + this.hardDrop(); + break; + } + } + // ============================================================ + // Game loop + // ============================================================ + frame(ts) { + const dt = Math.min(ts - this.lastTs, 200); // clamp gaps (e.g. tab switch) + this.lastTs = ts; + if (!this.over) { + if (this.clearingRows.length > 0) { + // ---- Clearing / flash phase ---- + this.flashTimer -= dt; + if (this.flashTimer <= 0) + this.commitClear(); + } + else { + // ---- Normal gravity ---- + this.elapsed += dt; + const interval = gravityMs(this.level); + while (this.elapsed >= interval) { + this.elapsed -= interval; + if (this.valid(this.current, 0, 1)) { + this.current.y++; + } + else { + this.lock(); + break; // lock() may start clearing phase; don't double-tick + } + } + } + } + this.render(); + requestAnimationFrame(this.frame.bind(this)); + } + // ============================================================ + // Rendering + // ============================================================ + render() { + this.renderBoard(); + this.renderNext(); + this.scoreEl.textContent = this.score.toLocaleString(); + this.levelEl.textContent = this.level.toString(); + this.linesEl.textContent = this.lines.toString(); + } + renderBoard() { + const ctx = this.boardCtx; + const W = COLS * CELL; + const H = ROWS * CELL; + // Background + ctx.fillStyle = '#0d0d1a'; + ctx.fillRect(0, 0, W, H); + // Subtle grid + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(W, r * CELL); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, H); + ctx.stroke(); + } + // Flash factor for clearing animation (1 → 0 over FLASH_MS) + const flashT = this.flashTimer > 0 + ? this.flashTimer / this.FLASH_MS // 1 at start, 0 at end + : 0; + // Placed blocks + for (let r = 0; r < ROWS; r++) { + const isFlashing = flashT > 0 && this.clearingRows.includes(r); + for (let c = 0; c < COLS; c++) { + const cell = this.board[r][c]; + if (cell) + this.drawBlock(ctx, c, r, cell, isFlashing ? flashT : 0); + } + } + if (!this.over && this.clearingRows.length === 0) { + // Ghost piece + const gy = this.ghostY(); + const shape = this.shapeOf(this.current); + const col = COLORS[this.current.type]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = this.current.x + c; + const by = gy + r; + if (by >= 0 && by < ROWS) + this.drawGhost(ctx, bx, by, col); + } + } + // Active piece + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = this.current.x + c; + const by = this.current.y + r; + if (by >= 0 && by < ROWS) + this.drawBlock(ctx, bx, by, col, 0); + } + } + } + } + /** + * Draw a bevelled, shaded block at board grid position (col, row). + * flashT: 0 = normal; >0 = blend toward white (line-clear flash). + */ + drawBlock(ctx, col, row, color, flashT) { + const x = col * CELL + 1; + const y = row * CELL + 1; + const s = CELL - 2; + // Base fill + ctx.fillStyle = color; + ctx.fillRect(x, y, s, s); + // Diagonal gradient overlay + const grad = ctx.createLinearGradient(x, y, x + s, y + s); + grad.addColorStop(0, 'rgba(255,255,255,0.22)'); + grad.addColorStop(1, 'rgba(0,0,0,0.22)'); + ctx.fillStyle = grad; + ctx.fillRect(x, y, s, s); + // Top-left bright bevel + ctx.fillStyle = 'rgba(255,255,255,0.45)'; + ctx.fillRect(x, y, s, 3); // top edge + ctx.fillRect(x, y, 3, s); // left edge + // Bottom-right dark bevel + ctx.fillStyle = 'rgba(0,0,0,0.40)'; + ctx.fillRect(x, y + s - 3, s, 3); // bottom edge + ctx.fillRect(x + s - 3, y, 3, s); // right edge + // Line-clear flash: overlay white + if (flashT > 0) { + // Pulse: brightest at mid-animation (sine curve feels best) + const pulse = Math.sin(flashT * Math.PI); + ctx.fillStyle = `rgba(255,255,255,${pulse * 0.75})`; + ctx.fillRect(x, y, s, s); + } + } + /** Draw a ghost block (hollow outline) at board position (col, row). */ + drawGhost(ctx, col, row, color) { + const x = col * CELL + 2; + const y = row * CELL + 2; + const s = CELL - 4; + ctx.strokeStyle = color; + ctx.lineWidth = 1.5; + ctx.globalAlpha = 0.28; + ctx.strokeRect(x, y, s, s); + ctx.globalAlpha = 1; + } + /** Render the next-piece preview canvas. */ + renderNext() { + const ctx = this.nextCtx; + const W = this.nextCanvas.width; + const H = this.nextCanvas.height; + const CS = 24; // cell size in the preview + ctx.fillStyle = '#0d0d1a'; + ctx.fillRect(0, 0, W, H); + const shape = SHAPES[this.nextType][0]; + const rows = shape.length; + const cols = shape[0].length; + // Tight bounding box of non-zero cells + let r0 = rows, r1 = 0, c0 = cols, c1 = 0; + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (shape[r][c]) { + if (r < r0) + r0 = r; + if (r > r1) + r1 = r; + if (c < c0) + c0 = c; + if (c > c1) + c1 = c; + } + } + } + const bW = (c1 - c0 + 1) * CS; + const bH = (r1 - r0 + 1) * CS; + const ox = Math.floor((W - bW) / 2) - c0 * CS; + const oy = Math.floor((H - bH) / 2) - r0 * CS; + const col = COLORS[this.nextType]; + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (!shape[r][c]) + continue; + const x = ox + c * CS + 1; + const y = oy + r * CS + 1; + const s = CS - 2; + // Base + ctx.fillStyle = col; + ctx.fillRect(x, y, s, s); + // Gradient + const g = ctx.createLinearGradient(x, y, x + s, y + s); + g.addColorStop(0, 'rgba(255,255,255,0.22)'); + g.addColorStop(1, 'rgba(0,0,0,0.22)'); + ctx.fillStyle = g; + ctx.fillRect(x, y, s, s); + // Bevels + ctx.fillStyle = 'rgba(255,255,255,0.45)'; + ctx.fillRect(x, y, s, 3); + ctx.fillRect(x, y, 3, s); + ctx.fillStyle = 'rgba(0,0,0,0.40)'; + ctx.fillRect(x, y + s - 3, s, 3); + ctx.fillRect(x + s - 3, y, 3, s); + } + } + } + // ============================================================ + // Restart + // ============================================================ + restart() { + this.bag = []; + this.board = this.newBoard(); + this.score = 0; + this.level = 1; + this.lines = 0; + this.over = false; + this.elapsed = 0; + this.clearingRows = []; + this.flashTimer = 0; + this.nextType = this.pullBag(); + this.spawnNext(); + this.overlayEl.style.display = 'none'; + } +} +// ---- Bootstrap ---------------------------------------- +window.addEventListener('DOMContentLoaded', () => { new Tetris(); }); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,530 @@ +"use strict"; +const COLS = 10; +const ROWS = 20; +const CELL = 32; +const NEXT_CELL = 24; +const COLORS = [ + '', + '#00f0f0', + '#f0f000', + '#a000f0', + '#00f000', + '#f00000', + '#0000f0', + '#f0a000', +]; +const SHADES = [ + '', + '#007878', + '#787800', + '#500078', + '#007800', + '#780000', + '#000078', + '#785000', +]; +const PIECES = [ + [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + [ + [2, 2], + [2, 2], + ], + [ + [0, 3, 0], + [3, 3, 3], + [0, 0, 0], + ], + [ + [0, 4, 4], + [4, 4, 0], + [0, 0, 0], + ], + [ + [5, 5, 0], + [0, 5, 5], + [0, 0, 0], + ], + [ + [6, 0, 0], + [6, 6, 6], + [0, 0, 0], + ], + [ + [0, 0, 7], + [7, 7, 7], + [0, 0, 0], + ], +]; +const CW_JLSTZ = [ + [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], +]; +const CCW_JLSTZ = [ + [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], +]; +const CW_I = [ + [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], +]; +const CCW_I = [ + [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], +]; +const LINE_PTS = [0, 100, 300, 500, 800]; +const DAS_DELAY = 167; +const DAS_RATE = 33; +const SD_RATE = 50; +function rotateCW(m) { + const n = m.length; + const r = Array.from({ length: n }, () => new Array(n).fill(0)); + for (let i = 0; i < n; i++) + for (let j = 0; j < n; j++) + r[j][n - 1 - i] = m[i][j]; + return r; +} +function rotateCCW(m) { + const n = m.length; + const r = Array.from({ length: n }, () => new Array(n).fill(0)); + for (let i = 0; i < n; i++) + for (let j = 0; j < n; j++) + r[n - 1 - j][i] = m[i][j]; + return r; +} +class SevenBag { + constructor() { + this.pool = []; + } + next() { + if (!this.pool.length) { + this.pool = [0, 1, 2, 3, 4, 5, 6]; + for (let i = 6; i > 0; i--) { + const j = (Math.random() * (i + 1)) | 0; + [this.pool[i], this.pool[j]] = [this.pool[j], this.pool[i]]; + } + } + return this.pool.pop(); + } +} +class Tetris { + constructor() { + this.bag = new SevenBag(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.over = false; + this.paused = false; + this.onGround = false; + this.lockAt = 0; + this.lockMoves = 0; + this.lastDrop = 0; + this.flashRows = []; + this.flashUntil = 0; + this.pendingLock = false; + this.held = new Map(); + this.lastRep = new Map(); + this.raf = 0; + this.board_cvs = document.getElementById('board'); + this.board_ctx = this.board_cvs.getContext('2d'); + this.next_cvs = document.getElementById('next'); + this.next_ctx = this.next_cvs.getContext('2d'); + this.board = this.emptyBoard(); + this.nextType = this.bag.next(); + this.spawn(); + this.bindKeys(); + this.raf = requestAnimationFrame(ts => this.tick(ts)); + } + emptyBoard() { + return Array.from({ length: ROWS }, () => new Array(COLS).fill(0)); + } + hits(m, px, py) { + for (let r = 0; r < m.length; r++) { + for (let c = 0; c < m[r].length; c++) { + if (!m[r][c]) + continue; + const nx = px + c, ny = py + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && this.board[ny][nx]) + return true; + } + } + return false; + } + spawn() { + const type = this.nextType; + this.nextType = this.bag.next(); + const matrix = PIECES[type].map(row => [...row]); + const x = Math.floor((COLS - matrix[0].length) / 2); + this.piece = { matrix, x, y: 0, type, rot: 0 }; + this.onGround = false; + this.lockMoves = 0; + if (this.hits(matrix, x, 0)) { + this.over = true; + } + this.drawNext(); + } + lock() { + const { matrix, x, y } = this.piece; + for (let r = 0; r < matrix.length; r++) + for (let c = 0; c < matrix[r].length; c++) + if (matrix[r][c] && y + r >= 0) + this.board[y + r][x + c] = matrix[r][c]; + const full = []; + for (let r = 0; r < ROWS; r++) + if (this.board[r].every(v => v !== 0)) + full.push(r); + if (full.length) { + this.flashRows = full; + this.flashUntil = performance.now() + 180; + this.pendingLock = true; + } + else { + this.onGround = false; + if (!this.over) + this.spawn(); + } + } + finishClear() { + const rows = [...this.flashRows].sort((a, b) => b - a); + for (const r of rows) { + this.board.splice(r, 1); + this.board.unshift(new Array(COLS).fill(0)); + } + const n = rows.length; + this.score += LINE_PTS[n] * this.level; + this.lines += n; + this.level = Math.floor(this.lines / 10) + 1; + this.updateUI(); + this.flashRows = []; + this.pendingLock = false; + this.onGround = false; + if (!this.over) + this.spawn(); + } + move(dx, dy) { + const { matrix, x, y } = this.piece; + if (this.hits(matrix, x + dx, y + dy)) + return false; + this.piece.x += dx; + this.piece.y += dy; + if (dx !== 0 && this.onGround && this.lockMoves < 15) { + this.lockAt = performance.now(); + this.lockMoves++; + } + return true; + } + rotate(dir) { + const { type, rot, matrix, x, y } = this.piece; + const isI = type === 0; + const newMat = dir === 1 ? rotateCW(matrix) : rotateCCW(matrix); + const kicks = dir === 1 + ? (isI ? CW_I : CW_JLSTZ) + : (isI ? CCW_I : CCW_JLSTZ); + for (const [dx, dy] of kicks[rot]) { + if (!this.hits(newMat, x + dx, y + dy)) { + this.piece.matrix = newMat; + this.piece.x += dx; + this.piece.y += dy; + this.piece.rot = ((rot + dir) + 4) % 4; + if (this.onGround && this.lockMoves < 15) { + this.lockAt = performance.now(); + this.lockMoves++; + } + return; + } + } + } + softDrop() { + if (this.move(0, 1)) { + this.score++; + this.updateUI(); + this.lastDrop = performance.now(); + } + } + hardDrop() { + let dropped = 0; + while (this.move(0, 1)) + dropped++; + this.score += dropped * 2; + this.updateUI(); + this.lock(); + this.lastDrop = performance.now(); + } + ghostY() { + let gy = this.piece.y; + while (!this.hits(this.piece.matrix, this.piece.x, gy + 1)) + gy++; + return gy; + } + dropInterval() { + return Math.max(50, 1000 - (this.level - 1) * 93); + } + updateUI() { + document.getElementById('score').textContent = this.score.toLocaleString(); + document.getElementById('level').textContent = String(this.level); + document.getElementById('lines').textContent = String(this.lines); + } + tick(ts) { + this.raf = requestAnimationFrame(t => this.tick(t)); + if (this.over || this.paused) { + this.render(ts); + return; + } + if (this.pendingLock) { + if (ts >= this.flashUntil) + this.finishClear(); + this.render(ts); + return; + } + this.held.forEach((pressTime, code) => { + var _a; + const sincePress = ts - pressTime; + const sinceRep = ts - ((_a = this.lastRep.get(code)) !== null && _a !== void 0 ? _a : pressTime); + if (code === 'ArrowLeft' || code === 'ArrowRight') { + if (sincePress >= DAS_DELAY && sinceRep >= DAS_RATE) { + if (code === 'ArrowLeft') + this.move(-1, 0); + else + this.move(1, 0); + this.lastRep.set(code, ts); + } + } + else if (code === 'ArrowDown') { + if (sinceRep >= SD_RATE) { + this.softDrop(); + this.lastRep.set(code, ts); + } + } + }); + if (ts - this.lastDrop >= this.dropInterval()) { + if (!this.move(0, 1)) { + if (!this.onGround) { + this.onGround = true; + this.lockAt = ts; + } + if (ts - this.lockAt >= 500 || this.lockMoves >= 15) { + this.lock(); + } + } + else { + this.onGround = false; + } + this.lastDrop = ts; + } + this.render(ts); + } + render(ts) { + const ctx = this.board_ctx; + const W = this.board_cvs.width; + const H = this.board_cvs.height; + ctx.fillStyle = '#111827'; + ctx.fillRect(0, 0, W, H); + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(W, r * CELL); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, H); + ctx.stroke(); + } + const flashSet = new Set(this.flashRows); + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (!this.board[r][c]) + continue; + if (flashSet.has(r)) { + const bright = Math.floor((ts / 60) % 2) === 0; + this.drawCell(ctx, c, r, this.board[r][c], 1, bright); + } + else { + this.drawCell(ctx, c, r, this.board[r][c]); + } + } + } + if (!this.over && !this.pendingLock) { + const { matrix, x, y } = this.piece; + const gy = this.ghostY(); + if (gy > y) { + ctx.globalAlpha = 0.18; + for (let r = 0; r < matrix.length; r++) + for (let c = 0; c < matrix[r].length; c++) + if (matrix[r][c] && gy + r >= 0) + this.drawCell(ctx, x + c, gy + r, matrix[r][c]); + ctx.globalAlpha = 1; + } + for (let r = 0; r < matrix.length; r++) + for (let c = 0; c < matrix[r].length; c++) + if (matrix[r][c] && y + r >= 0) + this.drawCell(ctx, x + c, y + r, matrix[r][c]); + } + if (this.over) { + ctx.fillStyle = 'rgba(0,0,0,0.78)'; + ctx.fillRect(0, 0, W, H); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.font = 'bold 42px monospace'; + ctx.fillStyle = '#ef4444'; + ctx.fillText('GAME OVER', W / 2, H / 2 - 44); + ctx.font = '20px monospace'; + ctx.fillStyle = '#94a3b8'; + ctx.fillText(`Score: ${this.score.toLocaleString()}`, W / 2, H / 2 + 4); + ctx.font = '15px monospace'; + ctx.fillStyle = '#64748b'; + ctx.fillText('Press R to restart', W / 2, H / 2 + 38); + } + else if (this.paused) { + ctx.fillStyle = 'rgba(0,0,0,0.65)'; + ctx.fillRect(0, 0, W, H); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.font = 'bold 44px monospace'; + ctx.fillStyle = '#f0f9ff'; + ctx.fillText('PAUSED', W / 2, H / 2 - 20); + ctx.font = '15px monospace'; + ctx.fillStyle = '#64748b'; + ctx.fillText('Press P to resume', W / 2, H / 2 + 22); + } + } + drawCell(ctx, col, row, idx, alpha = 1, bright = false) { + const x = col * CELL; + const y = row * CELL; + const color = bright ? '#ffffff' : COLORS[idx]; + const shade = bright ? '#cccccc' : SHADES[idx]; + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x, y, CELL, CELL); + ctx.fillStyle = 'rgba(255,255,255,0.45)'; + ctx.fillRect(x, y, CELL, 3); + ctx.fillRect(x, y, 3, CELL); + ctx.fillStyle = shade; + ctx.fillRect(x, y + CELL - 3, CELL, 3); + ctx.fillRect(x + CELL - 3, y, 3, CELL); + ctx.fillStyle = color; + ctx.fillRect(x + 3, y + 3, CELL - 6, CELL - 6); + ctx.globalAlpha = 1; + } + drawNext() { + const ctx = this.next_ctx; + const W = this.next_cvs.width; + const H = this.next_cvs.height; + const S = NEXT_CELL; + ctx.fillStyle = '#0f172a'; + ctx.fillRect(0, 0, W, H); + const m = PIECES[this.nextType]; + const ox = Math.floor((W - m[0].length * S) / 2); + const oy = Math.floor((H - m.length * S) / 2); + for (let r = 0; r < m.length; r++) { + for (let c = 0; c < m[r].length; c++) { + if (!m[r][c]) + continue; + const px = ox + c * S; + const py = oy + r * S; + const color = COLORS[m[r][c]]; + const shade = SHADES[m[r][c]]; + ctx.fillStyle = color; + ctx.fillRect(px, py, S, S); + ctx.fillStyle = 'rgba(255,255,255,0.45)'; + ctx.fillRect(px, py, S, 2); + ctx.fillRect(px, py, 2, S); + ctx.fillStyle = shade; + ctx.fillRect(px, py + S - 2, S, 2); + ctx.fillRect(px + S - 2, py, 2, S); + ctx.fillStyle = color; + ctx.fillRect(px + 2, py + 2, S - 4, S - 4); + } + } + } + bindKeys() { + const GAME_KEYS = new Set([ + 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Space', + 'KeyZ', 'KeyX', 'KeyP', 'KeyR', + ]); + document.addEventListener('keydown', e => { + if (GAME_KEYS.has(e.code)) + e.preventDefault(); + if (e.code === 'KeyR') { + this.restart(); + return; + } + if (e.code === 'KeyP') { + if (!this.over) + this.paused = !this.paused; + return; + } + if (this.over || this.paused || this.pendingLock) + return; + if (this.held.has(e.code)) + return; + const now = performance.now(); + this.held.set(e.code, now); + this.lastRep.set(e.code, now); + switch (e.code) { + case 'ArrowLeft': + this.move(-1, 0); + break; + case 'ArrowRight': + this.move(1, 0); + break; + case 'ArrowDown': + this.softDrop(); + break; + case 'ArrowUp': + case 'KeyX': + this.rotate(1); + break; + case 'KeyZ': + this.rotate(-1); + break; + case 'Space': + this.hardDrop(); + break; + } + }); + document.addEventListener('keyup', e => { + this.held.delete(e.code); + this.lastRep.delete(e.code); + }); + } + restart() { + cancelAnimationFrame(this.raf); + this.board = this.emptyBoard(); + this.bag = new SevenBag(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.over = false; + this.paused = false; + this.onGround = false; + this.lockMoves = 0; + this.lastDrop = 0; + this.flashRows = []; + this.pendingLock = false; + this.held.clear(); + this.lastRep.clear(); + this.nextType = this.bag.next(); + this.updateUI(); + this.spawn(); + this.raf = requestAnimationFrame(ts => this.tick(ts)); + } +} +window.addEventListener('DOMContentLoaded', () => { new Tetris(); }); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,630 @@ +"use strict"; +// ──────────────────────────────────────────────────────────────────────────── +// Tetris – complete implementation +// ──────────────────────────────────────────────────────────────────────────── +// ── Constants ──────────────────────────────────────────────────────────────── +const BOARD_COLS = 10; +const BOARD_ROWS = 20; +const CELL = 30; // px per cell on the main board +const PREVIEW_CS = 22; // px per cell in preview canvases +const COLORS = { + I: '#00d8ff', + O: '#ffe600', + T: '#b200ff', + S: '#00e040', + Z: '#ff2020', + J: '#2050ff', + L: '#ff8c00', +}; +// Darker shade used for the bevel shadow face +const DARK = { + I: '#0090aa', + O: '#aa9800', + T: '#720099', + S: '#008828', + Z: '#aa0000', + J: '#0030aa', + L: '#aa5c00', +}; +// ── Tetromino shapes (4 rotations each, SRS layout) ───────────────────────── +const SHAPES = { + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + O: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +// ── SRS Wall-kick tables (canvas coords: +y = downward) ───────────────────── +// Derived from standard SRS by negating the original y component. +const KICKS_JLSTZ = { + '0->1': [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + '1->0': [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + '1->2': [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + '2->1': [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + '2->3': [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + '3->2': [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + '3->0': [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + '0->3': [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], +}; +const KICKS_I = { + '0->1': [[0, 0], [-2, 0], [1, 0], [-2, 1], [1, -2]], + '1->0': [[0, 0], [2, 0], [-1, 0], [2, -1], [-1, 2]], + '1->2': [[0, 0], [-1, 0], [2, 0], [-1, -2], [2, 1]], + '2->1': [[0, 0], [1, 0], [-2, 0], [1, 2], [-2, -1]], + '2->3': [[0, 0], [2, 0], [-1, 0], [2, -1], [-1, 2]], + '3->2': [[0, 0], [-2, 0], [1, 0], [-2, 1], [1, -2]], + '3->0': [[0, 0], [1, 0], [-2, 0], [1, 2], [-2, -1]], + '0->3': [[0, 0], [-1, 0], [2, 0], [-1, -2], [2, 1]], +}; +// ── TetrisGame ─────────────────────────────────────────────────────────────── +class TetrisGame { + // ── constructor ────────────────────────────────────────────────────────── + constructor() { + // state + this.board = []; + this.current = null; + this.next = null; + this.held = null; + this.canHold = true; + this.score = 0; + this.best = 0; + this.level = 1; + this.lines = 0; + this.over = false; + this.paused = false; + // timing + this.dropMs = 1000; + this.lastDrop = 0; + // 7-bag randomizer + this.bag = []; + // DAS / ARR (values in ms) + this.DAS = 167; + this.ARR = 33; + this.heldKeys = new Map(); // key → pressTimestamp + this.dasActive = new Set(); + this.lastArr = new Map(); + // line-clear flash animation + this.flashRows = []; + this.flashUntil = 0; + this.pendingLock = false; + this.cvs = document.getElementById('game-canvas'); + this.ctx = this.cvs.getContext('2d'); + this.nCvs = document.getElementById('next-canvas'); + this.nCtx = this.nCvs.getContext('2d'); + this.hCvs = document.getElementById('hold-canvas'); + this.hCtx = this.hCvs.getContext('2d'); + this.best = parseInt(localStorage.getItem('tetris-best') ?? '0', 10); + this.bindInput(); + this.init(); + requestAnimationFrame(ts => this.loop(ts)); + } + // ── initialisation ─────────────────────────────────────────────────────── + init() { + this.board = Array.from({ length: BOARD_ROWS }, () => Array(BOARD_COLS).fill(null)); + this.held = null; + this.canHold = true; + this.score = 0; + this.level = 1; + this.lines = 0; + this.over = false; + this.paused = false; + this.dropMs = 1000; + this.bag = []; + this.flashRows = []; + this.flashUntil = 0; + this.pendingLock = false; + this.next = this.makePiece(this.drawBag()); + this.spawn(); + this.syncUI(); + } + // ── 7-bag ──────────────────────────────────────────────────────────────── + drawBag() { + if (!this.bag.length) { + this.bag = ['I', 'O', 'T', 'S', 'Z', 'J', 'L']; + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop(); + } + makePiece(type) { + const w = SHAPES[type][0][0].length; + return { type, rotation: 0, x: Math.floor((BOARD_COLS - w) / 2), y: 0 }; + } + spawn() { + this.current = this.next; + this.next = this.makePiece(this.drawBag()); + this.canHold = true; + if (!this.fits(this.current)) + this.endGame(); + } + // ── collision ──────────────────────────────────────────────────────────── + fits(p, dx = 0, dy = 0, rot) { + const shape = SHAPES[p.type][rot ?? p.rotation]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = p.x + dx + c; + const ny = p.y + dy + r; + if (nx < 0 || nx >= BOARD_COLS || ny >= BOARD_ROWS) + return false; + if (ny >= 0 && this.board[ny][nx] !== null) + return false; + } + } + return true; + } + // ── movement ───────────────────────────────────────────────────────────── + shiftH(dir) { + if (this.current && this.fits(this.current, dir)) + this.current.x += dir; + } + gravityDrop() { + if (!this.current) + return; + if (this.fits(this.current, 0, 1)) { + this.current.y++; + } + else { + this.triggerLock(); + } + } + softDrop() { + if (!this.current) + return; + if (this.fits(this.current, 0, 1)) { + this.current.y++; + this.score++; + this.syncUI(); + } + else { + this.triggerLock(); + } + } + hardDrop() { + if (!this.current) + return; + let n = 0; + while (this.fits(this.current, 0, n + 1)) + n++; + this.current.y += n; + this.score += n * 2; + this.syncUI(); + this.triggerLock(); + } + rotate(dir) { + if (!this.current) + return; + const from = this.current.rotation; + const to = ((from + dir) + 4) % 4; + const kicks = this.current.type === 'I' ? KICKS_I : KICKS_JLSTZ; + for (const [kx, ky] of (kicks[`${from}->${to}`] ?? [[0, 0]])) { + if (this.fits(this.current, kx, ky, to)) { + this.current.x += kx; + this.current.y += ky; + this.current.rotation = to; + return; + } + } + } + holdPiece() { + if (!this.current || !this.canHold) + return; + const t = this.current.type; + if (this.held) { + this.current = this.makePiece(this.held); + } + else { + this.current = this.next; + this.next = this.makePiece(this.drawBag()); + } + this.held = t; + this.canHold = false; + if (!this.fits(this.current)) + this.endGame(); + } + // ── locking & clearing ─────────────────────────────────────────────────── + triggerLock() { + // stamp piece onto board immediately then flash cleared rows + if (!this.current) + return; + const shape = SHAPES[this.current.type][this.current.rotation]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const ny = this.current.y + r; + const nx = this.current.x + c; + if (ny >= 0) + this.board[ny][nx] = COLORS[this.current.type]; + } + } + this.current = null; + // collect full rows + const full = []; + for (let r = 0; r < BOARD_ROWS; r++) { + if (this.board[r].every(c => c !== null)) + full.push(r); + } + if (full.length) { + this.flashRows = full; + this.flashUntil = performance.now() + 160; + this.pendingLock = true; + } + else { + this.spawn(); + } + } + commitClear() { + const cleared = this.flashRows.length; + // remove rows top-to-bottom (indices are already in order) + for (const r of this.flashRows) { + this.board.splice(r, 1); + this.board.unshift(Array(BOARD_COLS).fill(null)); + } + this.flashRows = []; + this.pendingLock = false; + const pts = [0, 100, 300, 500, 800]; + this.score += (pts[Math.min(cleared, 4)] ?? 800) * this.level; + this.lines += cleared; + this.level = Math.floor(this.lines / 10) + 1; + this.dropMs = Math.max(50, 1000 - (this.level - 1) * 100); + if (this.score > this.best) { + this.best = this.score; + localStorage.setItem('tetris-best', String(this.best)); + } + this.syncUI(); + this.spawn(); + } + // ── game-over ──────────────────────────────────────────────────────────── + endGame() { + this.over = true; + this.current = null; + const el = document.getElementById('final-score'); + if (el) + el.textContent = `Score: ${this.score.toLocaleString()}`; + const overlay = document.getElementById('game-over-overlay'); + if (overlay) + overlay.style.display = 'flex'; + } + // ── UI sync ────────────────────────────────────────────────────────────── + syncUI() { + document.getElementById('score').textContent = this.score.toLocaleString(); + document.getElementById('best').textContent = this.best.toLocaleString(); + document.getElementById('level').textContent = String(this.level); + document.getElementById('lines').textContent = String(this.lines); + } + // ── ghost piece ────────────────────────────────────────────────────────── + ghostRow() { + if (!this.current) + return 0; + let gy = this.current.y; + while (this.fits(this.current, 0, gy - this.current.y + 1)) + gy++; + return gy; + } + // ── rendering ──────────────────────────────────────────────────────────── + /** Draw a single bevelled block at grid position (col, row). */ + drawBlock(ctx, col, row, color, dark, cs = CELL, alpha = 1) { + const x = col * cs, y = row * cs; + ctx.globalAlpha = alpha; + // base fill + ctx.fillStyle = color; + ctx.fillRect(x + 1, y + 1, cs - 2, cs - 2); + // top & left highlight + ctx.fillStyle = 'rgba(255,255,255,0.28)'; + ctx.fillRect(x + 1, y + 1, cs - 2, 4); + ctx.fillRect(x + 1, y + 1, 4, cs - 2); + // inner darker accent strip (right & bottom) + ctx.fillStyle = dark; + ctx.fillRect(x + 1, y + cs - 5, cs - 2, 4); + ctx.fillRect(x + cs - 5, y + 1, 4, cs - 2); + // very dark outer edge + ctx.fillStyle = 'rgba(0,0,0,0.5)'; + ctx.fillRect(x + 1, y + cs - 2, cs - 2, 1); + ctx.fillRect(x + cs - 2, y + 1, 1, cs - 2); + ctx.globalAlpha = 1; + } + renderBoard() { + const { ctx, cvs } = this; + ctx.fillStyle = '#0d1117'; + ctx.fillRect(0, 0, cvs.width, cvs.height); + // subtle grid + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 0.5; + for (let c = 0; c <= BOARD_COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, cvs.height); + ctx.stroke(); + } + for (let r = 0; r <= BOARD_ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(cvs.width, r * CELL); + ctx.stroke(); + } + // locked cells (skip flash rows so they can pulse) + for (let r = 0; r < BOARD_ROWS; r++) { + if (this.flashRows.includes(r)) + continue; + for (let c = 0; c < BOARD_COLS; c++) { + if (this.board[r][c]) { + const col = this.board[r][c]; + const type = Object.keys(COLORS).find(k => COLORS[k] === col); + this.drawBlock(ctx, c, r, col, type ? DARK[type] : '#555'); + } + } + } + // flash animation for line clears + if (this.flashRows.length) { + const t = (performance.now() % 200) / 200; + const a = 0.4 + 0.6 * Math.sin(t * Math.PI); + for (const r of this.flashRows) { + ctx.globalAlpha = a; + ctx.fillStyle = '#ffffff'; + ctx.fillRect(0, r * CELL + 1, cvs.width, CELL - 2); + ctx.globalAlpha = 1; + } + } + } + renderGhost() { + if (!this.current) + return; + const gy = this.ghostRow(); + const shape = SHAPES[this.current.type][this.current.rotation]; + const color = COLORS[this.current.type]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = this.current.x + c; + const by = gy + r; + if (by < 0) + continue; + const px = bx * CELL, py = by * CELL; + this.ctx.globalAlpha = 0.12; + this.ctx.fillStyle = color; + this.ctx.fillRect(px + 1, py + 1, CELL - 2, CELL - 2); + this.ctx.globalAlpha = 0.45; + this.ctx.strokeStyle = color; + this.ctx.lineWidth = 1.5; + this.ctx.strokeRect(px + 2, py + 2, CELL - 4, CELL - 4); + this.ctx.globalAlpha = 1; + } + } + } + renderCurrent() { + if (!this.current) + return; + const shape = SHAPES[this.current.type][this.current.rotation]; + const color = COLORS[this.current.type]; + const dark = DARK[this.current.type]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const by = this.current.y + r; + if (by < 0) + continue; + this.drawBlock(this.ctx, this.current.x + c, by, color, dark); + } + } + } + renderPreview(ctx, cvs, type, dimmed = false) { + ctx.fillStyle = '#111827'; + ctx.fillRect(0, 0, cvs.width, cvs.height); + if (!type) + return; + const shape = SHAPES[type][0]; + const color = dimmed ? '#404055' : COLORS[type]; + const dark = dimmed ? '#28283a' : DARK[type]; + const rows = shape.length; + const cols = shape[0].length; + const cs = PREVIEW_CS; + const ox = Math.floor((cvs.width - cols * cs) / 2); + const oy = Math.floor((cvs.height - rows * cs) / 2); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (!shape[r][c]) + continue; + // manually offset instead of using drawBlock's grid-position + const px = Math.floor(ox / cs) + c; + const py = Math.floor(oy / cs) + r; + // draw manually at pixel-level + const x = ox + c * cs, y = oy + r * cs; + ctx.fillStyle = color; + ctx.fillRect(x + 1, y + 1, cs - 2, cs - 2); + if (!dimmed) { + ctx.fillStyle = 'rgba(255,255,255,0.28)'; + ctx.fillRect(x + 1, y + 1, cs - 2, 3); + ctx.fillRect(x + 1, y + 1, 3, cs - 2); + ctx.fillStyle = dark; + ctx.fillRect(x + 1, y + cs - 4, cs - 2, 3); + ctx.fillRect(x + cs - 4, y + 1, 3, cs - 2); + } + void px; + void py; // suppress unused-var + } + } + } + renderPause() { + const { ctx, cvs } = this; + ctx.fillStyle = 'rgba(0,0,0,0.7)'; + ctx.fillRect(0, 0, cvs.width, cvs.height); + ctx.font = 'bold 30px "Segoe UI", system-ui, sans-serif'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = '#ffffff'; + ctx.fillText('PAUSED', cvs.width / 2, cvs.height / 2 - 16); + ctx.font = '14px "Segoe UI", system-ui, sans-serif'; + ctx.fillStyle = 'rgba(255,255,255,0.5)'; + ctx.fillText('Press P to resume', cvs.width / 2, cvs.height / 2 + 18); + } + // ── game loop ──────────────────────────────────────────────────────────── + loop(ts) { + // handle pending flash → clear + if (this.pendingLock && ts >= this.flashUntil) { + this.commitClear(); + } + if (!this.over && !this.paused && !this.pendingLock) { + // gravity + if (ts - this.lastDrop >= this.dropMs) { + this.lastDrop = ts; + this.gravityDrop(); + } + // DAS / ARR + this.processDAS(ts); + } + // draw + this.renderBoard(); + this.renderGhost(); + this.renderCurrent(); + this.renderPreview(this.nCtx, this.nCvs, this.next?.type ?? null); + this.renderPreview(this.hCtx, this.hCvs, this.held, !this.canHold); + if (this.paused) + this.renderPause(); + requestAnimationFrame(ts2 => this.loop(ts2)); + } + // ── DAS / ARR ──────────────────────────────────────────────────────────── + processDAS(ts) { + for (const [key, pressTs] of this.heldKeys) { + if (ts - pressTs < this.DAS) + continue; + if (!this.dasActive.has(key)) { + this.dasActive.add(key); + this.lastArr.set(key, ts); + } + const la = this.lastArr.get(key); + const moves = Math.floor((ts - la) / this.ARR); + if (moves > 0) { + this.lastArr.set(key, la + moves * this.ARR); + for (let i = 0; i < moves; i++) { + if (key === 'ArrowLeft') + this.shiftH(-1); + if (key === 'ArrowRight') + this.shiftH(1); + if (key === 'ArrowDown') + this.softDrop(); + } + } + } + } + // ── input ──────────────────────────────────────────────────────────────── + bindInput() { + window.addEventListener('keydown', e => { + if (this.over) { + if (e.code === 'Enter' || e.code === 'Space') + this.restart(); + return; + } + if (e.code === 'KeyP') { + this.paused = !this.paused; + return; + } + if (this.paused) + return; + // suppress browser's built-in key-repeat for DAS keys + const dasKeys = ['ArrowLeft', 'ArrowRight', 'ArrowDown']; + if (dasKeys.includes(e.code) && this.heldKeys.has(e.code)) { + e.preventDefault(); + return; + } + switch (e.code) { + case 'ArrowLeft': + e.preventDefault(); + this.shiftH(-1); + this.heldKeys.set('ArrowLeft', performance.now()); + break; + case 'ArrowRight': + e.preventDefault(); + this.shiftH(1); + this.heldKeys.set('ArrowRight', performance.now()); + break; + case 'ArrowDown': + e.preventDefault(); + this.softDrop(); + this.heldKeys.set('ArrowDown', performance.now()); + break; + case 'ArrowUp': + e.preventDefault(); + this.rotate(1); + break; + case 'KeyX': + this.rotate(1); + break; + case 'KeyZ': + this.rotate(-1); + break; + case 'Space': + e.preventDefault(); + this.hardDrop(); + break; + case 'KeyC': + case 'ShiftLeft': + case 'ShiftRight': + e.preventDefault(); + this.holdPiece(); + break; + } + }); + window.addEventListener('keyup', e => { + this.heldKeys.delete(e.code); + this.dasActive.delete(e.code); + this.lastArr.delete(e.code); + }); + document.getElementById('restart-btn') + ?.addEventListener('click', () => this.restart()); + } + restart() { + const overlay = document.getElementById('game-over-overlay'); + if (overlay) + overlay.style.display = 'none'; + this.heldKeys.clear(); + this.dasActive.clear(); + this.lastArr.clear(); + this.lastDrop = 0; + this.init(); + } +} +// ── Bootstrap ──────────────────────────────────────────────────────────────── +window.addEventListener('DOMContentLoaded', () => new TetrisGame()); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=off_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js @@ -0,0 +1,538 @@ +"use strict"; +// ============================================================ +// TETRIS +// ============================================================ +// ── Constants ────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell +const DAS = 167; // ms – delay before auto-repeat +const ARR = 33; // ms – auto-repeat interval +const LOCK_DELAY = 500; // ms – lock delay on ground +// ── Colour palette (index 0 = empty) ──────────────────────── +const COLORS = [ + '', + '#00f0f0', // I – cyan + '#f0f000', // O – yellow + '#a000f0', // T – purple + '#00c000', // S – green + '#f00000', // Z – red + '#0000f0', // J – blue + '#f0a000', // L – orange +]; +// ── Piece definitions (rotation 0) ────────────────────────── +const SHAPES = { + I: [[0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0]], + O: [[1, 1], + [1, 1]], + T: [[0, 1, 0], + [1, 1, 1], + [0, 0, 0]], + S: [[0, 1, 1], + [1, 1, 0], + [0, 0, 0]], + Z: [[1, 1, 0], + [0, 1, 1], + [0, 0, 0]], + J: [[1, 0, 0], + [1, 1, 1], + [0, 0, 0]], + L: [[0, 0, 1], + [1, 1, 1], + [0, 0, 0]], +}; +const COLOR_IDX = { + I: 1, O: 2, T: 3, S: 4, Z: 5, J: 6, L: 7, +}; +const ALL_TYPES = ['I', 'O', 'T', 'S', 'Z', 'J', 'L']; +// ── 7-bag randomiser ───────────────────────────────────────── +let bag = []; +function nextFromBag() { + if (bag.length === 0) { + bag = [...ALL_TYPES]; + for (let i = bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [bag[i], bag[j]] = [bag[j], bag[i]]; + } + } + return bag.pop(); +} +// ── Matrix rotation ────────────────────────────────────────── +function rotateCW(m) { + const rows = m.length, cols = m[0].length; + return Array.from({ length: cols }, (_, i) => Array.from({ length: rows }, (_, j) => m[rows - 1 - j][i])); +} +function rotateCCW(m) { + return rotateCW(rotateCW(rotateCW(m))); +} +// ── Board helpers ──────────────────────────────────────────── +function emptyBoard() { + return Array.from({ length: ROWS }, () => new Array(COLS).fill(0)); +} +function isValidPos(board, shape, x, y) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = x + c; + const by = y + r; + if (bx < 0 || bx >= COLS || by >= ROWS) + return false; + if (by >= 0 && board[by][bx] !== 0) + return false; + } + } + return true; +} +function lockToBoard(board, piece) { + const b = board.map(r => [...r]); + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + const by = piece.y + r; + if (by >= 0) + b[by][piece.x + c] = piece.colorIdx; + } + } + return b; +} +function sweepLines(board) { + const kept = board.filter(row => row.some(c => c === 0)); + const cleared = ROWS - kept.length; + const empties = Array.from({ length: cleared }, () => new Array(COLS).fill(0)); + return { board: [...empties, ...kept], cleared }; +} +// ── Ghost piece ────────────────────────────────────────────── +function getGhostY(board, piece) { + let y = piece.y; + while (isValidPos(board, piece.shape, piece.x, y + 1)) + y++; + return y; +} +// ── Wall-kick rotation ──────────────────────────────────────── +const KICKS = [ + [0, 0], [-1, 0], [1, 0], [0, -1], [-1, -1], [1, -1], [0, 1], + [-2, 0], [2, 0], +]; +function tryRotate(board, piece, cw) { + const newShape = cw ? rotateCW(piece.shape) : rotateCCW(piece.shape); + for (const [dx, dy] of KICKS) { + const nx = piece.x + dx; + const ny = piece.y + dy; + if (isValidPos(board, newShape, nx, ny)) { + return { ...piece, shape: newShape, x: nx, y: ny }; + } + } + return null; +} +// ── Scoring ─────────────────────────────────────────────────── +const SCORE_TABLE = [0, 100, 300, 500, 800]; +function calcScore(lines, level) { + return (SCORE_TABLE[lines] ?? 0) * level; +} +function dropSpeed(level) { + return Math.max(50, 1000 - (level - 1) * 80); +} +let G; +function newGameState() { + bag = []; + return { + board: emptyBoard(), + piece: null, + nextType: nextFromBag(), + score: 0, + level: 1, + lines: 0, + over: false, + paused: false, + started: false, + }; +} +function spawn() { + const p = makePiece(G.nextType); + G.nextType = nextFromBag(); + if (!isValidPos(G.board, p.shape, p.x, p.y)) { + G.over = true; + G.piece = null; + return; + } + G.piece = p; +} +function makePiece(type) { + const shape = SHAPES[type].map(r => [...r]); + return { + type, + shape, + x: Math.floor((COLS - shape[0].length) / 2), + y: type === 'I' ? -1 : 0, + colorIdx: COLOR_IDX[type], + }; +} +// ── Timing variables ────────────────────────────────────────── +let dropTmr = 0; // accumulates gravity time +let lockTmr = 0; // accumulates time sitting on ground +let lockReset = 0; // how many times lock was reset this placement +// ── Actions ─────────────────────────────────────────────────── +function doMoveLeft() { + if (!G.piece) + return; + if (isValidPos(G.board, G.piece.shape, G.piece.x - 1, G.piece.y)) { + G.piece = { ...G.piece, x: G.piece.x - 1 }; + onPieceMoved(); + } +} +function doMoveRight() { + if (!G.piece) + return; + if (isValidPos(G.board, G.piece.shape, G.piece.x + 1, G.piece.y)) { + G.piece = { ...G.piece, x: G.piece.x + 1 }; + onPieceMoved(); + } +} +function doSoftDrop() { + if (!G.piece) + return false; + if (isValidPos(G.board, G.piece.shape, G.piece.x, G.piece.y + 1)) { + G.piece = { ...G.piece, y: G.piece.y + 1 }; + G.score++; + dropTmr = 0; + lockTmr = 0; + return true; + } + return false; +} +function doHardDrop() { + if (!G.piece) + return; + const gy = getGhostY(G.board, G.piece); + G.score += (gy - G.piece.y) * 2; + G.piece = { ...G.piece, y: gy }; + doLock(); +} +function doRotate(cw) { + if (!G.piece) + return; + const rotated = tryRotate(G.board, G.piece, cw); + if (rotated) { + G.piece = rotated; + onPieceMoved(); + } +} +function onPieceMoved() { + // Reset lock timer when player moves/rotates (up to 15 times) + if (lockReset < 15) { + lockTmr = 0; + lockReset++; + } +} +function doLock() { + if (!G.piece) + return; + G.board = lockToBoard(G.board, G.piece); + const { board, cleared } = sweepLines(G.board); + G.board = board; + G.score += calcScore(cleared, G.level); + G.lines += cleared; + G.level = Math.floor(G.lines / 10) + 1; + G.piece = null; + lockTmr = 0; + lockReset = 0; + dropTmr = 0; + // Flash rows animation + if (cleared > 0) + triggerLineClear(); + spawn(); +} +// ── Line-clear flash animation ──────────────────────────────── +let flashTimer = 0; +let flashActive = false; +function triggerLineClear() { + flashActive = true; + flashTimer = 0; +} +const held = new Set(); +const dasState = {}; +document.addEventListener('keydown', e => { + if (e.repeat) + return; + // Always prevent scroll on arrow keys / space + if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Space'].includes(e.code)) { + e.preventDefault(); + } + held.add(e.code); + dasState[e.code] = { timer: 0, active: false }; + // Start / restart + if (!G.started || G.over) { + if (e.code === 'Enter' || e.code === 'Space') + startGame(); + return; + } + if (e.code === 'KeyP') { + G.paused = !G.paused; + return; + } + if (G.paused) + return; + switch (e.code) { + case 'ArrowLeft': + doMoveLeft(); + break; + case 'ArrowRight': + doMoveRight(); + break; + case 'ArrowDown': + doSoftDrop(); + break; + case 'ArrowUp': + case 'KeyX': + doRotate(true); + break; + case 'KeyZ': + doRotate(false); + break; + case 'Space': + doHardDrop(); + break; + } +}); +document.addEventListener('keyup', e => { + held.delete(e.code); + if (dasState[e.code]) { + dasState[e.code].timer = 0; + dasState[e.code].active = false; + } +}); +// ── Game loop ───────────────────────────────────────────────── +let lastT = 0; +function loop(t) { + const dt = Math.min(t - lastT, 50); // cap delta to 50 ms + lastT = t; + if (G.started && !G.paused && !G.over) { + // ── DAS processing ── + for (const code of ['ArrowLeft', 'ArrowRight', 'ArrowDown']) { + if (!held.has(code)) + continue; + const ds = dasState[code]; + if (!ds) + continue; + ds.timer += dt; + if (!ds.active) { + if (ds.timer >= DAS) { + ds.active = true; + ds.timer = 0; + applyHeld(code); + } + } + else { + while (ds.timer >= ARR) { + ds.timer -= ARR; + applyHeld(code); + } + } + } + // ── Gravity / lock ── + if (G.piece) { + const p = G.piece; + const canFall = isValidPos(G.board, p.shape, p.x, p.y + 1); + if (canFall) { + lockTmr = 0; + lockReset = 0; + dropTmr += dt; + if (dropTmr >= dropSpeed(G.level)) { + dropTmr = 0; + G.piece = { ...p, y: p.y + 1 }; + } + } + else { + lockTmr += dt; + if (lockTmr >= LOCK_DELAY) { + doLock(); + } + } + } + // ── Flash animation ── + if (flashActive) { + flashTimer += dt; + if (flashTimer >= 120) + flashActive = false; + } + } + render(); + requestAnimationFrame(loop); +} +function applyHeld(code) { + if (!G.piece || G.paused || G.over) + return; + if (code === 'ArrowLeft') + doMoveLeft(); + if (code === 'ArrowRight') + doMoveRight(); + if (code === 'ArrowDown') + doSoftDrop(); +} +function startGame() { + G = newGameState(); + G.started = true; + dropTmr = 0; + lockTmr = 0; + lockReset = 0; + flashActive = false; + spawn(); +} +// ── Canvas setup ────────────────────────────────────────────── +const boardCanvas = document.getElementById('board'); +const nextCanvas = document.getElementById('next'); +const ctx = boardCanvas.getContext('2d'); +const nctx = nextCanvas.getContext('2d'); +boardCanvas.width = COLS * BLOCK; +boardCanvas.height = ROWS * BLOCK; +nextCanvas.width = 4 * BLOCK; +nextCanvas.height = 4 * BLOCK; +// ── Drawing ─────────────────────────────────────────────────── +function drawBlock(c, col, row, cidx, alpha = 1, outline = false) { + if (cidx <= 0) + return; + const x = col * BLOCK; + const y = row * BLOCK; + const color = COLORS[cidx]; + c.globalAlpha = alpha; + if (outline) { + c.strokeStyle = color; + c.lineWidth = 1.5; + c.strokeRect(x + 2, y + 2, BLOCK - 4, BLOCK - 4); + c.globalAlpha = 1; + return; + } + // Main fill + c.fillStyle = color; + c.fillRect(x + 1, y + 1, BLOCK - 2, BLOCK - 2); + // Top-left highlight + c.fillStyle = 'rgba(255,255,255,0.40)'; + c.fillRect(x + 1, y + 1, BLOCK - 2, 5); + c.fillRect(x + 1, y + 1, 5, BLOCK - 2); + // Bottom-right shadow + c.fillStyle = 'rgba(0,0,0,0.35)'; + c.fillRect(x + 1, y + BLOCK - 6, BLOCK - 2, 5); + c.fillRect(x + BLOCK - 6, y + 1, 5, BLOCK - 2); + c.globalAlpha = 1; +} +function drawPieceShape(c, shape, cidx, offX, offY, alpha = 1, outline = false) { + for (let r = 0; r < shape.length; r++) { + for (let col = 0; col < shape[r].length; col++) { + if (!shape[r][col]) + continue; + const bx = offX + col; + const by = offY + r; + if (by < 0) + continue; // above visible area + drawBlock(c, bx, by, cidx, alpha, outline); + } + } +} +function render() { + // ── Board background ── + ctx.fillStyle = '#080818'; + ctx.fillRect(0, 0, boardCanvas.width, boardCanvas.height); + // ── Grid ── + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 0.5; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK, r * BLOCK, BLOCK, BLOCK); + } + } + // ── Locked cells ── + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (G.board[r][c]) + drawBlock(ctx, c, r, G.board[r][c]); + } + } + // ── Ghost piece ── + if (G.piece && G.started && !G.over) { + const p = G.piece; + const gy = getGhostY(G.board, p); + if (gy !== p.y) { + drawPieceShape(ctx, p.shape, p.colorIdx, p.x, gy, 0.22, true); + } + } + // ── Active piece ── + if (G.piece) { + const p = G.piece; + drawPieceShape(ctx, p.shape, p.colorIdx, p.x, p.y); + } + // ── Line-clear flash ── + if (flashActive) { + const alpha = 0.6 * (1 - flashTimer / 120); + ctx.fillStyle = `rgba(255,255,255,${alpha})`; + ctx.fillRect(0, 0, boardCanvas.width, boardCanvas.height); + } + // ── Next piece preview ── + nctx.fillStyle = '#080818'; + nctx.fillRect(0, 0, nextCanvas.width, nextCanvas.height); + const ns = SHAPES[G.nextType]; + const ncol = COLOR_IDX[G.nextType]; + const ox = Math.floor((4 - ns[0].length) / 2); + const oy = Math.floor((4 - ns.length) / 2); + for (let r = 0; r < ns.length; r++) { + for (let c = 0; c < ns[r].length; c++) { + if (!ns[r][c]) + continue; + const x = (ox + c) * BLOCK; + const y = (oy + r) * BLOCK; + nctx.fillStyle = COLORS[ncol]; + nctx.fillRect(x + 1, y + 1, BLOCK - 2, BLOCK - 2); + nctx.fillStyle = 'rgba(255,255,255,0.40)'; + nctx.fillRect(x + 1, y + 1, BLOCK - 2, 5); + nctx.fillRect(x + 1, y + 1, 5, BLOCK - 2); + nctx.fillStyle = 'rgba(0,0,0,0.35)'; + nctx.fillRect(x + 1, y + BLOCK - 6, BLOCK - 2, 5); + nctx.fillRect(x + BLOCK - 6, y + 1, 5, BLOCK - 2); + } + } + // ── HUD ── + const scoreEl = document.getElementById('score'); + const levelEl = document.getElementById('level'); + const linesEl = document.getElementById('lines'); + if (scoreEl) + scoreEl.textContent = G.score.toString(); + if (levelEl) + levelEl.textContent = G.level.toString(); + if (linesEl) + linesEl.textContent = G.lines.toString(); + // ── Overlays ── + if (!G.started) { + drawOverlay('TETRIS', 'Press Enter or Space to start'); + } + else if (G.paused) { + drawOverlay('PAUSED', 'Press P to resume'); + } + else if (G.over) { + drawOverlay('GAME OVER', `Score: ${G.score} · Press Enter to restart`); + } +} +function drawOverlay(title, sub) { + ctx.fillStyle = 'rgba(8,8,24,0.82)'; + ctx.fillRect(0, 0, boardCanvas.width, boardCanvas.height); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + // Glow + ctx.shadowColor = 'rgba(120,80,255,0.9)'; + ctx.shadowBlur = 20; + ctx.fillStyle = '#ffffff'; + ctx.font = 'bold 38px "Courier New", monospace'; + ctx.fillText(title, boardCanvas.width / 2, boardCanvas.height / 2 - 22); + ctx.shadowBlur = 0; + ctx.font = '13px "Courier New", monospace'; + ctx.fillStyle = '#9988cc'; + ctx.fillText(sub, boardCanvas.width / 2, boardCanvas.height / 2 + 20); + ctx.textAlign = 'left'; + ctx.textBaseline = 'alphabetic'; +} +// ── Bootstrap ──────────────────────────────────────────────── +G = newGameState(); +requestAnimationFrame(loop); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,375 @@ +"use strict"; +// ─── Constants ─────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell +const PREVIEW_BLOCK = 24; // px per cell in preview box +// Colours per piece type (index matches PIECES) +const COLOURS = [ + "#00f0f0", // I – cyan + "#f0a000", // O – yellow (index 1) + "#a000f0", // T – purple + "#00f000", // S – green + "#f00000", // Z – red + "#0000f0", // J – blue + "#f07000", // L – orange +]; +// Each piece: array of 4 rotations, each rotation is an array of [row, col] offsets +const PIECES = [ + // I + [ + [[1, 0], [1, 1], [1, 2], [1, 3]], + [[0, 2], [1, 2], [2, 2], [3, 2]], + [[2, 0], [2, 1], [2, 2], [2, 3]], + [[0, 1], [1, 1], [2, 1], [3, 1]], + ], + // O + [ + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + ], + // T + [ + [[0, 1], [1, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [1, 2], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 1]], + [[0, 1], [1, 0], [1, 1], [2, 1]], + ], + // S + [ + [[0, 1], [0, 2], [1, 0], [1, 1]], + [[0, 1], [1, 1], [1, 2], [2, 2]], + [[1, 1], [1, 2], [2, 0], [2, 1]], + [[0, 0], [1, 0], [1, 1], [2, 1]], + ], + // Z + [ + [[0, 0], [0, 1], [1, 1], [1, 2]], + [[0, 2], [1, 1], [1, 2], [2, 1]], + [[1, 0], [1, 1], [2, 1], [2, 2]], + [[0, 1], [1, 0], [1, 1], [2, 0]], + ], + // J + [ + [[0, 0], [1, 0], [1, 1], [1, 2]], + [[0, 1], [0, 2], [1, 1], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 2]], + [[0, 1], [1, 1], [2, 0], [2, 1]], + ], + // L + [ + [[0, 2], [1, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [2, 1], [2, 2]], + [[1, 0], [1, 1], [1, 2], [2, 0]], + [[0, 0], [0, 1], [1, 1], [2, 1]], + ], +]; +// Scoring table: points for clearing 1/2/3/4 lines simultaneously +const LINE_POINTS = [0, 100, 300, 500, 800]; +// ─── Game State ────────────────────────────────────────────────────────────── +let board; +let current; +let next; +let score; +let lines; +let level; +let gameOver; +let paused; +let dropTimer; // ms since last automatic drop +let lastTimestamp; +let animFrameId; +let lockTimer; // RAF id for lock-delay timer +// ─── DOM / Canvas ──────────────────────────────────────────────────────────── +const canvas = document.getElementById("board"); +const ctx = canvas.getContext("2d"); +const previewCanvas = document.getElementById("preview"); +const pCtx = previewCanvas.getContext("2d"); +const scoreEl = document.getElementById("score"); +const linesEl = document.getElementById("lines"); +const levelEl = document.getElementById("level"); +const messageEl = document.getElementById("message"); +const startBtn = document.getElementById("startBtn"); +canvas.width = COLS * BLOCK; +canvas.height = ROWS * BLOCK; +previewCanvas.width = 4 * PREVIEW_BLOCK; +previewCanvas.height = 4 * PREVIEW_BLOCK; +// ─── Helpers ───────────────────────────────────────────────────────────────── +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function randomPiece() { + const type = Math.floor(Math.random() * PIECES.length); + return { type, rotation: 0, row: 0, col: Math.floor(COLS / 2) - 2 }; +} +/** Return the absolute [row, col] cells occupied by a piece */ +function cells(p) { + return PIECES[p.type][p.rotation].map(([r, c]) => [p.row + r, p.col + c]); +} +function isValid(p) { + for (const [r, c] of cells(p)) { + if (r < 0 || r >= ROWS || c < 0 || c >= COLS) + return false; + if (board[r][c] !== null) + return false; + } + return true; +} +function lockPiece() { + const colour = COLOURS[current.type]; + for (const [r, c] of cells(current)) { + if (r >= 0 && r < ROWS) + board[r][c] = colour; + } + clearLines(); + current = next; + next = randomPiece(); + if (!isValid(current)) { + gameOver = true; + showMessage("GAME OVER"); + startBtn.textContent = "New Game"; + } +} +function clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every(cell => cell !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // recheck same index after splice + } + } + if (cleared > 0) { + score += LINE_POINTS[cleared] * level; + lines += cleared; + level = Math.floor(lines / 10) + 1; + updateHUD(); + } +} +function dropInterval() { + // Starts at 800ms, halves roughly every 5 levels, floor at 50ms + return Math.max(50, 800 - (level - 1) * 70); +} +function updateHUD() { + scoreEl.textContent = String(score); + linesEl.textContent = String(lines); + levelEl.textContent = String(level); +} +function showMessage(msg) { + messageEl.textContent = msg; + messageEl.style.display = "block"; +} +function hideMessage() { + messageEl.style.display = "none"; +} +// ─── Ghost Piece ───────────────────────────────────────────────────────────── +function ghostPiece() { + const ghost = Object.assign({}, current); + while (isValid(Object.assign(Object.assign({}, ghost), { row: ghost.row + 1 }))) + ghost.row++; + return ghost; +} +// ─── Drawing ───────────────────────────────────────────────────────────────── +function drawBlock(c2d, row, col, colour, blockSize, alpha = 1) { + c2d.globalAlpha = alpha; + c2d.fillStyle = colour; + c2d.fillRect(col * blockSize + 1, row * blockSize + 1, blockSize - 2, blockSize - 2); + // Highlight + c2d.fillStyle = "rgba(255,255,255,0.25)"; + c2d.fillRect(col * blockSize + 1, row * blockSize + 1, blockSize - 2, 4); + c2d.fillRect(col * blockSize + 1, row * blockSize + 1, 4, blockSize - 2); + // Shadow + c2d.fillStyle = "rgba(0,0,0,0.25)"; + c2d.fillRect(col * blockSize + 1, row * blockSize + blockSize - 5, blockSize - 2, 4); + c2d.fillRect(col * blockSize + blockSize - 5, row * blockSize + 1, 4, blockSize - 2); + c2d.globalAlpha = 1; +} +function drawBoard() { + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + ctx.lineWidth = 1; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK, r * BLOCK, BLOCK, BLOCK); + } + } + // Locked blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c]) + drawBlock(ctx, r, c, board[r][c], BLOCK); + } + } + // Ghost piece + const ghost = ghostPiece(); + for (const [r, c] of cells(ghost)) { + if (r >= 0) + drawBlock(ctx, r, c, COLOURS[current.type], BLOCK, 0.2); + } + // Current piece + for (const [r, c] of cells(current)) { + if (r >= 0) + drawBlock(ctx, r, c, COLOURS[current.type], BLOCK); + } +} +function drawPreview() { + pCtx.fillStyle = "#1a1a2e"; + pCtx.fillRect(0, 0, previewCanvas.width, previewCanvas.height); + const offsets = PIECES[next.type][0]; + // Centre the piece in the 4×4 preview + const minR = Math.min(...offsets.map(([r]) => r)); + const maxR = Math.max(...offsets.map(([r]) => r)); + const minC = Math.min(...offsets.map(([, c]) => c)); + const maxC = Math.max(...offsets.map(([, c]) => c)); + const rowPad = (3 - (maxR - minR)) / 2; + const colPad = (3 - (maxC - minC)) / 2; + for (const [r, c] of offsets) { + drawBlock(pCtx, r - minR + rowPad, c - minC + colPad, COLOURS[next.type], PREVIEW_BLOCK); + } +} +// ─── Input ─────────────────────────────────────────────────────────────────── +document.addEventListener("keydown", (e) => { + if (gameOver) + return; + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + togglePause(); + return; + } + if (paused) + return; + switch (e.key) { + case "ArrowLeft": { + const moved = Object.assign(Object.assign({}, current), { col: current.col - 1 }); + if (isValid(moved)) + current = moved; + break; + } + case "ArrowRight": { + const moved = Object.assign(Object.assign({}, current), { col: current.col + 1 }); + if (isValid(moved)) + current = moved; + break; + } + case "ArrowDown": { + const moved = Object.assign(Object.assign({}, current), { row: current.row + 1 }); + if (isValid(moved)) { + current = moved; + dropTimer = 0; // reset auto-drop timer + } + else { + lockPiece(); + } + break; + } + case "ArrowUp": + case "x": + case "X": { + // Rotate CW + const rotated = Object.assign(Object.assign({}, current), { rotation: (current.rotation + 1) % 4 }); + if (!tryWallKick(rotated, 1)) { + // no-op if all kicks fail + } + break; + } + case "z": + case "Z": { + // Rotate CCW + const rotated = Object.assign(Object.assign({}, current), { rotation: (current.rotation + 3) % 4 }); + tryWallKick(rotated, -1); + break; + } + case " ": { + // Hard drop + e.preventDefault(); + while (isValid(Object.assign(Object.assign({}, current), { row: current.row + 1 }))) + current.row++; + lockPiece(); + dropTimer = 0; + break; + } + } +}); +/** Try standard SRS wall-kick offsets; mutates current on success. Returns true if succeeded. */ +function tryWallKick(rotated, _dir) { + const kicks = [0, -1, 1, -2, 2]; + for (const offset of kicks) { + const candidate = Object.assign(Object.assign({}, rotated), { col: rotated.col + offset }); + if (isValid(candidate)) { + current = candidate; + return true; + } + } + return false; +} +// ─── Game Loop ─────────────────────────────────────────────────────────────── +function gameLoop(timestamp) { + if (!gameOver && !paused) { + const delta = timestamp - lastTimestamp; + lastTimestamp = timestamp; + dropTimer += delta; + if (dropTimer >= dropInterval()) { + dropTimer = 0; + const dropped = Object.assign(Object.assign({}, current), { row: current.row + 1 }); + if (isValid(dropped)) { + current = dropped; + } + else { + lockPiece(); + } + } + drawBoard(); + drawPreview(); + } + animFrameId = requestAnimationFrame(gameLoop); +} +// ─── Controls ──────────────────────────────────────────────────────────────── +function togglePause() { + if (gameOver) + return; + paused = !paused; + if (paused) { + showMessage("PAUSED"); + } + else { + hideMessage(); + lastTimestamp = performance.now(); + } +} +function startGame() { + board = createBoard(); + score = 0; + lines = 0; + level = 1; + gameOver = false; + paused = false; + dropTimer = 0; + current = randomPiece(); + next = randomPiece(); + updateHUD(); + hideMessage(); + startBtn.textContent = "Restart"; + if (animFrameId) + cancelAnimationFrame(animFrameId); + lastTimestamp = performance.now(); + animFrameId = requestAnimationFrame(gameLoop); +} +// ─── Bootstrap ─────────────────────────────────────────────────────────────── +startBtn.addEventListener("click", startGame); +// Initial idle draw +board = createBoard(); +score = 0; +lines = 0; +level = 1; +gameOver = true; +paused = false; +current = randomPiece(); +next = randomPiece(); +updateHUD(); +showMessage("Press Start"); +drawBoard(); +drawPreview(); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,443 @@ +"use strict"; +// ── Constants ────────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; +const COLORS = { + I: "#00cfcf", + O: "#cfcf00", + T: "#9f00cf", + S: "#00cf00", + Z: "#cf0000", + J: "#0000cf", + L: "#cf7f00", + ghost: "rgba(255,255,255,0.15)", + empty: "#111", +}; +// Each piece defined as rotations of [col, row] offsets from pivot +const PIECES = { + I: [ + [[0, 1], [1, 1], [2, 1], [3, 1]], + [[2, 0], [2, 1], [2, 2], [2, 3]], + [[0, 2], [1, 2], [2, 2], [3, 2]], + [[1, 0], [1, 1], [1, 2], [1, 3]], + ], + O: [ + [[1, 0], [2, 0], [1, 1], [2, 1]], + [[1, 0], [2, 0], [1, 1], [2, 1]], + [[1, 0], [2, 0], [1, 1], [2, 1]], + [[1, 0], [2, 0], [1, 1], [2, 1]], + ], + T: [ + [[1, 0], [0, 1], [1, 1], [2, 1]], + [[1, 0], [1, 1], [2, 1], [1, 2]], + [[0, 1], [1, 1], [2, 1], [1, 2]], + [[1, 0], [0, 1], [1, 1], [1, 2]], + ], + S: [ + [[1, 0], [2, 0], [0, 1], [1, 1]], + [[1, 0], [1, 1], [2, 1], [2, 2]], + [[1, 1], [2, 1], [0, 2], [1, 2]], + [[0, 0], [0, 1], [1, 1], [1, 2]], + ], + Z: [ + [[0, 0], [1, 0], [1, 1], [2, 1]], + [[2, 0], [1, 1], [2, 1], [1, 2]], + [[0, 1], [1, 1], [1, 2], [2, 2]], + [[1, 0], [0, 1], [1, 1], [0, 2]], + ], + J: [ + [[0, 0], [0, 1], [1, 1], [2, 1]], + [[1, 0], [2, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [2, 1], [2, 2]], + [[1, 0], [1, 1], [0, 2], [1, 2]], + ], + L: [ + [[2, 0], [0, 1], [1, 1], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 2]], + [[0, 1], [1, 1], [2, 1], [0, 2]], + [[0, 0], [1, 0], [1, 1], [1, 2]], + ], +}; +const PIECE_KEYS = Object.keys(PIECES); +// Wall-kick offsets for J,L,S,T,Z (index = rotation state * 4 + test) +const WALL_KICKS_JLSTZ = [ + [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], // 0->1 + [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], // 1->2 + [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], // 2->3 + [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], // 3->0 +]; +const WALL_KICKS_I = [ + [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], +]; +// ── Game State ───────────────────────────────────────────────────────────────── +let board; +let current; +let next; +let score; +let lines; +let level; +let gameOver; +let paused; +let dropInterval; +let lastTime; +let dropCounter; +let animationId; +// ── Canvas Setup ─────────────────────────────────────────────────────────────── +const canvas = document.getElementById("game"); +const nextCanvas = document.getElementById("next"); +const ctx = canvas.getContext("2d"); +const nextCtx = nextCanvas.getContext("2d"); +canvas.width = COLS * BLOCK; +canvas.height = ROWS * BLOCK; +nextCanvas.width = 4 * BLOCK; +nextCanvas.height = 4 * BLOCK; +// ── Helpers ──────────────────────────────────────────────────────────────────── +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function randomPiece() { + const type = PIECE_KEYS[Math.floor(Math.random() * PIECE_KEYS.length)]; + return { type, rotation: 0, x: 3, y: 0 }; +} +function getCells(piece) { + return PIECES[piece.type][piece.rotation].map(([dc, dr]) => [piece.x + dc, piece.y + dr]); +} +function isValid(piece, board) { + for (const [c, r] of getCells(piece)) { + if (c < 0 || c >= COLS || r >= ROWS) + return false; + if (r >= 0 && board[r][c] !== null) + return false; + } + return true; +} +function merge(piece, board) { + for (const [c, r] of getCells(piece)) { + if (r >= 0) + board[r][c] = piece.type; + } +} +function clearLines(board) { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every(cell => cell !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check same row index after splice + } + } + return cleared; +} +function calcScore(cleared, lvl) { + var _a; + const base = [0, 100, 300, 500, 800]; + return ((_a = base[cleared]) !== null && _a !== void 0 ? _a : 800) * (lvl + 1); +} +function ghostPiece(piece, board) { + const g = Object.assign({}, piece); + while (isValid(Object.assign(Object.assign({}, g), { y: g.y + 1 }), board)) + g.y++; + return g; +} +function tryRotate(piece, dir, board) { + const newRot = ((piece.rotation + dir) + 4) % 4; + const rotated = Object.assign(Object.assign({}, piece), { rotation: newRot }); + const kicks = piece.type === "I" ? WALL_KICKS_I : WALL_KICKS_JLSTZ; + const kickSet = kicks[piece.rotation + (dir === 1 ? 0 : (piece.rotation + 3) % 4)]; + // Simple approach: try each wall kick offset + const testsIndex = dir === 1 ? piece.rotation : newRot; + const tests = kicks[testsIndex]; + for (const [kx, ky] of tests) { + const candidate = Object.assign(Object.assign({}, rotated), { x: rotated.x + kx, y: rotated.y - ky }); + if (isValid(candidate, board)) + return candidate; + } + return null; +} +// ── Drawing ──────────────────────────────────────────────────────────────────── +function drawBlock(context, col, row, color, size = BLOCK) { + context.fillStyle = color; + context.fillRect(col * size + 1, row * size + 1, size - 2, size - 2); + // Highlight + context.fillStyle = "rgba(255,255,255,0.18)"; + context.fillRect(col * size + 1, row * size + 1, size - 2, 4); + context.fillRect(col * size + 1, row * size + 1, 4, size - 2); + // Shadow + context.fillStyle = "rgba(0,0,0,0.25)"; + context.fillRect(col * size + 1, row * size + size - 5, size - 2, 4); + context.fillRect(col * size + size - 5, row * size + 1, 4, size - 2); +} +function drawBoard() { + ctx.fillStyle = COLORS.empty; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + ctx.lineWidth = 1; + for (let c = 0; c < COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, canvas.height); + ctx.stroke(); + } + for (let r = 0; r < ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(canvas.width, r * BLOCK); + ctx.stroke(); + } + // Placed blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const cell = board[r][c]; + if (cell) + drawBlock(ctx, c, r, COLORS[cell]); + } + } +} +function drawPiece(piece, context, offX = 0, offY = 0, size = BLOCK, alpha = 1) { + context.globalAlpha = alpha; + for (const [c, r] of getCells(piece)) { + if (r >= 0) + drawBlock(context, c + offX, r + offY, COLORS[piece.type], size); + } + context.globalAlpha = 1; +} +function drawGhost() { + const g = ghostPiece(current, board); + for (const [c, r] of getCells(g)) { + if (r >= 0) { + ctx.fillStyle = COLORS.ghost; + ctx.strokeStyle = "rgba(255,255,255,0.3)"; + ctx.lineWidth = 1; + ctx.fillRect(c * BLOCK + 1, r * BLOCK + 1, BLOCK - 2, BLOCK - 2); + ctx.strokeRect(c * BLOCK + 1.5, r * BLOCK + 1.5, BLOCK - 3, BLOCK - 3); + } + } +} +function drawNext() { + nextCtx.fillStyle = "#1a1a2e"; + nextCtx.fillRect(0, 0, nextCanvas.width, nextCanvas.height); + const size = BLOCK * 0.85; + const offX = -next.x; + const offY = 0; + nextCtx.globalAlpha = 1; + for (const [c, r] of getCells(next)) { + const px = (c + offX) * size + (nextCanvas.width - 4 * size) / 2; + const py = (r + offY) * size + (nextCanvas.height - 4 * size) / 2; + nextCtx.fillStyle = COLORS[next.type]; + nextCtx.fillRect(px + 1, py + 1, size - 2, size - 2); + nextCtx.fillStyle = "rgba(255,255,255,0.18)"; + nextCtx.fillRect(px + 1, py + 1, size - 2, 4); + nextCtx.fillRect(px + 1, py + 1, 4, size - 2); + nextCtx.fillStyle = "rgba(0,0,0,0.25)"; + nextCtx.fillRect(px + 1, py + size - 5, size - 2, 4); + nextCtx.fillRect(px + size - 5, py + 1, 4, size - 2); + } +} +function updateHUD() { + document.getElementById("score").textContent = score.toString(); + document.getElementById("lines").textContent = lines.toString(); + document.getElementById("level").textContent = (level + 1).toString(); +} +function render() { + drawBoard(); + drawGhost(); + drawPiece(current, ctx); + drawNext(); + updateHUD(); + if (gameOver) { + ctx.fillStyle = "rgba(0,0,0,0.6)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px 'Segoe UI', sans-serif"; + ctx.textAlign = "center"; + ctx.fillText("GAME OVER", canvas.width / 2, canvas.height / 2 - 20); + ctx.font = "16px 'Segoe UI', sans-serif"; + ctx.fillText("Press R to restart", canvas.width / 2, canvas.height / 2 + 14); + ctx.textAlign = "left"; + } + else if (paused) { + ctx.fillStyle = "rgba(0,0,0,0.5)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px 'Segoe UI', sans-serif"; + ctx.textAlign = "center"; + ctx.fillText("PAUSED", canvas.width / 2, canvas.height / 2); + ctx.textAlign = "left"; + } +} +// ── Game Logic ───────────────────────────────────────────────────────────────── +function spawnPiece() { + current = next; + next = randomPiece(); + if (!isValid(current, board)) { + gameOver = true; + } +} +function lockPiece() { + merge(current, board); + const cleared = clearLines(board); + if (cleared > 0) { + score += calcScore(cleared, level); + lines += cleared; + level = Math.floor(lines / 10); + dropInterval = Math.max(100, 1000 - level * 90); + } + spawnPiece(); +} +function moveDown() { + if (gameOver || paused) + return; + const moved = Object.assign(Object.assign({}, current), { y: current.y + 1 }); + if (isValid(moved, board)) { + current = moved; + } + else { + lockPiece(); + } +} +function moveLeft() { + if (gameOver || paused) + return; + const moved = Object.assign(Object.assign({}, current), { x: current.x - 1 }); + if (isValid(moved, board)) + current = moved; +} +function moveRight() { + if (gameOver || paused) + return; + const moved = Object.assign(Object.assign({}, current), { x: current.x + 1 }); + if (isValid(moved, board)) + current = moved; +} +function rotate(dir) { + if (gameOver || paused) + return; + const rotated = tryRotate(current, dir, board); + if (rotated) + current = rotated; +} +function hardDrop() { + if (gameOver || paused) + return; + const g = ghostPiece(current, board); + score += (g.y - current.y) * 2; + current = g; + lockPiece(); +} +// ── Game Loop ────────────────────────────────────────────────────────────────── +function gameLoop(timestamp) { + const delta = timestamp - lastTime; + lastTime = timestamp; + if (!paused && !gameOver) { + dropCounter += delta; + if (dropCounter >= dropInterval) { + moveDown(); + dropCounter = 0; + } + } + render(); + if (!gameOver) { + animationId = requestAnimationFrame(gameLoop); + } + else { + render(); // draw game over overlay + } +} +// ── Init / Reset ─────────────────────────────────────────────────────────────── +function init() { + board = createBoard(); + score = 0; + lines = 0; + level = 0; + gameOver = false; + paused = false; + dropInterval = 1000; + dropCounter = 0; + lastTime = 0; + next = randomPiece(); + spawnPiece(); + if (animationId) + cancelAnimationFrame(animationId); + animationId = requestAnimationFrame((ts) => { + lastTime = ts; + gameLoop(ts); + }); +} +// ── Input ────────────────────────────────────────────────────────────────────── +let softDropActive = false; +let softDropTimer = null; +document.addEventListener("keydown", (e) => { + if (e.key === "r" || e.key === "R") { + init(); + return; + } + if (e.key === "p" || e.key === "P") { + if (!gameOver) { + paused = !paused; + if (!paused) { + lastTime = performance.now(); + animationId = requestAnimationFrame(gameLoop); + } + } + return; + } + if (gameOver || paused) + return; + switch (e.key) { + case "ArrowLeft": + e.preventDefault(); + moveLeft(); + break; + case "ArrowRight": + e.preventDefault(); + moveRight(); + break; + case "ArrowDown": + e.preventDefault(); + if (!softDropActive) { + softDropActive = true; + dropInterval = Math.max(50, dropInterval); + const fastDrop = () => { + moveDown(); + score += 1; + if (softDropActive) + softDropTimer = window.setTimeout(fastDrop, 50); + }; + fastDrop(); + } + break; + case "ArrowUp": + e.preventDefault(); + rotate(1); + break; + case "z": + case "Z": + rotate(-1); + break; + case "x": + case "X": + rotate(1); + break; + case " ": + e.preventDefault(); + hardDrop(); + break; + } +}); +document.addEventListener("keyup", (e) => { + if (e.key === "ArrowDown") { + softDropActive = false; + if (softDropTimer !== null) { + clearTimeout(softDropTimer); + softDropTimer = null; + } + } +}); +// ── Start ────────────────────────────────────────────────────────────────────── +init(); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=off_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,596 @@ +"use strict"; +// ============================================================= +// TETRIS – Full TypeScript implementation +// ============================================================= +// ── Constants ──────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell +// Bright neon palette +const COLORS = { + I: '#00F5FF', + O: '#FFE500', + T: '#CC00FF', + S: '#00E676', + Z: '#FF1744', + J: '#2979FF', + L: '#FF6D00', +}; +// Canonical spawning shapes (0° rotation) +const SHAPES = { + I: [[0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0]], + O: [[1, 1], + [1, 1]], + T: [[0, 1, 0], + [1, 1, 1], + [0, 0, 0]], + S: [[0, 1, 1], + [1, 1, 0], + [0, 0, 0]], + Z: [[1, 1, 0], + [0, 1, 1], + [0, 0, 0]], + J: [[1, 0, 0], + [1, 1, 1], + [0, 0, 0]], + L: [[0, 0, 1], + [1, 1, 1], + [0, 0, 0]], +}; +// Points awarded per lines-cleared, multiplied by current level +const LINE_POINTS = [0, 100, 300, 500, 800]; +// Drop interval in ms per level (index = level-1, capped at last entry) +const DROP_SPEED = [ + 800, 717, 633, 550, 467, 383, + 300, 217, 133, 100, 83, 67, + 50, 33, 17 +]; +// Wall-kick offsets tried when a rotation would be invalid +// Applies to J, L, S, T, Z (I uses its own) +const KICKS_JLSTZ = [[0, 0], [-1, 0], [1, 0], [0, -1], [-1, -1], [1, -1]]; +const KICKS_I = [[0, 0], [-1, 0], [-2, 0], [1, 0], [2, 0]]; +// ── Board helpers ──────────────────────────────────────────── +function makeBoard() { + return Array.from({ length: ROWS }, () => new Array(COLS).fill(null)); +} +function cloneShape(s) { + return s.map(row => [...row]); +} +/** Rotate shape 90° clockwise */ +function rotateCW(shape) { + const R = shape.length; + const C = shape[0].length; + const out = Array.from({ length: C }, () => new Array(R).fill(0)); + for (let r = 0; r < R; r++) + for (let c = 0; c < C; c++) + out[c][R - 1 - r] = shape[r][c]; + return out; +} +/** Rotate shape 90° counter-clockwise */ +function rotateCCW(shape) { + const R = shape.length; + const C = shape[0].length; + const out = Array.from({ length: C }, () => new Array(R).fill(0)); + for (let r = 0; r < R; r++) + for (let c = 0; c < C; c++) + out[C - 1 - c][r] = shape[r][c]; + return out; +} +// ── Piece factory ──────────────────────────────────────────── +const PIECE_KEYS = ['I', 'O', 'T', 'S', 'Z', 'J', 'L']; +// 7-bag randomiser +let bag = []; +function nextBagKey() { + if (bag.length === 0) { + bag = [...PIECE_KEYS].sort(() => Math.random() - 0.5); + } + return bag.pop(); +} +function spawnPiece(key) { + const shape = cloneShape(SHAPES[key]); + const x = Math.floor(COLS / 2) - Math.floor(shape[0].length / 2); + // I-piece and O-piece start higher to look natural + const y = key === 'I' ? -1 : 0; + return { key, shape, x, y }; +} +// ── Game class ─────────────────────────────────────────────── +class TetrisGame { + constructor() { + var _a; + // Game state + this.board = makeBoard(); + this.current = null; + this.next = nextBagKey(); + this.held = null; + this.canHold = true; + this.score = 0; + this.best = 0; + this.level = 1; + this.lines = 0; + this.state = 'idle'; + // Timing + this.rafId = 0; + this.lastTs = 0; + this.dropAccum = 0; // ms accumulated toward next automatic drop + // Lock-delay (piece sits still up to 500 ms before locking) + this.lockTimer = 0; + this.lockPending = false; + this.cvs = document.getElementById('game-canvas'); + this.ctx = this.cvs.getContext('2d'); + this.cvs.width = COLS * BLOCK; + this.cvs.height = ROWS * BLOCK; + this.nCvs = document.getElementById('next-canvas'); + this.nCtx = this.nCvs.getContext('2d'); + this.nCvs.width = 4 * BLOCK; + this.nCvs.height = 4 * BLOCK; + this.hCvs = document.getElementById('hold-canvas'); + this.hCtx = this.hCvs.getContext('2d'); + this.hCvs.width = 4 * BLOCK; + this.hCvs.height = 4 * BLOCK; + this.scoreEl = document.getElementById('score-value'); + this.bestEl = document.getElementById('best-value'); + this.levelEl = document.getElementById('level-value'); + this.linesEl = document.getElementById('lines-value'); + this.overlayEl = document.getElementById('overlay'); + this.overlayTitle = document.getElementById('overlay-title'); + this.overlayBody = document.getElementById('overlay-body'); + // Load best score from localStorage + this.best = parseInt((_a = localStorage.getItem('tetris-best')) !== null && _a !== void 0 ? _a : '0', 10); + this.bestEl.textContent = this.best.toString(); + this.showOverlay('TETRIS', 'Press <kbd>Enter</kbd> to play'); + this.bindInput(); + this.drawEmpty(); + } + // ── Input ────────────────────────────────────────────────── + bindInput() { + // DAS (Delayed Auto Shift) state + let dasDir = 0; + let dasTimer = 0; + let arrTimer = 0; + const DAS_DELAY = 150; // ms before auto-repeat starts + const ARR_RATE = 50; // ms between auto-repeat moves + document.addEventListener('keydown', (e) => { + // prevent page scroll on game keys + if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Space'].includes(e.code)) + e.preventDefault(); + if (e.repeat) + return; // handled by DAS below + switch (e.code) { + case 'Enter': + if (this.state === 'idle' || this.state === 'gameover') + this.startGame(); + else if (this.state === 'paused') + this.resume(); + break; + case 'KeyP': + case 'Escape': + if (this.state === 'playing') + this.pause(); + else if (this.state === 'paused') + this.resume(); + break; + case 'ArrowLeft': + this.tryMove(-1); + dasDir = -1; + dasTimer = 0; + arrTimer = 0; + break; + case 'ArrowRight': + this.tryMove(1); + dasDir = 1; + dasTimer = 0; + arrTimer = 0; + break; + case 'ArrowDown': + this.softDrop(); + break; + case 'ArrowUp': + case 'KeyX': + this.rotate(1); + break; + case 'KeyZ': + this.rotate(-1); + break; + case 'KeyA': + this.rotate(2); + break; // 180° flip + case 'Space': + this.hardDrop(); + break; + case 'KeyC': + case 'ShiftLeft': + case 'ShiftRight': + this.holdPiece(); + break; + } + }); + document.addEventListener('keyup', (e) => { + if (e.code === 'ArrowLeft' || e.code === 'ArrowRight') { + dasDir = 0; + } + }); + // DAS loop via rAF-independent interval + let prevDasTs = 0; + const dasLoop = (ts) => { + const dt = ts - prevDasTs; + prevDasTs = ts; + if (dasDir !== 0 && this.state === 'playing') { + dasTimer += dt; + if (dasTimer >= DAS_DELAY) { + arrTimer += dt; + while (arrTimer >= ARR_RATE) { + this.tryMove(dasDir); + arrTimer -= ARR_RATE; + } + } + } + requestAnimationFrame(dasLoop); + }; + requestAnimationFrame(dasLoop); + } + // ── Game flow ────────────────────────────────────────────── + startGame() { + this.board = makeBoard(); + this.score = 0; + this.level = 1; + this.lines = 0; + this.held = null; + this.canHold = true; + bag = []; // reset bag + this.next = nextBagKey(); + this.updateStats(); + this.drawHold(); + this.state = 'playing'; + this.dropAccum = 0; + this.lockTimer = 0; + this.lockPending = false; + this.hideOverlay(); + this.spawnNext(); + this.lastTs = performance.now(); + cancelAnimationFrame(this.rafId); + this.rafId = requestAnimationFrame((ts) => this.loop(ts)); + } + pause() { + if (this.state !== 'playing') + return; + this.state = 'paused'; + cancelAnimationFrame(this.rafId); + this.showOverlay('PAUSED', 'Press <kbd>Enter</kbd> or <kbd>P</kbd> to resume'); + } + resume() { + if (this.state !== 'paused') + return; + this.state = 'playing'; + this.hideOverlay(); + this.lastTs = performance.now(); + this.rafId = requestAnimationFrame((ts) => this.loop(ts)); + } + spawnNext() { + this.current = spawnPiece(this.next); + this.next = nextBagKey(); + this.canHold = true; + this.drawNextPiece(); + if (!this.valid(this.current.shape, this.current.x, this.current.y)) { + // Block-out game over + this.endGame(); + } + } + endGame() { + this.state = 'gameover'; + if (this.score > this.best) { + this.best = this.score; + localStorage.setItem('tetris-best', this.best.toString()); + this.bestEl.textContent = this.best.toString(); + } + cancelAnimationFrame(this.rafId); + this.showOverlay('GAME OVER', `Score: <strong>${this.score}</strong><br> + Level: <strong>${this.level}</strong><br> + Lines: <strong>${this.lines}</strong><br><br> + Press <kbd>Enter</kbd> to play again`); + } + // ── Main loop ────────────────────────────────────────────── + loop(ts) { + if (this.state !== 'playing') + return; + const dt = Math.min(ts - this.lastTs, 100); // cap at 100 ms + this.lastTs = ts; + this.dropAccum += dt; + const speed = DROP_SPEED[Math.min(this.level - 1, DROP_SPEED.length - 1)]; + if (this.dropAccum >= speed) { + this.dropAccum -= speed; + this.stepDown(); + } + // Lock-delay + if (this.lockPending) { + this.lockTimer += dt; + if (this.lockTimer >= 500) { + this.lock(); + } + } + this.render(); + this.rafId = requestAnimationFrame((ts2) => this.loop(ts2)); + } + stepDown() { + if (!this.current) + return; + if (this.valid(this.current.shape, this.current.x, this.current.y + 1)) { + this.current.y++; + this.lockPending = false; + this.lockTimer = 0; + } + else { + // Piece can't drop – start lock-delay + if (!this.lockPending) { + this.lockPending = true; + this.lockTimer = 0; + } + } + } + // ── Moves ────────────────────────────────────────────────── + tryMove(dx) { + if (this.state !== 'playing' || !this.current) + return; + if (this.valid(this.current.shape, this.current.x + dx, this.current.y)) { + this.current.x += dx; + // Reset lock-delay on successful lateral move (up to a limit handled by lockTimer cap) + if (this.lockPending) + this.lockTimer = Math.min(this.lockTimer, 450); + } + } + softDrop() { + if (this.state !== 'playing' || !this.current) + return; + if (this.valid(this.current.shape, this.current.x, this.current.y + 1)) { + this.current.y++; + this.score++; + this.updateStats(); + this.dropAccum = 0; + this.lockPending = false; + this.lockTimer = 0; + } + } + hardDrop() { + if (this.state !== 'playing' || !this.current) + return; + let dropped = 0; + while (this.valid(this.current.shape, this.current.x, this.current.y + 1)) { + this.current.y++; + dropped++; + } + this.score += dropped * 2; + this.updateStats(); + this.lock(); + } + rotate(times) { + if (this.state !== 'playing' || !this.current) + return; + let shape = this.current.shape; + const n = ((times % 4) + 4) % 4; + for (let i = 0; i < n; i++) + shape = rotateCW(shape); + const kicks = this.current.key === 'I' ? KICKS_I : KICKS_JLSTZ; + for (const [kx, ky] of kicks) { + const nx = this.current.x + kx; + const ny = this.current.y + ky; + if (this.valid(shape, nx, ny)) { + this.current.shape = shape; + this.current.x = nx; + this.current.y = ny; + // Reset lock timer on successful rotation + if (this.lockPending) + this.lockTimer = Math.min(this.lockTimer, 450); + return; + } + } + } + holdPiece() { + if (this.state !== 'playing' || !this.current || !this.canHold) + return; + const cur = this.current.key; + if (this.held === null) { + this.held = cur; + this.current = spawnPiece(this.next); + this.next = nextBagKey(); + this.drawNextPiece(); + } + else { + const prev = this.held; + this.held = cur; + this.current = spawnPiece(prev); + } + this.canHold = false; + this.lockPending = false; + this.lockTimer = 0; + this.drawHold(); + } + // ── Lock & line-clear ────────────────────────────────────── + lock() { + if (!this.current) + return; + const { key, shape, x, y } = this.current; + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c] && y + r >= 0) + this.board[y + r][x + c] = COLORS[key]; + this.current = null; + this.lockPending = false; + this.lockTimer = 0; + this.clearLines(); + this.spawnNext(); + } + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every(c => c !== null)) { + this.board.splice(r, 1); + this.board.unshift(new Array(COLS).fill(null)); + cleared++; + r++; // re-examine same index after splice + } + } + if (cleared === 0) + return; + this.lines += cleared; + this.score += LINE_POINTS[cleared] * this.level; + this.level = Math.floor(this.lines / 10) + 1; + this.updateStats(); + } + // ── Collision ────────────────────────────────────────────── + valid(shape, px, py) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = px + c; + const ny = py + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return false; + if (ny >= 0 && this.board[ny][nx] !== null) + return false; + } + } + return true; + } + // ── Ghost piece ──────────────────────────────────────────── + ghostY() { + if (!this.current) + return 0; + let gy = this.current.y; + while (this.valid(this.current.shape, this.current.x, gy + 1)) + gy++; + return gy; + } + // ── Rendering ────────────────────────────────────────────── + drawEmpty() { + this.ctx.fillStyle = '#0d0d1a'; + this.ctx.fillRect(0, 0, this.cvs.width, this.cvs.height); + this.drawGrid(); + } + render() { + const ctx = this.ctx; + ctx.fillStyle = '#0d0d1a'; + ctx.fillRect(0, 0, this.cvs.width, this.cvs.height); + this.drawGrid(); + this.drawBoard(); + if (this.current) { + this.drawGhost(); + this.drawPieceOnMain(this.current); + } + } + drawGrid() { + const ctx = this.ctx; + ctx.save(); + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, ROWS * BLOCK); + ctx.stroke(); + } + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(COLS * BLOCK, r * BLOCK); + ctx.stroke(); + } + ctx.restore(); + } + drawBoard() { + for (let r = 0; r < ROWS; r++) + for (let c = 0; c < COLS; c++) + if (this.board[r][c]) + this.drawBlock(this.ctx, c, r, this.board[r][c]); + } + drawGhost() { + if (!this.current) + return; + const gy = this.ghostY(); + if (gy === this.current.y) + return; // piece is already at bottom + const ctx = this.ctx; + ctx.save(); + ctx.globalAlpha = 0.20; + this.drawShapeAt(ctx, this.current.shape, this.current.x, gy, COLORS[this.current.key]); + ctx.restore(); + } + drawPieceOnMain(p) { + this.drawShapeAt(this.ctx, p.shape, p.x, p.y, COLORS[p.key]); + } + drawShapeAt(ctx, shape, px, py, color) { + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c]) + this.drawBlock(ctx, px + c, py + r, color); + } + drawBlock(ctx, col, row, color) { + const x = col * BLOCK; + const y = row * BLOCK; + const S = BLOCK; + const pad = 1; + // Base fill + ctx.fillStyle = color; + ctx.fillRect(x + pad, y + pad, S - pad * 2, S - pad * 2); + // Inner glow / highlight + const grad = ctx.createLinearGradient(x, y, x + S, y + S); + grad.addColorStop(0, 'rgba(255,255,255,0.30)'); + grad.addColorStop(1, 'rgba(0,0,0,0.25)'); + ctx.fillStyle = grad; + ctx.fillRect(x + pad, y + pad, S - pad * 2, S - pad * 2); + // Top-left bevel + ctx.fillStyle = 'rgba(255,255,255,0.22)'; + ctx.fillRect(x + pad, y + pad, S - pad * 2, 3); + ctx.fillRect(x + pad, y + pad, 3, S - pad * 2); + // Bottom-right bevel + ctx.fillStyle = 'rgba(0,0,0,0.30)'; + ctx.fillRect(x + pad, y + S - pad - 3, S - pad * 2, 3); + ctx.fillRect(x + S - pad - 3, y + pad, 3, S - pad * 2); + } + drawMiniPiece(ctx, canvas, key) { + ctx.fillStyle = '#0d0d1a'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + const shape = SHAPES[key]; + const cols = shape[0].length; + const rows = shape.length; + const ox = Math.floor((4 - cols) / 2); + const oy = Math.floor((4 - rows) / 2); + for (let r = 0; r < rows; r++) + for (let c = 0; c < cols; c++) + if (shape[r][c]) + this.drawBlock(ctx, ox + c, oy + r, COLORS[key]); + } + drawNextPiece() { + this.drawMiniPiece(this.nCtx, this.nCvs, this.next); + } + drawHold() { + if (this.held === null) { + this.hCtx.fillStyle = '#0d0d1a'; + this.hCtx.fillRect(0, 0, this.hCvs.width, this.hCvs.height); + return; + } + this.drawMiniPiece(this.hCtx, this.hCvs, this.held); + } + // ── UI helpers ───────────────────────────────────────────── + updateStats() { + this.scoreEl.textContent = this.score.toString(); + this.levelEl.textContent = this.level.toString(); + this.linesEl.textContent = this.lines.toString(); + if (this.score > this.best) { + this.best = this.score; + this.bestEl.textContent = this.best.toString(); + } + } + showOverlay(title, body) { + this.overlayTitle.textContent = title; + this.overlayBody.innerHTML = body; + this.overlayEl.style.display = 'flex'; + } + hideOverlay() { + this.overlayEl.style.display = 'none'; + } +} +// ── Bootstrap ──────────────────────────────────────────────── +window.addEventListener('DOMContentLoaded', () => { new TetrisGame(); }); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,429 @@ +"use strict"; +// ─── Constants ──────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell +const DAS_DELAY = 150; // ms before auto-shift kicks in +const DAS_RATE = 50; // ms between auto-shift steps +/** Piece colours indexed 1-7 (0 = empty) */ +const COLOURS = [ + '', + '#00d4d4', // 1 I cyan + '#e8d800', // 2 O yellow + '#cc44ff', // 3 T purple + '#44dd44', // 4 S green + '#ee3333', // 5 Z red + '#3366ff', // 6 J blue + '#ff8800', // 7 L orange +]; +/** + * Spawn shapes – all in square bounding boxes. + * Index 0 is a placeholder; pieces are 1-7. + */ +const SHAPES = [ + [], // 0 unused + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], // 1 I (4×4) + [[2, 2], [2, 2]], // 2 O (2×2) + [[0, 3, 0], [3, 3, 3], [0, 0, 0]], // 3 T (3×3) + [[0, 4, 4], [4, 4, 0], [0, 0, 0]], // 4 S + [[5, 5, 0], [0, 5, 5], [0, 0, 0]], // 5 Z + [[6, 0, 0], [6, 6, 6], [0, 0, 0]], // 6 J + [[0, 0, 7], [7, 7, 7], [0, 0, 0]], // 7 L +]; +/** Drop interval in ms per level (index = level, capped at last entry). */ +const SPEEDS = [ + 800, 717, 633, 550, 467, 383, 300, 217, 133, 100, + 83, 83, 83, 67, 67, 67, 50, 50, 50, 33, +]; +/** Points awarded for 1-4 simultaneous line clears × (level+1). */ +const LINE_SCORES = [0, 40, 100, 300, 1200]; +/** + * Wall-kick offsets [dx, dy] tried in order when rotating. + * Covers the most common SRS-like situations. + */ +const KICKS = [ + [0, 0], [-1, 0], [1, 0], [-2, 0], [2, 0], + [0, -1], [-1, -1], [1, -1], [0, -2], +]; +// ─── Pure helpers ───────────────────────────────────────────────────────────── +function makeBoard() { + return Array.from({ length: ROWS }, () => new Array(COLS).fill(0)); +} +function rotateCW(s) { + const R = s.length, C = s[0].length; + const out = Array.from({ length: C }, () => new Array(R).fill(0)); + for (let r = 0; r < R; r++) + for (let c = 0; c < C; c++) + out[c][R - 1 - r] = s[r][c]; + return out; +} +function rotateCCW(s) { + const R = s.length, C = s[0].length; + const out = Array.from({ length: C }, () => new Array(R).fill(0)); + for (let r = 0; r < R; r++) + for (let c = 0; c < C; c++) + out[C - 1 - c][r] = s[r][c]; + return out; +} +function dropSpeed(level) { + return SPEEDS[Math.min(level, SPEEDS.length - 1)]; +} +// ─── Game class ─────────────────────────────────────────────────────────────── +class Tetris { + constructor() { + // DAS (Delayed Auto Shift) + this.dasKey = null; + this.boardCanvas = document.getElementById('board'); + this.boardCtx = this.boardCanvas.getContext('2d'); + this.nextCanvas = document.getElementById('next'); + this.nextCtx = this.nextCanvas.getContext('2d'); + this.scoreEl = document.getElementById('score'); + this.linesEl = document.getElementById('lines'); + this.levelEl = document.getElementById('level'); + this.boardCanvas.width = COLS * BLOCK; + this.boardCanvas.height = ROWS * BLOCK; + this.nextCanvas.width = 4 * BLOCK; + this.nextCanvas.height = 4 * BLOCK; + document.addEventListener('keydown', this.onKeyDown.bind(this)); + document.addEventListener('keyup', this.onKeyUp.bind(this)); + this.reset(); + } + // ─── Initialisation ────────────────────────────────────────────────────── + reset() { + this.board = makeBoard(); + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + this.dropTimer = dropSpeed(0); + this.lastTime = 0; + this.dasKey = null; + this.dasTimer = 0; + this.next = this.newPiece(); + this.spawn(); // sets this.piece, draws next + this.updateUI(); + cancelAnimationFrame(this.rafId); + this.rafId = requestAnimationFrame(this.loop.bind(this)); + } + newPiece() { + const type = (Math.floor(Math.random() * 7) + 1); + const shape = SHAPES[type].map(row => [...row]); + return { + type, + shape, + x: Math.floor(COLS / 2) - Math.floor(shape[0].length / 2), + y: 0, + }; + } + /** Advance next→current, generate a new next, check game-over. */ + spawn() { + this.piece = this.next; + this.next = this.newPiece(); + this.renderNext(); + if (!this.valid(this.piece.shape, this.piece.x, this.piece.y)) { + this.gameOver = true; + } + } + // ─── Core mechanics ────────────────────────────────────────────────────── + valid(shape, px, py) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = px + c, ny = py + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return false; + if (ny >= 0 && this.board[ny][nx]) + return false; + } + } + return true; + } + lock() { + for (let r = 0; r < this.piece.shape.length; r++) { + for (let c = 0; c < this.piece.shape[r].length; c++) { + if (!this.piece.shape[r][c]) + continue; + const ny = this.piece.y + r; + if (ny < 0) { + this.gameOver = true; + return; + } + this.board[ny][this.piece.x + c] = this.piece.type; + } + } + this.clearLines(); + this.spawn(); + } + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every(v => v !== 0)) { + this.board.splice(r, 1); + this.board.unshift(new Array(COLS).fill(0)); + cleared++; + r++; // re-check the same index after splice + } + } + if (cleared > 0) { + this.score += LINE_SCORES[Math.min(cleared, 4)] * (this.level + 1); + this.lines += cleared; + this.level = Math.floor(this.lines / 10); + this.updateUI(); + } + } + ghostY() { + let gy = this.piece.y; + while (this.valid(this.piece.shape, this.piece.x, gy + 1)) + gy++; + return gy; + } + rotate(dir) { + const rotated = dir === 1 ? rotateCW(this.piece.shape) : rotateCCW(this.piece.shape); + for (const [dx, dy] of KICKS) { + const nx = this.piece.x + dx, ny = this.piece.y + dy; + if (this.valid(rotated, nx, ny)) { + this.piece.shape = rotated; + this.piece.x = nx; + this.piece.y = ny; + return; + } + } + } + shiftH(dx) { + if (this.valid(this.piece.shape, this.piece.x + dx, this.piece.y)) + this.piece.x += dx; + } + softDrop() { + if (this.valid(this.piece.shape, this.piece.x, this.piece.y + 1)) { + this.piece.y++; + this.score++; + this.dropTimer = dropSpeed(this.level); + this.updateUI(); + } + else { + this.lock(); + } + } + hardDrop() { + const gy = this.ghostY(); + const dist = gy - this.piece.y; + this.piece.y = gy; + this.score += dist * 2; + this.updateUI(); + this.lock(); + } + // ─── Input ─────────────────────────────────────────────────────────────── + onKeyDown(e) { + if (e.key === 'r' || e.key === 'R') { + this.reset(); + return; + } + if (this.gameOver || this.paused) { + if ((e.key === 'p' || e.key === 'P') && !this.gameOver) { + this.togglePause(); + } + return; + } + switch (e.key) { + case 'ArrowLeft': + e.preventDefault(); + this.shiftH(-1); + if (this.dasKey !== 'ArrowLeft') { + this.dasKey = 'ArrowLeft'; + this.dasPhase = 'delay'; + this.dasTimer = DAS_DELAY; + } + break; + case 'ArrowRight': + e.preventDefault(); + this.shiftH(1); + if (this.dasKey !== 'ArrowRight') { + this.dasKey = 'ArrowRight'; + this.dasPhase = 'delay'; + this.dasTimer = DAS_DELAY; + } + break; + case 'ArrowDown': + e.preventDefault(); + this.softDrop(); + break; + case 'ArrowUp': + case 'x': + case 'X': + e.preventDefault(); + this.rotate(1); + break; + case 'z': + case 'Z': + e.preventDefault(); + this.rotate(-1); + break; + case ' ': + e.preventDefault(); + this.hardDrop(); + break; + case 'p': + case 'P': + e.preventDefault(); + this.togglePause(); + break; + } + } + onKeyUp(e) { + if (e.key === this.dasKey) + this.dasKey = null; + } + togglePause() { + this.paused = !this.paused; + if (!this.paused) + this.lastTime = 0; // reset timing so no instant drop on resume + } + // ─── Game loop ─────────────────────────────────────────────────────────── + loop(time) { + // First frame: initialise lastTime without advancing anything + if (this.lastTime === 0) + this.lastTime = time; + const dt = time - this.lastTime; + this.lastTime = time; + if (!this.paused && !this.gameOver) { + // Auto-drop + this.dropTimer -= dt; + if (this.dropTimer <= 0) { + if (this.valid(this.piece.shape, this.piece.x, this.piece.y + 1)) { + this.piece.y++; + } + else { + this.lock(); + } + this.dropTimer = dropSpeed(this.level); + } + // DAS + if (this.dasKey) { + this.dasTimer -= dt; + if (this.dasTimer <= 0) { + this.shiftH(this.dasKey === 'ArrowLeft' ? -1 : 1); + this.dasPhase = 'repeat'; + this.dasTimer = DAS_RATE; + } + } + } + this.render(); + this.rafId = requestAnimationFrame(this.loop.bind(this)); + } + // ─── Rendering ─────────────────────────────────────────────────────────── + render() { + const ctx = this.boardCtx; + const W = this.boardCanvas.width; + const H = this.boardCanvas.height; + // Background + ctx.fillStyle = '#0a0a18'; + ctx.fillRect(0, 0, W, H); + // Subtle grid + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(W, r * BLOCK); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, H); + ctx.stroke(); + } + // Locked board cells + for (let r = 0; r < ROWS; r++) + for (let c = 0; c < COLS; c++) + if (this.board[r][c]) + this.drawBlock(ctx, c, r, COLOURS[this.board[r][c]]); + // Ghost piece + if (!this.gameOver && !this.paused) { + const gy = this.ghostY(); + if (gy !== this.piece.y) { + for (let r = 0; r < this.piece.shape.length; r++) + for (let c = 0; c < this.piece.shape[r].length; c++) + if (this.piece.shape[r][c]) + this.drawGhost(ctx, this.piece.x + c, gy + r, COLOURS[this.piece.type]); + } + } + // Active piece + if (!this.gameOver) { + for (let r = 0; r < this.piece.shape.length; r++) + for (let c = 0; c < this.piece.shape[r].length; c++) + if (this.piece.shape[r][c]) + this.drawBlock(ctx, this.piece.x + c, this.piece.y + r, COLOURS[this.piece.type]); + } + // Pause overlay + if (this.paused) { + ctx.fillStyle = 'rgba(0,0,0,0.60)'; + ctx.fillRect(0, 0, W, H); + ctx.textAlign = 'center'; + ctx.fillStyle = '#ffffff'; + ctx.font = `bold 30px 'Courier New', monospace`; + ctx.fillText('PAUSED', W / 2, H / 2 - 18); + ctx.font = `14px 'Courier New', monospace`; + ctx.fillStyle = '#aaaaaa'; + ctx.fillText('Press P to continue', W / 2, H / 2 + 14); + } + // Game-over overlay + if (this.gameOver) { + ctx.fillStyle = 'rgba(0,0,0,0.72)'; + ctx.fillRect(0, 0, W, H); + ctx.textAlign = 'center'; + ctx.fillStyle = '#ff4444'; + ctx.font = `bold 30px 'Courier New', monospace`; + ctx.fillText('GAME OVER', W / 2, H / 2 - 22); + ctx.fillStyle = '#aaaaaa'; + ctx.font = `14px 'Courier New', monospace`; + ctx.fillText(`Score: ${this.score}`, W / 2, H / 2 + 10); + ctx.fillText('Press R to restart', W / 2, H / 2 + 34); + } + } + drawBlock(ctx, col, row, colour) { + const x = col * BLOCK, y = row * BLOCK, s = BLOCK, p = 1; + // Main face + ctx.fillStyle = colour; + ctx.fillRect(x + p, y + p, s - p * 2, s - p * 2); + // Top-left highlight + ctx.fillStyle = 'rgba(255,255,255,0.28)'; + ctx.fillRect(x + p, y + p, s - p * 2, 4); + ctx.fillRect(x + p, y + p, 4, s - p * 2); + // Bottom-right shadow + ctx.fillStyle = 'rgba(0,0,0,0.28)'; + ctx.fillRect(x + p, y + s - p - 4, s - p * 2, 4); + ctx.fillRect(x + s - p - 4, y + p, 4, s - p * 2); + } + drawGhost(ctx, col, row, colour) { + const x = col * BLOCK, y = row * BLOCK, s = BLOCK; + ctx.save(); + ctx.globalAlpha = 0.28; + ctx.strokeStyle = colour; + ctx.lineWidth = 2; + ctx.strokeRect(x + 2, y + 2, s - 4, s - 4); + ctx.restore(); + } + renderNext() { + const ctx = this.nextCtx; + ctx.fillStyle = '#0a0a18'; + ctx.fillRect(0, 0, this.nextCanvas.width, this.nextCanvas.height); + const shape = this.next.shape; + const ox = Math.floor((4 - shape[0].length) / 2); + const oy = Math.floor((4 - shape.length) / 2); + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c]) + this.drawBlock(ctx, ox + c, oy + r, COLOURS[this.next.type]); + } + // ─── UI ────────────────────────────────────────────────────────────────── + updateUI() { + this.scoreEl.textContent = String(this.score).padStart(7, '0'); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + } +} +// ─── Boot ───────────────────────────────────────────────────────────────────── +new Tetris(); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,566 @@ +"use strict"; +// ============================================================ +// Tetris — complete browser implementation in TypeScript +// ============================================================ +// ── Constants ──────────────────────────────────────────────── +const BOARD_COLS = 10; +const BOARD_ROWS = 20; +const BLOCK_SIZE = 30; // px per cell on the main board +const PREVIEW_BLOCK = 26; // px per cell in the next-piece box +// ── Piece definitions ──────────────────────────────────────── +const PIECE_COLORS = { + I: '#00cfcf', + O: '#cfcf00', + T: '#9900cf', + S: '#00cf00', + Z: '#cf0000', + J: '#0000cf', + L: '#cf7f00', +}; +// Each piece has 4 rotation states stored as 2-D arrays of 0/1. +const PIECE_SHAPES = { + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + O: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +const PIECE_TYPES = ['I', 'O', 'T', 'S', 'Z', 'J', 'L']; +// ── Scoring tables ─────────────────────────────────────────── +// Points awarded per line-clear count (multiplied by level) +const LINE_SCORES = [0, 100, 300, 500, 800]; +// Drop interval in ms per level (index 0 = level 1) +const DROP_INTERVALS = [ + 800, 717, 633, 550, 467, 383, + 300, 217, 133, 100, 83, 83, + 83, 67, 67, 67, 50, 50, + 50, 50, 33, +]; +function dropInterval(level) { + const idx = Math.min(level - 1, DROP_INTERVALS.length - 1); + return DROP_INTERVALS[idx]; +} +// ── Random bag (7-bag randomiser) ──────────────────────────── +class Bag { + constructor() { + this.bag = []; + } + next() { + if (this.bag.length === 0) + this.refill(); + return this.bag.pop(); + } + refill() { + this.bag = [...PIECE_TYPES]; + // Fisher-Yates shuffle + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } +} +// ── Game logic ─────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameOver = false; + this.paused = false; + this.started = false; + this.bag = new Bag(); + this.board = this.emptyBoard(); + this.next = this.bag.next(); + this.current = this.spawn(); + } + // ── Helpers ──────────────────────────────────────────────── + emptyBoard() { + return Array.from({ length: BOARD_ROWS }, () => Array(BOARD_COLS).fill(null)); + } + spawn() { + const type = this.next; + this.next = this.bag.next(); + const shape = PIECE_SHAPES[type][0]; + const x = Math.floor((BOARD_COLS - shape[0].length) / 2); + return { type, rotation: 0, x, y: 0 }; + } + shape(piece = this.current) { + return PIECE_SHAPES[piece.type][piece.rotation]; + } + // Returns true if 'piece' (optionally with dx/dy offset) fits on the board. + isValid(piece, dx = 0, dy = 0) { + const s = this.shape(piece); + const nx = piece.x + dx; + const ny = piece.y + dy; + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const bx = nx + c; + const by = ny + r; + if (by < 0) + continue; // above board ← OK + if (bx < 0 || bx >= BOARD_COLS) + return false; + if (by >= BOARD_ROWS) + return false; + if (this.board[by][bx] !== null) + return false; + } + } + return true; + } + // ── Ghost ────────────────────────────────────────────────── + ghostY() { + let gy = this.current.y; + while (this.isValid(Object.assign(Object.assign({}, this.current), { y: gy + 1 }))) + gy++; + return gy; + } + // ── Player actions ───────────────────────────────────────── + moveLeft() { if (this.isValid(this.current, -1, 0)) { + this.current.x--; + return true; + } return false; } + moveRight() { if (this.isValid(this.current, 1, 0)) { + this.current.x++; + return true; + } return false; } + softDrop() { + if (this.isValid(this.current, 0, 1)) { + this.current.y++; + this.score += 1; + return true; + } + return false; + } + rotate(dir) { + const newRot = ((this.current.rotation + dir) + 4) % 4; + const rotated = Object.assign(Object.assign({}, this.current), { rotation: newRot }); + // Wall-kick attempts: 0, ±1, ±2 columns + for (const kick of [0, 1, -1, 2, -2]) { + if (this.isValid(Object.assign(Object.assign({}, rotated), { x: rotated.x + kick }))) { + this.current = Object.assign(Object.assign({}, rotated), { x: rotated.x + kick }); + return; + } + } + } + hardDrop() { + const cells = this.current.y; + this.current = Object.assign(Object.assign({}, this.current), { y: this.ghostY() }); + this.score += (this.current.y - cells) * 2; + this.lock(); + } + // ── Internal ─────────────────────────────────────────────── + tick() { + if (!this.isValid(this.current, 0, 1)) { + this.lock(); + } + else { + this.current.y++; + } + } + lock() { + const s = this.shape(); + const color = PIECE_COLORS[this.current.type]; + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const bx = this.current.x + c; + const by = this.current.y + r; + if (by < 0) { + this.gameOver = true; + return; + } + this.board[by][bx] = color; + } + } + const cleared = this.clearLines(); + if (cleared > 0) { + this.score += LINE_SCORES[Math.min(cleared, 4)] * this.level; + this.lines += cleared; + this.level = Math.floor(this.lines / 10) + 1; + } + this.current = this.spawn(); + if (!this.isValid(this.current)) + this.gameOver = true; + } + clearLines() { + let cleared = 0; + for (let r = BOARD_ROWS - 1; r >= 0; r--) { + if (this.board[r].every(cell => cell !== null)) { + this.board.splice(r, 1); + this.board.unshift(Array(BOARD_COLS).fill(null)); + cleared++; + r++; // recheck this index + } + } + return cleared; + } + // ── Reset ────────────────────────────────────────────────── + reset() { + this.bag = new Bag(); + this.board = this.emptyBoard(); + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameOver = false; + this.paused = false; + this.started = true; + this.next = this.bag.next(); + this.current = this.spawn(); + } +} +// ── Renderer ───────────────────────────────────────────────── +class TetrisRenderer { + constructor() { + this.gameCanvas = document.getElementById('game-canvas'); + this.nextCanvas = document.getElementById('next-canvas'); + this.scoreEl = document.getElementById('score-val'); + this.levelEl = document.getElementById('level-val'); + this.linesEl = document.getElementById('lines-val'); + this.overlay = document.getElementById('overlay'); + this.gameCtx = this.gameCanvas.getContext('2d'); + this.nextCtx = this.nextCanvas.getContext('2d'); + this.gameCanvas.width = BOARD_COLS * BLOCK_SIZE; + this.gameCanvas.height = BOARD_ROWS * BLOCK_SIZE; + this.nextCanvas.width = 4 * PREVIEW_BLOCK; + this.nextCanvas.height = 4 * PREVIEW_BLOCK; + } + // Draw a single block at grid coords (gx, gy) in the given canvas + drawBlock(ctx, gx, gy, color, sz, alpha = 1) { + const px = gx * sz; + const py = gy * sz; + const s = sz - 1; + ctx.globalAlpha = alpha; + // Base fill + ctx.fillStyle = color; + ctx.fillRect(px, py, s, s); + // Inner highlight (top-left bevel) + ctx.fillStyle = 'rgba(255,255,255,0.35)'; + ctx.fillRect(px, py, s, 3); + ctx.fillRect(px, py, 3, s); + // Inner shadow (bottom-right bevel) + ctx.fillStyle = 'rgba(0,0,0,0.35)'; + ctx.fillRect(px, py + s - 3, s, 3); + ctx.fillRect(px + s - 3, py, 3, s); + ctx.globalAlpha = 1; + } + render(game) { + this.drawBoard(game); + this.drawNextPiece(game); + this.scoreEl.textContent = game.score.toLocaleString(); + this.levelEl.textContent = String(game.level); + this.linesEl.textContent = String(game.lines); + this.updateOverlay(game); + } + drawBoard(game) { + const ctx = this.gameCtx; + const W = this.gameCanvas.width; + const H = this.gameCanvas.height; + const sz = BLOCK_SIZE; + // Background + ctx.fillStyle = '#0d0d1a'; + ctx.fillRect(0, 0, W, H); + // Subtle grid lines + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let c = 0; c <= BOARD_COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * sz, 0); + ctx.lineTo(c * sz, H); + ctx.stroke(); + } + for (let r = 0; r <= BOARD_ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * sz); + ctx.lineTo(W, r * sz); + ctx.stroke(); + } + // Locked board cells + for (let r = 0; r < BOARD_ROWS; r++) { + for (let c = 0; c < BOARD_COLS; c++) { + const color = game.board[r][c]; + if (color) + this.drawBlock(ctx, c, r, color, sz); + } + } + if (!game.started || game.gameOver || game.paused) + return; + const s = game.shape(); + const color = PIECE_COLORS[game.current.type]; + // Ghost piece + const gy = game.ghostY(); + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const bx = game.current.x + c; + const by = gy + r; + if (by >= 0 && by < BOARD_ROWS) { + this.drawBlock(ctx, bx, by, color, sz, 0.22); + } + } + } + // Active piece + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const bx = game.current.x + c; + const by = game.current.y + r; + if (by >= 0 && by < BOARD_ROWS) { + this.drawBlock(ctx, bx, by, color, sz); + } + } + } + } + drawNextPiece(game) { + const ctx = this.nextCtx; + const W = this.nextCanvas.width; + const H = this.nextCanvas.height; + const sz = PREVIEW_BLOCK; + ctx.fillStyle = '#0d0d1a'; + ctx.fillRect(0, 0, W, H); + if (!game.started) + return; + const s = PIECE_SHAPES[game.next][0]; + const color = PIECE_COLORS[game.next]; + const ox = Math.floor((4 - s[0].length) / 2); + const oy = Math.floor((4 - s.length) / 2); + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (s[r][c]) + this.drawBlock(ctx, ox + c, oy + r, color, sz); + } + } + } + updateOverlay(game) { + if (!game.started) { + this.overlay.innerHTML = + '<h2>TETRIS</h2>' + + '<p>Press <kbd>Enter</kbd> to start</p>' + + '<div class="controls-hint">' + + '<span>← → Move</span>' + + '<span>↑ / X Rotate CW</span>' + + '<span>Z Rotate CCW</span>' + + '<span>↓ Soft drop</span>' + + '<span>Space Hard drop</span>' + + '<span>P Pause</span>' + + '</div>'; + this.overlay.style.display = 'flex'; + } + else if (game.gameOver) { + this.overlay.innerHTML = + '<h2>GAME OVER</h2>' + + `<p class="final-score">Score: ${game.score.toLocaleString()}</p>` + + '<p>Press <kbd>Enter</kbd> to play again</p>'; + this.overlay.style.display = 'flex'; + } + else if (game.paused) { + this.overlay.innerHTML = + '<h2>PAUSED</h2>' + + '<p>Press <kbd>P</kbd> or <kbd>Enter</kbd> to resume</p>'; + this.overlay.style.display = 'flex'; + } + else { + this.overlay.style.display = 'none'; + } + } +} +// ── Controller ─────────────────────────────────────────────── +class TetrisController { + constructor() { + // Game-loop timing + this.lastTime = 0; + this.dropAcc = 0; // accumulates time toward next gravity tick + this.softAcc = 0; // accumulates time toward next soft-drop tick + // DAS (Delayed Auto Shift) state + this.DAS = 160; // ms before auto-repeat begins + this.ARR = 50; // ms per auto-repeat step + this.dasLeft = false; + this.dasRight = false; + this.dasTimerLeft = 0; + this.dasTimerRight = 0; + // Keys currently held + this.keysHeld = new Set(); + this.game = new TetrisGame(); + this.renderer = new TetrisRenderer(); + document.addEventListener('keydown', e => this.onKeyDown(e)); + document.addEventListener('keyup', e => this.onKeyUp(e)); + this.renderer.render(this.game); + requestAnimationFrame(t => this.loop(t)); + } + onKeyDown(e) { + // Prevent arrow keys + space from scrolling the page + if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', ' '].includes(e.key)) { + e.preventDefault(); + } + if (e.repeat) + return; // We handle repetition ourselves via DAS + this.keysHeld.add(e.key); + const { game } = this; + const active = game.started && !game.gameOver && !game.paused; + switch (e.key) { + // Start / restart / pause + case 'Enter': + if (!game.started || game.gameOver) { + game.reset(); + this.dropAcc = 0; + } + else { + game.paused = !game.paused; + } + break; + case 'p': + case 'P': + if (game.started && !game.gameOver) + game.paused = !game.paused; + break; + // Movement (first press — DAS handles subsequent) + case 'ArrowLeft': + if (active) { + game.moveLeft(); + this.dasLeft = true; + this.dasTimerLeft = 0; + } + break; + case 'ArrowRight': + if (active) { + game.moveRight(); + this.dasRight = true; + this.dasTimerRight = 0; + } + break; + // Rotation + case 'ArrowUp': + case 'x': + case 'X': + if (active) + game.rotate(1); + break; + case 'z': + case 'Z': + if (active) + game.rotate(-1); + break; + // Hard drop + case ' ': + if (active) { + game.hardDrop(); + this.dropAcc = 0; + } + break; + } + } + onKeyUp(e) { + this.keysHeld.delete(e.key); + if (e.key === 'ArrowLeft') { + this.dasLeft = false; + this.dasTimerLeft = 0; + } + if (e.key === 'ArrowRight') { + this.dasRight = false; + this.dasTimerRight = 0; + } + } + loop(timestamp) { + const delta = Math.min(timestamp - this.lastTime, 100); // cap at 100 ms + this.lastTime = timestamp; + const { game } = this; + const active = game.started && !game.gameOver && !game.paused; + if (active) { + // ── DAS for left ── + if (this.dasLeft) { + this.dasTimerLeft += delta; + if (this.dasTimerLeft >= this.DAS) { + // How many ARR steps have elapsed beyond the DAS threshold? + // Use Math.max(0, ...) so negatives don't trigger a spurious step. + const timeSinceDas = this.dasTimerLeft - this.DAS; + const prevSinceDas = Math.max(0, this.dasTimerLeft - delta - this.DAS); + const steps = Math.floor(timeSinceDas / this.ARR); + const prevSteps = Math.floor(prevSinceDas / this.ARR); + if (steps > prevSteps) + game.moveLeft(); + } + } + // ── DAS for right ── + if (this.dasRight) { + this.dasTimerRight += delta; + if (this.dasTimerRight >= this.DAS) { + const timeSinceDas = this.dasTimerRight - this.DAS; + const prevSinceDas = Math.max(0, this.dasTimerRight - delta - this.DAS); + const steps = Math.floor(timeSinceDas / this.ARR); + const prevSteps = Math.floor(prevSinceDas / this.ARR); + if (steps > prevSteps) + game.moveRight(); + } + } + // ── Soft drop (down arrow held) ── + const softDropping = this.keysHeld.has('ArrowDown'); + if (softDropping) { + this.softAcc += delta; + const softInterval = Math.min(dropInterval(game.level) / 20, 50); + while (this.softAcc >= softInterval) { + game.softDrop(); + this.softAcc -= softInterval; + this.dropAcc = 0; // reset gravity so it doesn't double-advance + } + } + else { + this.softAcc = 0; + } + // ── Gravity ── + this.dropAcc += delta; + const interval = dropInterval(game.level); + while (this.dropAcc >= interval) { + game.tick(); + this.dropAcc -= interval; + } + } + this.renderer.render(game); + requestAnimationFrame(t => this.loop(t)); + } +} +// ── Bootstrap ──────────────────────────────────────────────── +window.addEventListener('DOMContentLoaded', () => { + new TetrisController(); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=off_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,430 @@ +"use strict"; +// ============================================================ +// Tetris – fully playable browser implementation in TypeScript +// ============================================================ +// ── Constants ──────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell +const PREVIEW_BLOCK = 25; // px per cell in next-piece panel +// Scoring (Tetris guideline points) +const SCORE_TABLE = [0, 100, 300, 500, 800]; // 0–4 lines +// Speed: interval in ms for one gravity tick at each level +function levelInterval(level) { + return Math.max(50, 1000 - (level - 1) * 90); +} +const PIECES = [ + // I + { + color: '#00f0f0', + shapes: [ + [[1, 0], [1, 1], [1, 2], [1, 3]], + [[0, 2], [1, 2], [2, 2], [3, 2]], + [[2, 0], [2, 1], [2, 2], [2, 3]], + [[0, 1], [1, 1], [2, 1], [3, 1]], + ], + }, + // O + { + color: '#f0f000', + shapes: [ + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + ], + }, + // T + { + color: '#a000f0', + shapes: [ + [[0, 1], [1, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [1, 2], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 1]], + [[0, 1], [1, 0], [1, 1], [2, 1]], + ], + }, + // S + { + color: '#00f000', + shapes: [ + [[0, 1], [0, 2], [1, 0], [1, 1]], + [[0, 1], [1, 1], [1, 2], [2, 2]], + [[1, 1], [1, 2], [2, 0], [2, 1]], + [[0, 0], [1, 0], [1, 1], [2, 1]], + ], + }, + // Z + { + color: '#f00000', + shapes: [ + [[0, 0], [0, 1], [1, 1], [1, 2]], + [[0, 2], [1, 1], [1, 2], [2, 1]], + [[1, 0], [1, 1], [2, 1], [2, 2]], + [[0, 1], [1, 0], [1, 1], [2, 0]], + ], + }, + // J + { + color: '#0000f0', + shapes: [ + [[0, 0], [1, 0], [1, 1], [1, 2]], + [[0, 1], [0, 2], [1, 1], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 2]], + [[0, 1], [1, 1], [2, 0], [2, 1]], + ], + }, + // L + { + color: '#f0a000', + shapes: [ + [[0, 2], [1, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [2, 1], [2, 2]], + [[1, 0], [1, 1], [1, 2], [2, 0]], + [[0, 0], [0, 1], [1, 1], [2, 1]], + ], + }, +]; +function emptyBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function cells(p) { + return PIECES[p.pieceIndex].shapes[p.rotation].map(([r, c]) => [r + p.row, c + p.col]); +} +function isValid(board, p) { + for (const [r, c] of cells(p)) { + if (r < 0 || r >= ROWS || c < 0 || c >= COLS) + return false; + if (board[r][c] !== null) + return false; + } + return true; +} +// ── Game class ─────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.board = emptyBoard(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.dropTimer = 0; + this.lastTime = 0; + this.animId = 0; + // Soft-drop tracking + this.softDrop = false; + this.canvas = document.getElementById('board'); + this.ctx = this.canvas.getContext('2d'); + this.nextCanvas = document.getElementById('next'); + this.nextCtx = this.nextCanvas.getContext('2d'); + this.scoreEl = document.getElementById('score'); + this.linesEl = document.getElementById('lines'); + this.levelEl = document.getElementById('level'); + this.messageEl = document.getElementById('message'); + this.canvas.width = COLS * BLOCK; + this.canvas.height = ROWS * BLOCK; + this.nextCanvas.width = 4 * PREVIEW_BLOCK; + this.nextCanvas.height = 4 * PREVIEW_BLOCK; + this.bindKeys(); + this.reset(); + } + // ── Reset / start ────────────────────────────────────────── + reset() { + this.board = emptyBoard(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.dropTimer = 0; + this.lastTime = 0; + this.messageEl.textContent = ''; + this.next = this.randomPiece(); + this.spawn(); + this.updateHUD(); + cancelAnimationFrame(this.animId); + this.animId = requestAnimationFrame(ts => this.loop(ts)); + } + randomPiece() { + return Math.floor(Math.random() * PIECES.length); + } + spawn() { + const idx = this.next; + this.next = this.randomPiece(); + this.active = { + pieceIndex: idx, + rotation: 0, + row: 0, + col: Math.floor((COLS - 4) / 2), // center in 10-wide board + }; + if (!isValid(this.board, this.active)) { + this.gameOver = true; + this.messageEl.textContent = 'GAME OVER'; + } + this.drawNext(); + } + // ── Main loop ────────────────────────────────────────────── + loop(timestamp) { + if (this.gameOver) { + this.draw(); + return; + } + const delta = timestamp - this.lastTime; + this.lastTime = timestamp; + if (!this.paused) { + const interval = this.softDrop + ? Math.min(50, levelInterval(this.level) / 10) + : levelInterval(this.level); + this.dropTimer += delta; + if (this.dropTimer >= interval) { + this.dropTimer = 0; + this.gravityDrop(); + } + } + this.draw(); + this.animId = requestAnimationFrame(ts => this.loop(ts)); + } + // ── Gravity ──────────────────────────────────────────────── + gravityDrop() { + const moved = { ...this.active, row: this.active.row + 1 }; + if (isValid(this.board, moved)) { + this.active = moved; + } + else { + this.lock(); + } + } + lock() { + const color = PIECES[this.active.pieceIndex].color; + for (const [r, c] of cells(this.active)) { + if (r >= 0) + this.board[r][c] = color; + } + const cleared = this.clearLines(); + this.addScore(cleared); + this.spawn(); + } + clearLines() { + let count = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every(c => c !== null)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(null)); + count++; + r++; // re-check same row index + } + } + return count; + } + addScore(cleared) { + if (cleared === 0) + return; + this.score += SCORE_TABLE[cleared] * this.level; + this.lines += cleared; + this.level = Math.floor(this.lines / 10) + 1; + this.updateHUD(); + } + updateHUD() { + this.scoreEl.textContent = String(this.score); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + } + // ── Controls ─────────────────────────────────────────────── + bindKeys() { + document.addEventListener('keydown', e => { + if (e.repeat && ['ArrowLeft', 'ArrowRight', 'ArrowDown'].includes(e.key)) { + // allow repeats for movement + } + else if (e.repeat) { + return; + } + if (this.gameOver) { + if (e.key === 'Enter' || e.key === ' ') + this.reset(); + return; + } + switch (e.key) { + case 'ArrowLeft': + e.preventDefault(); + this.move(0, -1); + break; + case 'ArrowRight': + e.preventDefault(); + this.move(0, 1); + break; + case 'ArrowDown': + e.preventDefault(); + this.softDrop = true; + this.dropTimer = 9999; // force immediate drop + break; + case 'ArrowUp': + e.preventDefault(); + this.rotate(1); + break; + case 'z': + case 'Z': + e.preventDefault(); + this.rotate(-1); + break; + case ' ': + e.preventDefault(); + this.hardDrop(); + break; + case 'p': + case 'P': + this.togglePause(); + break; + } + }); + document.addEventListener('keyup', e => { + if (e.key === 'ArrowDown') { + this.softDrop = false; + this.dropTimer = 0; + } + }); + } + move(dr, dc) { + if (this.paused || this.gameOver) + return; + const moved = { ...this.active, row: this.active.row + dr, col: this.active.col + dc }; + if (isValid(this.board, moved)) + this.active = moved; + } + rotate(dir) { + if (this.paused || this.gameOver) + return; + const numRotations = PIECES[this.active.pieceIndex].shapes.length; + const newRot = ((this.active.rotation + dir) + numRotations) % numRotations; + const rotated = { ...this.active, rotation: newRot }; + // Wall-kick attempts: 0, ±1, ±2 column offsets + for (const kick of [0, -1, 1, -2, 2]) { + const kicked = { ...rotated, col: rotated.col + kick }; + if (isValid(this.board, kicked)) { + this.active = kicked; + return; + } + } + } + hardDrop() { + if (this.paused || this.gameOver) + return; + let p = this.active; + while (true) { + const next = { ...p, row: p.row + 1 }; + if (!isValid(this.board, next)) + break; + p = next; + } + this.active = p; + this.lock(); + this.dropTimer = 0; + } + togglePause() { + if (this.gameOver) + return; + this.paused = !this.paused; + this.messageEl.textContent = this.paused ? 'PAUSED' : ''; + if (!this.paused) { + this.lastTime = performance.now(); + } + } + // ── Ghost piece ──────────────────────────────────────────── + ghostRow() { + let p = this.active; + while (true) { + const next = { ...p, row: p.row + 1 }; + if (!isValid(this.board, next)) + break; + p = next; + } + return p.row; + } + // ── Drawing ──────────────────────────────────────────────── + draw() { + const ctx = this.ctx; + ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + // Background + ctx.fillStyle = '#111'; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Grid lines + ctx.strokeStyle = '#222'; + ctx.lineWidth = 0.5; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK, r * BLOCK, BLOCK, BLOCK); + } + } + // Board cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.board[r][c]) { + this.drawBlock(ctx, c, r, this.board[r][c], BLOCK); + } + } + } + // Ghost piece + if (!this.gameOver && !this.paused) { + const ghostR = this.ghostRow(); + const color = PIECES[this.active.pieceIndex].color; + for (const [r, c] of PIECES[this.active.pieceIndex].shapes[this.active.rotation]) { + const gr = r + ghostR; + const gc = c + this.active.col; + if (gr >= 0 && gr < ROWS && gc >= 0 && gc < COLS) { + ctx.fillStyle = color + '33'; // transparent + ctx.fillRect(gc * BLOCK + 1, gr * BLOCK + 1, BLOCK - 2, BLOCK - 2); + ctx.strokeStyle = color + '88'; + ctx.lineWidth = 1; + ctx.strokeRect(gc * BLOCK + 1, gr * BLOCK + 1, BLOCK - 2, BLOCK - 2); + } + } + } + // Active piece + if (!this.gameOver) { + const color = PIECES[this.active.pieceIndex].color; + for (const [r, c] of cells(this.active)) { + if (r >= 0) + this.drawBlock(ctx, c, r, color, BLOCK); + } + } + } + drawBlock(ctx, col, row, color, size, offsetX = 0, offsetY = 0) { + const x = offsetX + col * size; + const y = offsetY + row * size; + const pad = 1; + // Main fill + ctx.fillStyle = color; + ctx.fillRect(x + pad, y + pad, size - pad * 2, size - pad * 2); + // Highlight (top-left) + ctx.fillStyle = 'rgba(255,255,255,0.35)'; + ctx.fillRect(x + pad, y + pad, size - pad * 2, 4); + ctx.fillRect(x + pad, y + pad, 4, size - pad * 2); + // Shadow (bottom-right) + ctx.fillStyle = 'rgba(0,0,0,0.35)'; + ctx.fillRect(x + pad, y + size - pad - 4, size - pad * 2, 4); + ctx.fillRect(x + size - pad - 4, y + pad, 4, size - pad * 2); + } + drawNext() { + const ctx = this.nextCtx; + const size = PREVIEW_BLOCK; + ctx.clearRect(0, 0, this.nextCanvas.width, this.nextCanvas.height); + ctx.fillStyle = '#111'; + ctx.fillRect(0, 0, this.nextCanvas.width, this.nextCanvas.height); + const piece = PIECES[this.next]; + const shape = piece.shapes[0]; + // Centre the piece in the 4×4 preview box + const minR = Math.min(...shape.map(([r]) => r)); + const maxR = Math.max(...shape.map(([r]) => r)); + const minC = Math.min(...shape.map(([, c]) => c)); + const maxC = Math.max(...shape.map(([, c]) => c)); + const offR = Math.floor((4 - (maxR - minR + 1)) / 2) - minR; + const offC = Math.floor((4 - (maxC - minC + 1)) / 2) - minC; + for (const [r, c] of shape) { + this.drawBlock(ctx, c + offC, r + offR, piece.color, size); + } + } +} +// ── Bootstrap ──────────────────────────────────────────────── +window.addEventListener('DOMContentLoaded', () => { + new TetrisGame(); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,462 @@ +"use strict"; +// ============================================================ +// TETRIS – Browser TypeScript implementation +// ============================================================ +// ---------- Constants ---------- +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // pixels per cell +const HIDDEN_ROWS = 2; // extra rows above visible area for spawning +const COLORS = { + I: "#00cfcf", + O: "#cfcf00", + T: "#9f00cf", + S: "#00cf00", + Z: "#cf0000", + J: "#0000cf", + L: "#cf6f00", +}; +// Score table: points awarded per number of lines cleared at once +const LINE_SCORES = [0, 100, 300, 500, 800]; +// Frames per cell drop at each level (60 fps assumed) +const LEVEL_SPEED = [ + 48, 43, 38, 33, 28, 23, 18, 13, 8, 6, // 0–9 + 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, // 10–19 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, // 20–29 +]; +function getDropInterval(level) { + const idx = Math.min(level, LEVEL_SPEED.length - 1); + return Math.round(1000 / 60 * LEVEL_SPEED[idx]); +} +// ---------- Tetrominoes ---------- +// Each piece has 4 rotation states stored as arrays of [row, col] offsets +// relative to a pivot. +const TETROMINOES = { + I: [ + [[1, 0], [1, 1], [1, 2], [1, 3]], + [[0, 2], [1, 2], [2, 2], [3, 2]], + [[2, 0], [2, 1], [2, 2], [2, 3]], + [[0, 1], [1, 1], [2, 1], [3, 1]], + ], + O: [ + [[0, 1], [0, 2], [1, 1], [1, 2]], + [[0, 1], [0, 2], [1, 1], [1, 2]], + [[0, 1], [0, 2], [1, 1], [1, 2]], + [[0, 1], [0, 2], [1, 1], [1, 2]], + ], + T: [ + [[0, 1], [1, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [1, 2], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 1]], + [[0, 1], [1, 0], [1, 1], [2, 1]], + ], + S: [ + [[0, 1], [0, 2], [1, 0], [1, 1]], + [[0, 1], [1, 1], [1, 2], [2, 2]], + [[1, 1], [1, 2], [2, 0], [2, 1]], + [[0, 0], [1, 0], [1, 1], [2, 1]], + ], + Z: [ + [[0, 0], [0, 1], [1, 1], [1, 2]], + [[0, 2], [1, 1], [1, 2], [2, 1]], + [[1, 0], [1, 1], [2, 1], [2, 2]], + [[0, 1], [1, 0], [1, 1], [2, 0]], + ], + J: [ + [[0, 0], [1, 0], [1, 1], [1, 2]], + [[0, 1], [0, 2], [1, 1], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 2]], + [[0, 1], [1, 1], [2, 0], [2, 1]], + ], + L: [ + [[0, 2], [1, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [2, 1], [2, 2]], + [[1, 0], [1, 1], [1, 2], [2, 0]], + [[0, 0], [0, 1], [1, 1], [2, 1]], + ], +}; +const PIECE_NAMES = Object.keys(TETROMINOES); +// Wall-kick offsets to try when rotation would collide: [dRow, dCol] +const WALL_KICKS = [ + [0, 0], [0, -1], [0, 1], [0, -2], [0, 2], + [-1, 0], [-1, -1], [-1, 1], +]; +// ---------- Helpers ---------- +function createBoard() { + return Array.from({ length: ROWS + HIDDEN_ROWS }, () => Array(COLS).fill(null)); +} +function cells(p) { + return TETROMINOES[p.type][p.rot].map(([dr, dc]) => [p.row + dr, p.col + dc]); +} +function collides(board, p) { + for (const [r, c] of cells(p)) { + if (c < 0 || c >= COLS) + return true; + if (r >= ROWS + HIDDEN_ROWS) + return true; + if (r >= 0 && board[r][c] !== null) + return true; + } + return false; +} +function spawnPiece(type) { + return { type, rot: 0, row: 0, col: 3 }; +} +function randomType() { + return PIECE_NAMES[Math.floor(Math.random() * PIECE_NAMES.length)]; +} +// ---------- Game State ---------- +class TetrisGame { + constructor() { + this.board = createBoard(); + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + this.dropTimer = 0; + this.lockDelay = 0; + this.LOCK_MS = 500; + this.highScore = 0; + this.current = spawnPiece(randomType()); + this.next = spawnPiece(randomType()); + this.highScore = this.loadHighScore(); + } + loadHighScore() { + var _a; + try { + return parseInt((_a = localStorage.getItem("tetris-hs")) !== null && _a !== void 0 ? _a : "0", 10) || 0; + } + catch (_b) { + return 0; + } + } + saveHighScore() { + try { + localStorage.setItem("tetris-hs", String(this.highScore)); + } + catch ( /* ignore */_a) { /* ignore */ } + } + tryMove(dr, dc) { + const moved = Object.assign(Object.assign({}, this.current), { row: this.current.row + dr, col: this.current.col + dc }); + if (!collides(this.board, moved)) { + this.current = moved; + return true; + } + return false; + } + tryRotate(dir) { + const newRot = ((this.current.rot + dir) + 4) % 4; + for (const [dr, dc] of WALL_KICKS) { + const rotated = Object.assign(Object.assign({}, this.current), { rot: newRot, row: this.current.row + dr, col: this.current.col + dc }); + if (!collides(this.board, rotated)) { + this.current = rotated; + return true; + } + } + return false; + } + hardDrop() { + while (this.tryMove(1, 0)) { + this.score += 2; + } + this.lock(); + } + lock() { + for (const [r, c] of cells(this.current)) { + if (r >= 0) + this.board[r][c] = this.current.type; + } + const cleared = this.clearLines(); + this.score += LINE_SCORES[cleared] * (this.level + 1); + this.lines += cleared; + this.level = Math.floor(this.lines / 10); + if (this.score > this.highScore) { + this.highScore = this.score; + this.saveHighScore(); + } + this.current = this.next; + this.next = spawnPiece(randomType()); + this.lockDelay = 0; + if (collides(this.board, this.current)) { + this.gameOver = true; + } + } + clearLines() { + let cleared = 0; + for (let r = ROWS + HIDDEN_ROWS - 1; r >= 0; r--) { + if (this.board[r].every(c => c !== null)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // recheck same index + } + } + return cleared; + } + ghostRow() { + let g = this.current.row; + while (true) { + const test = Object.assign(Object.assign({}, this.current), { row: g + 1 }); + if (collides(this.board, test)) + break; + g++; + } + return g; + } + update(dt) { + if (this.gameOver || this.paused) + return; + this.dropTimer += dt; + const interval = getDropInterval(this.level); + if (this.dropTimer >= interval) { + this.dropTimer = 0; + const moved = this.tryMove(1, 0); + if (!moved) { + this.lockDelay += interval; + if (this.lockDelay >= this.LOCK_MS) { + this.lockDelay = 0; + this.lock(); + } + } + else { + this.lockDelay = 0; + } + } + } + reset() { + this.board = createBoard(); + this.current = spawnPiece(randomType()); + this.next = spawnPiece(randomType()); + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + this.dropTimer = 0; + this.lockDelay = 0; + } +} +// ---------- Renderer ---------- +class Renderer { + constructor(canvas, nextCanvas) { + this.canvas = canvas; + this.nextCanvas = nextCanvas; + this.ctx = canvas.getContext("2d"); + this.nextCtx = nextCanvas.getContext("2d"); + canvas.width = COLS * BLOCK; + canvas.height = ROWS * BLOCK; + nextCanvas.width = 4 * BLOCK; + nextCanvas.height = 4 * BLOCK; + } + drawBlock(ctx, r, c, color, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(c * BLOCK + 1, r * BLOCK + 1, BLOCK - 2, BLOCK - 2); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(c * BLOCK + 1, r * BLOCK + 1, BLOCK - 2, 6); + ctx.globalAlpha = 1; + } + drawBoard(game) { + const { ctx, canvas } = this; + // Background + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.05)"; + ctx.lineWidth = 1; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK, r * BLOCK, BLOCK, BLOCK); + } + } + // Placed blocks + for (let r = HIDDEN_ROWS; r < ROWS + HIDDEN_ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const type = game.board[r][c]; + if (type) { + this.drawBlock(ctx, r - HIDDEN_ROWS, c, COLORS[type]); + } + } + } + // Ghost piece + const ghostRow = game.ghostRow(); + if (ghostRow !== game.current.row) { + const ghost = Object.assign(Object.assign({}, game.current), { row: ghostRow }); + for (const [r, c] of cells(ghost)) { + const dr = r - HIDDEN_ROWS; + if (dr >= 0) { + ctx.globalAlpha = 0.2; + ctx.fillStyle = COLORS[game.current.type]; + ctx.fillRect(c * BLOCK + 1, dr * BLOCK + 1, BLOCK - 2, BLOCK - 2); + ctx.globalAlpha = 1; + } + } + } + // Active piece + for (const [r, c] of cells(game.current)) { + const dr = r - HIDDEN_ROWS; + if (dr >= 0) { + this.drawBlock(ctx, dr, c, COLORS[game.current.type]); + } + } + // Game over overlay + if (game.gameOver) { + ctx.fillStyle = "rgba(0,0,0,0.6)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px monospace"; + ctx.textAlign = "center"; + ctx.fillText("GAME OVER", canvas.width / 2, canvas.height / 2 - 20); + ctx.font = "16px monospace"; + ctx.fillText("Press R to restart", canvas.width / 2, canvas.height / 2 + 16); + } + // Paused overlay + if (game.paused && !game.gameOver) { + ctx.fillStyle = "rgba(0,0,0,0.5)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px monospace"; + ctx.textAlign = "center"; + ctx.fillText("PAUSED", canvas.width / 2, canvas.height / 2); + } + } + drawNext(game) { + const { nextCtx: ctx, nextCanvas: canvas } = this; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + const piece = game.next; + const blocks = TETROMINOES[piece.type][0]; + // Center the piece in the 4×4 preview + const minR = Math.min(...blocks.map(b => b[0])); + const maxR = Math.max(...blocks.map(b => b[0])); + const minC = Math.min(...blocks.map(b => b[1])); + const maxC = Math.max(...blocks.map(b => b[1])); + const offR = Math.floor((4 - (maxR - minR + 1)) / 2) - minR; + const offC = Math.floor((4 - (maxC - minC + 1)) / 2) - minC; + for (const [r, c] of blocks) { + this.drawBlock(ctx, r + offR, c + offC, COLORS[piece.type]); + } + } + updateHUD(game) { + document.getElementById("score").textContent = String(game.score); + document.getElementById("lines").textContent = String(game.lines); + document.getElementById("level").textContent = String(game.level); + document.getElementById("highscore").textContent = String(game.highScore); + } +} +// ---------- Input ---------- +class InputHandler { + constructor(game) { + this.game = game; + this.das = 0; // delayed auto-shift timer + this.arr = 0; // auto-repeat rate timer + this.DAS = 170; // ms before repeat starts + this.ARR = 50; // ms between repeats + this.heldLeft = false; + this.heldRight = false; + this.heldDown = false; + window.addEventListener("keydown", (e) => this.onKeyDown(e)); + window.addEventListener("keyup", (e) => this.onKeyUp(e)); + } + onKeyDown(e) { + if (e.repeat) + return; + const g = this.game; + switch (e.code) { + case "ArrowLeft": + this.heldLeft = true; + g.tryMove(0, -1); + this.das = 0; + break; + case "ArrowRight": + this.heldRight = true; + g.tryMove(0, 1); + this.das = 0; + break; + case "ArrowDown": + this.heldDown = true; + g.tryMove(1, 0); + break; + case "ArrowUp": + g.tryRotate(1); + break; + case "KeyZ": + g.tryRotate(-1); + break; + case "KeyX": + g.tryRotate(1); + break; + case "Space": + e.preventDefault(); + g.hardDrop(); + break; + case "KeyP": + case "Escape": + if (!g.gameOver) + g.paused = !g.paused; + break; + case "KeyR": + g.reset(); + break; + } + } + onKeyUp(e) { + if (e.code === "ArrowLeft") { + this.heldLeft = false; + } + if (e.code === "ArrowRight") { + this.heldRight = false; + } + if (e.code === "ArrowDown") { + this.heldDown = false; + } + } + update(dt) { + if (this.game.gameOver || this.game.paused) + return; + if (this.heldLeft || this.heldRight) { + this.das += dt; + if (this.das >= this.DAS) { + this.arr += dt; + if (this.arr >= this.ARR) { + this.arr = 0; + if (this.heldLeft) + this.game.tryMove(0, -1); + if (this.heldRight) + this.game.tryMove(0, 1); + } + } + } + else { + this.das = 0; + this.arr = 0; + } + if (this.heldDown) { + this.game.tryMove(1, 0); + } + } +} +// ---------- Main Loop ---------- +function main() { + const canvas = document.getElementById("board"); + const nextCanvas = document.getElementById("next-canvas"); + const game = new TetrisGame(); + const renderer = new Renderer(canvas, nextCanvas); + const input = new InputHandler(game); + let last = performance.now(); + function loop(now) { + const dt = now - last; + last = now; + input.update(dt); + game.update(dt); + renderer.drawBoard(game); + renderer.drawNext(game); + renderer.updateHUD(game); + requestAnimationFrame(loop); + } + requestAnimationFrame(loop); +} +window.addEventListener("DOMContentLoaded", main); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":";AAAA,+DAA+D;AAC/D,6CAA6C;AAC7C,+DAA+D;AAE/D,kCAAkC;AAClC,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,KAAK,GAAG,EAAE,CAAC,CAAW,kBAAkB;AAC9C,MAAM,WAAW,GAAG,CAAC,CAAC,CAAM,6CAA6C;AAEzE,MAAM,MAAM,GAA2B;IACrC,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;CACb,CAAC;AAEF,kEAAkE;AAClE,MAAM,WAAW,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAE5C,sDAAsD;AACtD,MAAM,WAAW,GAAa;IAC5B,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAI,MAAM;IAC9C,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAY,QAAQ;IAChD,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAY,QAAQ;CACjD,CAAC;AAEF,SAAS,eAAe,CAAC,KAAa;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACpD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,oCAAoC;AACpC,0EAA0E;AAC1E,uBAAuB;AACvB,MAAM,WAAW,GAAiC;IAChD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,462 @@ +"use strict"; +// ============================================================ +// Tetris – TypeScript implementation +// ============================================================ +// --------------- Constants ----------------------------------- +const BOARD_COLS = 10; +const BOARD_ROWS = 20; +const BLOCK = 30; // px per cell on the main board +// Scoring: points for 1, 2, 3, 4 cleared lines (multiplied by level) +const LINE_SCORES = [0, 100, 300, 500, 800]; +// Drop interval in ms for each level (capped at level 15+) +function dropInterval(level) { + return Math.max(50, 1000 - (level - 1) * 65); +} +const TETROMINOES = [ + { + name: "I", + color: "#00f0f0", + matrix: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + }, + { + name: "O", + color: "#f0f000", + matrix: [ + [1, 1], + [1, 1], + ], + }, + { + name: "T", + color: "#a000f0", + matrix: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + }, + { + name: "S", + color: "#00d000", + matrix: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + }, + { + name: "Z", + color: "#f00000", + matrix: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + }, + { + name: "J", + color: "#0060ff", + matrix: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + }, + { + name: "L", + color: "#f0a000", + matrix: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], + }, +]; +// --------------- Helpers ------------------------------------ +/** Rotate a matrix 90° clockwise */ +function rotateMatrix(m) { + const rows = m.length; + const cols = m[0].length; + const out = Array.from({ length: cols }, () => Array(rows).fill(0)); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + out[c][rows - 1 - r] = m[r][c]; + } + } + return out; +} +function randomTetromino() { + return TETROMINOES[Math.floor(Math.random() * TETROMINOES.length)]; +} +function makePiece(t) { + const matrix = t.matrix.map((row) => [...row]); + return { + matrix, + color: t.color, + name: t.name, + x: Math.floor((BOARD_COLS - matrix[0].length) / 2), + y: 0, + }; +} +function emptyBoard() { + return Array.from({ length: BOARD_ROWS }, () => Array(BOARD_COLS).fill(null)); +} +// --------------- Collision detection ------------------------ +function collides(board, piece, dx = 0, dy = 0, matrix) { + const m = matrix ?? piece.matrix; + for (let r = 0; r < m.length; r++) { + for (let c = 0; c < m[r].length; c++) { + if (!m[r][c]) + continue; + const nx = piece.x + c + dx; + const ny = piece.y + r + dy; + if (nx < 0 || nx >= BOARD_COLS || ny >= BOARD_ROWS) + return true; + if (ny >= 0 && board[ny][nx] !== null) + return true; + } + } + return false; +} +// --------------- Ghost piece -------------------------------- +function ghostY(board, piece) { + let dy = 0; + while (!collides(board, piece, 0, dy + 1)) { + dy++; + } + return piece.y + dy; +} +// --------------- Line clear --------------------------------- +/** Remove full rows, return count cleared */ +function clearLines(board) { + let cleared = 0; + for (let r = BOARD_ROWS - 1; r >= 0;) { + if (board[r].every((c) => c !== null)) { + board.splice(r, 1); + board.unshift(Array(BOARD_COLS).fill(null)); + cleared++; + // Don't decrement r – the row at index r is now what was above + } + else { + r--; + } + } + return cleared; +} +// --------------- Drawing ------------------------------------ +function drawBlock(ctx, x, y, color, size) { + // Main fill + ctx.fillStyle = color; + ctx.fillRect(x * size + 1, y * size + 1, size - 2, size - 2); + // Top-left bevel highlight + ctx.fillStyle = "rgba(255,255,255,0.35)"; + ctx.fillRect(x * size + 1, y * size + 1, size - 2, 4); + ctx.fillRect(x * size + 1, y * size + 1, 4, size - 2); + // Bottom-right bevel shadow + ctx.fillStyle = "rgba(0,0,0,0.30)"; + ctx.fillRect(x * size + 1, y * size + size - 5, size - 2, 4); + ctx.fillRect(x * size + size - 5, y * size + 1, 4, size - 2); +} +function drawGhostBlock(ctx, x, y, color, size) { + ctx.strokeStyle = color; + ctx.lineWidth = 2; + ctx.globalAlpha = 0.45; + ctx.strokeRect(x * size + 2, y * size + 2, size - 4, size - 4); + ctx.globalAlpha = 1; +} +// --------------- Game class --------------------------------- +class TetrisGame { + constructor() { + this.board = emptyBoard(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.lastDrop = 0; + this.rafId = 0; + this.boardCanvas = document.getElementById("board"); + this.boardCtx = this.boardCanvas.getContext("2d"); + this.nextCanvas = document.getElementById("next-canvas"); + this.nextCtx = this.nextCanvas.getContext("2d"); + this.boardCanvas.width = BOARD_COLS * BLOCK; + this.boardCanvas.height = BOARD_ROWS * BLOCK; + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.gameOverOverlay = document.getElementById("gameover-overlay"); + this.pauseOverlay = document.getElementById("pause-overlay"); + this.finalScoreEl = document.getElementById("final-score"); + this.next = randomTetromino(); + this.current = makePiece(randomTetromino()); + this.spawnNext(); + this.bindKeys(); + this.bindButtons(); + this.rafId = requestAnimationFrame((ts) => this.loop(ts)); + } + // ---- Piece management ----------------------------------- + spawnNext() { + this.current = makePiece(this.next); + this.next = randomTetromino(); + this.drawNextPreview(); + if (collides(this.board, this.current)) { + this.triggerGameOver(); + } + } + lockCurrent() { + const p = this.current; + for (let r = 0; r < p.matrix.length; r++) { + for (let c = 0; c < p.matrix[r].length; c++) { + if (!p.matrix[r][c]) + continue; + const ny = p.y + r; + const nx = p.x + c; + if (ny >= 0) + this.board[ny][nx] = p.color; + } + } + const cleared = clearLines(this.board); + if (cleared > 0) { + this.score += LINE_SCORES[cleared] * this.level; + this.lines += cleared; + this.level = Math.floor(this.lines / 10) + 1; + this.refreshStats(); + } + this.spawnNext(); + } + // ---- Movement ------------------------------------------- + moveLeft() { + if (collides(this.board, this.current, -1, 0)) + return; + this.current.x--; + } + moveRight() { + if (collides(this.board, this.current, 1, 0)) + return; + this.current.x++; + } + /** Returns true if the piece actually moved down */ + moveDown() { + if (collides(this.board, this.current, 0, 1)) + return false; + this.current.y++; + return true; + } + hardDrop() { + const dy = ghostY(this.board, this.current) - this.current.y; + this.current.y += dy; + this.score += dy * 2; + this.refreshStats(); + this.lockCurrent(); + } + rotate() { + const rotated = rotateMatrix(this.current.matrix); + // Wall-kick offsets to try + const kicks = [0, 1, -1, 2, -2]; + for (const dx of kicks) { + if (!collides(this.board, this.current, dx, 0, rotated)) { + this.current.matrix = rotated; + this.current.x += dx; + return; + } + } + } + // ---- Game state ----------------------------------------- + triggerGameOver() { + this.gameOver = true; + this.finalScoreEl.textContent = this.score.toLocaleString(); + this.gameOverOverlay.classList.remove("hidden"); + } + restart() { + this.board = emptyBoard(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.lastDrop = 0; + this.pauseOverlay.classList.add("hidden"); + this.gameOverOverlay.classList.add("hidden"); + this.refreshStats(); + this.next = randomTetromino(); + this.spawnNext(); + } + togglePause() { + if (this.gameOver) + return; + this.paused = !this.paused; + if (this.paused) { + this.pauseOverlay.classList.remove("hidden"); + } + else { + this.pauseOverlay.classList.add("hidden"); + // Reset lastDrop so paused time doesn't count + this.lastDrop = performance.now(); + this.rafId = requestAnimationFrame((ts) => this.loop(ts)); + } + } + // ---- UI helpers ----------------------------------------- + refreshStats() { + this.scoreEl.textContent = this.score.toLocaleString(); + this.linesEl.textContent = this.lines.toLocaleString(); + this.levelEl.textContent = this.level.toString(); + } + // ---- Drawing -------------------------------------------- + drawBoard() { + const ctx = this.boardCtx; + const w = this.boardCanvas.width; + const h = this.boardCanvas.height; + // Background + ctx.fillStyle = "#0d0d1a"; + ctx.fillRect(0, 0, w, h); + // Subtle grid + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + ctx.lineWidth = 1; + for (let c = 0; c <= BOARD_COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, h); + ctx.stroke(); + } + for (let r = 0; r <= BOARD_ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(w, r * BLOCK); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < BOARD_ROWS; r++) { + for (let c = 0; c < BOARD_COLS; c++) { + const cell = this.board[r][c]; + if (cell) + drawBlock(ctx, c, r, cell, BLOCK); + } + } + // Ghost piece + const gy = ghostY(this.board, this.current); + if (gy !== this.current.y) { + for (let r = 0; r < this.current.matrix.length; r++) { + for (let c = 0; c < this.current.matrix[r].length; c++) { + if (!this.current.matrix[r][c]) + continue; + const gRow = gy + r; + const gCol = this.current.x + c; + if (gRow >= 0) + drawGhostBlock(ctx, gCol, gRow, this.current.color, BLOCK); + } + } + } + // Active piece + for (let r = 0; r < this.current.matrix.length; r++) { + for (let c = 0; c < this.current.matrix[r].length; c++) { + if (!this.current.matrix[r][c]) + continue; + const bRow = this.current.y + r; + const bCol = this.current.x + c; + if (bRow >= 0) + drawBlock(ctx, bCol, bRow, this.current.color, BLOCK); + } + } + } + drawNextPreview() { + const ctx = this.nextCtx; + const cw = this.nextCanvas.width; + const ch = this.nextCanvas.height; + const NEXT_BLOCK = 26; + ctx.fillStyle = "#0d0d1a"; + ctx.fillRect(0, 0, cw, ch); + const m = this.next.matrix; + const pieceW = m[0].length * NEXT_BLOCK; + const pieceH = m.length * NEXT_BLOCK; + const offX = Math.floor((cw - pieceW) / 2 / NEXT_BLOCK); + const offY = Math.floor((ch - pieceH) / 2 / NEXT_BLOCK); + for (let r = 0; r < m.length; r++) { + for (let c = 0; c < m[r].length; c++) { + if (!m[r][c]) + continue; + drawBlock(ctx, offX + c, offY + r, this.next.color, NEXT_BLOCK); + } + } + } + // ---- Main loop ------------------------------------------ + loop(timestamp) { + if (this.paused || this.gameOver) + return; + if (timestamp - this.lastDrop >= dropInterval(this.level)) { + if (!this.moveDown()) { + this.lockCurrent(); + } + this.lastDrop = timestamp; + } + this.drawBoard(); + this.rafId = requestAnimationFrame((ts) => this.loop(ts)); + } + // ---- Input ---------------------------------------------- + bindKeys() { + document.addEventListener("keydown", (e) => { + if (this.gameOver) { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + this.restart(); + } + return; + } + switch (e.key) { + case "ArrowLeft": + e.preventDefault(); + if (!this.paused) + this.moveLeft(); + break; + case "ArrowRight": + e.preventDefault(); + if (!this.paused) + this.moveRight(); + break; + case "ArrowDown": + e.preventDefault(); + if (!this.paused) { + if (this.moveDown()) { + this.score += 1; + this.refreshStats(); + } + } + break; + case "ArrowUp": + e.preventDefault(); + if (!this.paused) + this.rotate(); + break; + case " ": + e.preventDefault(); + if (!this.paused) + this.hardDrop(); + break; + case "p": + case "P": + this.togglePause(); + break; + case "r": + case "R": + if (e.ctrlKey) + break; // don't intercept ctrl+r + this.restart(); + break; + } + }); + } + bindButtons() { + document.getElementById("btn-restart").addEventListener("click", () => this.restart()); + document.getElementById("btn-pause").addEventListener("click", () => this.togglePause()); + document.getElementById("btn-play-again").addEventListener("click", () => this.restart()); + } +} +// --------------- Bootstrap ---------------------------------- +window.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=off_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,553 @@ +"use strict"; +// ============================================================ +// T E T R I S — Complete TypeScript Implementation +// ============================================================ +// Controls: +// ← → Move left / right +// ↑ or X Rotate clockwise +// Z Rotate counter-clockwise +// ↓ Soft drop +// Space Hard drop +// C / Shift Hold piece +// P Pause +// R Restart +// ============================================================ +// ─── Constants ─────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per grid cell +const LOCK_DELAY = 500; // ms before a grounded piece locks +const DAS = 167; // delay-auto-shift (ms) +const ARR = 33; // auto-repeat rate (ms) +// ─── Piece Definitions ─────────────────────────────────────── +const PIECE_TYPES = ['I', 'O', 'T', 'S', 'Z', 'J', 'L']; +const PIECE_COLORS = { + I: '#00d4d4', + O: '#d4c400', + T: '#9900cc', + S: '#00b800', + Z: '#cc0000', + J: '#0000cc', + L: '#d47800', +}; +// Pre-computed 4 rotation states per piece. +// Using fixed-size matrices: I → 4×4, O → 2×2, others → 3×3 +const PIECE_SHAPES = { + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + O: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +// Wall-kick offsets [dx, dy] tried in order during rotation. +// Covers standard SRS-inspired kicks for all pieces. +const KICKS = [ + [0, 0], [-1, 0], [1, 0], [0, -1], + [-1, -1], [1, -1], [-2, 0], [2, 0], [0, 1], +]; +// I-piece needs wider horizontal kicks +const KICKS_I = [ + [0, 0], [-2, 0], [1, 0], [3, 0], [-3, 0], + [0, -1], [0, 1], [-2, -1], [1, 2], +]; +// ─── Canvas Setup ──────────────────────────────────────────── +const boardCanvas = document.getElementById('board'); +const ctx = boardCanvas.getContext('2d'); +const nextCanvas = document.getElementById('next'); +const nextCtx = nextCanvas.getContext('2d'); +const holdCanvas = document.getElementById('hold'); +const holdCtx = holdCanvas.getContext('2d'); +boardCanvas.width = COLS * BLOCK; // 300 px +boardCanvas.height = ROWS * BLOCK; // 600 px +// ─── Game State ────────────────────────────────────────────── +let board; +let current; +let next; +let heldType; +let canHold; +let score; +let level; +let lines; +let gameOver; +let paused; +let dropAccum; // gravity accumulator (ms) +let lockAccum; // lock-delay accumulator (ms) +let landed; // piece is sitting on something +let prevTime; +let rafId; +// 7-bag randomiser — guarantees every piece type once per 7 pieces +let bag = []; +function bagNext() { + if (!bag.length) { + bag = [...PIECE_TYPES]; + for (let i = bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [bag[i], bag[j]] = [bag[j], bag[i]]; + } + } + return bag.pop(); +} +// ─── Piece Helpers ─────────────────────────────────────────── +function spawnPiece(type) { + const t = type !== null && type !== void 0 ? type : bagNext(); + const shape = PIECE_SHAPES[t][0]; + // Centre horizontally; offset upward so the first block row is at row 0 + const x = Math.floor((COLS - shape[0].length) / 2); + let firstRow = 0; + for (let r = 0; r < shape.length; r++) { + if (shape[r].some(Boolean)) { + firstRow = r; + break; + } + } + return { type: t, shape, color: PIECE_COLORS[t], x, y: -firstRow, rot: 0 }; +} +function emptyBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +// ─── Collision Detection ───────────────────────────────────── +function valid(p, dx = 0, dy = 0, shapeOverride) { + const s = shapeOverride !== null && shapeOverride !== void 0 ? shapeOverride : p.shape; + const px = p.x + dx; + const py = p.y + dy; + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const br = py + r; + const bc = px + c; + if (bc < 0 || bc >= COLS || br >= ROWS) + return false; + if (br >= 0 && board[br][bc] !== null) + return false; + } + } + return true; +} +function grounded() { return !valid(current, 0, 1); } +// ─── Drop Speed ────────────────────────────────────────────── +// Tetris Guideline formula: seconds-per-row = (0.8 − (lvl−1)×0.007)^(lvl−1) +function dropMs() { + const secs = Math.pow(0.8 - (level - 1) * 0.007, level - 1); + return Math.max(50, secs * 1000); +} +// ─── Commit & Clear ────────────────────────────────────────── +function commitPiece() { + for (let r = 0; r < current.shape.length; r++) { + for (let c = 0; c < current.shape[r].length; c++) { + if (!current.shape[r][c]) + continue; + const br = current.y + r; + if (br < 0) + return false; // block above skyline → game over + board[br][current.x + c] = current.color; + } + } + return true; +} +function sweepLines() { + let n = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every(Boolean)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + n++; + r++; + } + } + return n; +} +// ─── Lock Piece ────────────────────────────────────────────── +const LINE_PTS = [0, 100, 300, 500, 800]; +function lockPiece() { + var _a; + if (!commitPiece()) { + triggerGameOver(); + return; + } + const n = sweepLines(); + if (n > 0) { + score += ((_a = LINE_PTS[n]) !== null && _a !== void 0 ? _a : 0) * level; + lines += n; + level = Math.floor(lines / 10) + 1; + } + updateHUD(); + current = next; + next = spawnPiece(); + canHold = true; + landed = false; + lockAccum = 0; + if (!valid(current)) + triggerGameOver(); +} +// ─── Player Actions ────────────────────────────────────────── +function move(dx, dy) { + if (!valid(current, dx, dy)) + return false; + current.x += dx; + current.y += dy; + // If the piece slid off a ledge, reset the lock timer + if (landed && !grounded()) { + landed = false; + lockAccum = 0; + } + return true; +} +function rotate(dir) { + const newRot = ((current.rot + dir) + 4) % 4; + const newShape = PIECE_SHAPES[current.type][newRot]; + const kicks = current.type === 'I' ? KICKS_I : KICKS; + for (const [dx, dy] of kicks) { + if (valid(current, dx, dy, newShape)) { + current.x += dx; + current.y += dy; + current.shape = newShape; + current.rot = newRot; + if (landed && !grounded()) { + landed = false; + lockAccum = 0; + } + return; + } + } +} +function hardDrop() { + let dist = 0; + while (valid(current, 0, dist + 1)) + dist++; + score += dist * 2; + current.y += dist; + lockPiece(); + updateHUD(); +} +function ghostY() { + let d = 0; + while (valid(current, 0, d + 1)) + d++; + return current.y + d; +} +function doHold() { + if (!canHold) + return; + canHold = false; + const prev = heldType; + heldType = current.type; + current = prev !== null ? spawnPiece(prev) : next; + if (prev === null) + next = spawnPiece(); + landed = false; + lockAccum = 0; +} +// ─── Rendering ─────────────────────────────────────────────── +function drawBlock(c, gx, gy, color, alpha = 1) { + const px = Math.round(gx * BLOCK); + const py = Math.round(gy * BLOCK); + c.save(); + c.globalAlpha = alpha; + // Main fill + c.fillStyle = color; + c.fillRect(px + 1, py + 1, BLOCK - 2, BLOCK - 2); + // Top + left highlights (bevel light) + c.fillStyle = 'rgba(255,255,255,0.40)'; + c.fillRect(px + 1, py + 1, BLOCK - 2, 4); + c.fillRect(px + 1, py + 1, 4, BLOCK - 2); + // Bottom + right shadows (bevel dark) + c.fillStyle = 'rgba(0,0,0,0.35)'; + c.fillRect(px + 1, py + BLOCK - 5, BLOCK - 2, 4); + c.fillRect(px + BLOCK - 5, py + 1, 4, BLOCK - 2); + c.restore(); +} +function drawBoardLayer() { + // Background + ctx.fillStyle = '#0d1117'; + ctx.fillRect(0, 0, boardCanvas.width, boardCanvas.height); + // Faint grid lines + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let r = 0; r < ROWS; r++) + for (let c = 0; c < COLS; c++) + ctx.strokeRect(c * BLOCK, r * BLOCK, BLOCK, BLOCK); + // Settled blocks + for (let r = 0; r < ROWS; r++) + for (let c = 0; c < COLS; c++) + if (board[r][c]) + drawBlock(ctx, c, r, board[r][c]); +} +function drawGhost() { + const gy = ghostY(); + if (gy === current.y) + return; // no gap — skip ghost + for (let r = 0; r < current.shape.length; r++) + for (let c = 0; c < current.shape[r].length; c++) + if (current.shape[r][c]) { + const br = gy + r; + if (br >= 0) + drawBlock(ctx, current.x + c, br, current.color, 0.18); + } +} +function drawActive() { + for (let r = 0; r < current.shape.length; r++) + for (let c = 0; c < current.shape[r].length; c++) + if (current.shape[r][c]) { + const br = current.y + r; + if (br >= 0) + drawBlock(ctx, current.x + c, br, current.color); + } +} +// Draw a piece centred inside a preview canvas +function drawPreview(c, type) { + const cw = c.canvas.width; + const ch = c.canvas.height; + c.fillStyle = '#111827'; + c.fillRect(0, 0, cw, ch); + if (!type) + return; + const shape = PIECE_SHAPES[type][0]; + const color = PIECE_COLORS[type]; + // Find actual occupied bounding box within the matrix + let rMin = shape.length, rMax = -1, cMin = shape[0].length, cMax = -1; + for (let r = 0; r < shape.length; r++) + for (let cc = 0; cc < shape[r].length; cc++) + if (shape[r][cc]) { + if (r < rMin) + rMin = r; + if (r > rMax) + rMax = r; + if (cc < cMin) + cMin = cc; + if (cc > cMax) + cMax = cc; + } + if (rMax < 0) + return; + const bW = cMax - cMin + 1; + const bH = rMax - rMin + 1; + const ox = (cw / BLOCK - bW) / 2 - cMin; + const oy = (ch / BLOCK - bH) / 2 - rMin; + for (let r = 0; r < shape.length; r++) + for (let cc = 0; cc < shape[r].length; cc++) + if (shape[r][cc]) + drawBlock(c, ox + cc, oy + r, color); +} +function renderFrame() { + var _a; + drawBoardLayer(); + if (!gameOver) + drawGhost(); + if (!gameOver) + drawActive(); + drawPreview(nextCtx, (_a = next === null || next === void 0 ? void 0 : next.type) !== null && _a !== void 0 ? _a : null); + drawPreview(holdCtx, heldType); +} +// ─── Overlays ──────────────────────────────────────────────── +function showOverlay(rows, headColor) { + const cw = boardCanvas.width; + const ch = boardCanvas.height; + ctx.fillStyle = 'rgba(0,0,0,0.74)'; + ctx.fillRect(0, 0, cw, ch); + ctx.textAlign = 'center'; + const lineH = BLOCK * 1.55; + const total = rows.length * lineH; + let y = ch / 2 - total / 2 + lineH * 0.8; + rows.forEach((row, i) => { + ctx.fillStyle = i === 0 ? headColor : (i === rows.length - 1 ? '#888' : '#ccc'); + ctx.font = i === 0 + ? `bold ${Math.round(BLOCK * 1.1)}px 'Courier New', monospace` + : `${Math.round(BLOCK * 0.58)}px 'Courier New', monospace`; + ctx.fillText(row, cw / 2, y); + y += lineH * (i === 0 ? 1.3 : 1); + }); +} +function triggerGameOver() { + gameOver = true; + renderFrame(); // draw board state first (without active piece) + showOverlay(['GAME OVER', `Score: ${score.toLocaleString()}`, 'Press R to restart'], '#ff4444'); +} +// ─── HUD ───────────────────────────────────────────────────── +function el(id) { return document.getElementById(id); } +function updateHUD() { + el('score').textContent = score.toLocaleString(); + el('level').textContent = String(level); + el('lines').textContent = String(lines); +} +// ─── Game Loop ─────────────────────────────────────────────── +function tick(ts) { + const dt = Math.min(ts - prevTime, 200); // cap to avoid spiral-of-death + prevTime = ts; + if (!paused && !gameOver) { + dropAccum += dt; + const ms = dropMs(); + while (dropAccum >= ms) { + dropAccum -= ms; + if (!move(0, 1)) + landed = true; + } + if (landed) { + lockAccum += dt; + if (lockAccum >= LOCK_DELAY) { + lockAccum = 0; + lockPiece(); + } + } + } + if (!gameOver) { + renderFrame(); + if (paused) + showOverlay(['PAUSED', 'Press P to resume'], '#ffffff'); + rafId = requestAnimationFrame(tick); + } +} +const arL = { fn: null, delay: null, repeat: null }; +const arR = { fn: null, delay: null, repeat: null }; +const arD = { fn: null, delay: null, repeat: null }; +function startAR(ar, fn) { + stopAR(ar); + ar.fn = fn; + fn(); // immediate first action + ar.delay = setTimeout(() => { + ar.repeat = setInterval(() => { var _a; return (_a = ar.fn) === null || _a === void 0 ? void 0 : _a.call(ar); }, ARR); + }, DAS); +} +function stopAR(ar) { + if (ar.delay) { + clearTimeout(ar.delay); + ar.delay = null; + } + if (ar.repeat) { + clearInterval(ar.repeat); + ar.repeat = null; + } +} +// ─── Input ─────────────────────────────────────────────────── +window.addEventListener('keydown', (e) => { + // Always available + if (e.key === 'r' || e.key === 'R') { + init(); + return; + } + if (e.key === 'p' || e.key === 'P') { + if (!gameOver) { + paused = !paused; + if (!paused) { + prevTime = performance.now(); + rafId = requestAnimationFrame(tick); + } + } + return; + } + if (gameOver || paused) + return; + switch (e.key) { + case 'ArrowLeft': + e.preventDefault(); + startAR(arL, () => move(-1, 0)); + break; + case 'ArrowRight': + e.preventDefault(); + startAR(arR, () => move(1, 0)); + break; + case 'ArrowDown': + e.preventDefault(); + startAR(arD, () => { + if (move(0, 1)) { + score += 1; + updateHUD(); + } + else + landed = true; + }); + break; + case 'ArrowUp': + case 'x': + case 'X': + e.preventDefault(); + rotate(1); + break; + case 'z': + case 'Z': + e.preventDefault(); + rotate(-1); + break; + case ' ': + e.preventDefault(); + hardDrop(); + break; + case 'c': + case 'C': + case 'Shift': + e.preventDefault(); + doHold(); + break; + } +}); +window.addEventListener('keyup', (e) => { + if (e.key === 'ArrowLeft') + stopAR(arL); + if (e.key === 'ArrowRight') + stopAR(arR); + if (e.key === 'ArrowDown') + stopAR(arD); +}); +// ─── Initialisation ────────────────────────────────────────── +function init() { + if (rafId) + cancelAnimationFrame(rafId); + stopAR(arL); + stopAR(arR); + stopAR(arD); + bag = []; + board = emptyBoard(); + heldType = null; + canHold = true; + score = 0; + level = 1; + lines = 0; + gameOver = false; + paused = false; + dropAccum = 0; + lockAccum = 0; + landed = false; + prevTime = performance.now(); + current = spawnPiece(); + next = spawnPiece(); + updateHUD(); + rafId = requestAnimationFrame(tick); +} +window.addEventListener('DOMContentLoaded', init); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,463 @@ +"use strict"; +// ============================================================ +// TETRIS – TypeScript / Canvas +// ============================================================ +// --------------- constants ---------------------------------- +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell +const CANVAS_W = COLS * BLOCK; +const CANVAS_H = ROWS * BLOCK; +// Points awarded per simultaneous line clears (classic Tetris) +const LINE_POINTS = [0, 100, 300, 500, 800]; +// Base fall interval (ms) at level 1; decreases each level +function levelInterval(level) { + return Math.max(80, 1000 - (level - 1) * 80); +} +const SHAPES = { + I: [ + [[0, 1], [1, 1], [2, 1], [3, 1]], + [[2, 0], [2, 1], [2, 2], [2, 3]], + [[0, 2], [1, 2], [2, 2], [3, 2]], + [[1, 0], [1, 1], [1, 2], [1, 3]], + ], + O: [ + [[1, 0], [2, 0], [1, 1], [2, 1]], + [[1, 0], [2, 0], [1, 1], [2, 1]], + [[1, 0], [2, 0], [1, 1], [2, 1]], + [[1, 0], [2, 0], [1, 1], [2, 1]], + ], + T: [ + [[1, 0], [0, 1], [1, 1], [2, 1]], + [[1, 0], [1, 1], [2, 1], [1, 2]], + [[0, 1], [1, 1], [2, 1], [1, 2]], + [[1, 0], [0, 1], [1, 1], [1, 2]], + ], + S: [ + [[1, 0], [2, 0], [0, 1], [1, 1]], + [[1, 0], [1, 1], [2, 1], [2, 2]], + [[1, 1], [2, 1], [0, 2], [1, 2]], + [[0, 0], [0, 1], [1, 1], [1, 2]], + ], + Z: [ + [[0, 0], [1, 0], [1, 1], [2, 1]], + [[2, 0], [1, 1], [2, 1], [1, 2]], + [[0, 1], [1, 1], [1, 2], [2, 2]], + [[1, 0], [0, 1], [1, 1], [0, 2]], + ], + J: [ + [[0, 0], [0, 1], [1, 1], [2, 1]], + [[1, 0], [2, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [2, 1], [2, 2]], + [[1, 0], [1, 1], [0, 2], [1, 2]], + ], + L: [ + [[2, 0], [0, 1], [1, 1], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 2]], + [[0, 1], [1, 1], [2, 1], [0, 2]], + [[0, 0], [1, 0], [1, 1], [1, 2]], + ], +}; +const COLORS = { + I: '#00CFCF', + O: '#F7D308', + T: '#A000F0', + S: '#00A000', + Z: '#F00000', + J: '#0000F0', + L: '#F0A000', +}; +const PIECE_NAMES = Object.keys(SHAPES); +// --------------- game class --------------------------------- +class Tetris { + constructor() { + this.board = []; + this.current = null; + this.next = null; + this.held = null; + this.holdUsed = false; + this.score = 0; + this.lines = 0; + this.level = 1; + this.state = 'idle'; + this.dropTimer = 0; + this.lastTime = 0; + this.animId = 0; + this.canvas = document.getElementById('board'); + this.ctx = this.canvas.getContext('2d'); + this.nextCanvas = document.getElementById('next'); + this.nextCtx = this.nextCanvas.getContext('2d'); + this.scoreEl = document.getElementById('score'); + this.linesEl = document.getElementById('lines'); + this.levelEl = document.getElementById('level'); + this.statusEl = document.getElementById('status'); + this.startBtn = document.getElementById('startBtn'); + this.canvas.width = CANVAS_W; + this.canvas.height = CANVAS_H; + this.bindKeys(); + this.startBtn.addEventListener('click', () => this.startGame()); + this.drawIdleScreen(); + } + // --------------- initialisation --------------------------- + newBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); + } + randomPiece() { + const type = PIECE_NAMES[Math.floor(Math.random() * PIECE_NAMES.length)]; + return { type, rotation: 0, x: 3, y: 0 }; + } + startGame() { + cancelAnimationFrame(this.animId); + this.board = this.newBoard(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.held = null; + this.holdUsed = false; + this.state = 'playing'; + this.current = this.randomPiece(); + this.next = this.randomPiece(); + this.updateHUD(); + this.statusEl.textContent = ''; + this.startBtn.textContent = 'Restart'; + this.lastTime = performance.now(); + this.dropTimer = 0; + this.animId = requestAnimationFrame(t => this.loop(t)); + } + // --------------- game loop -------------------------------- + loop(timestamp) { + if (this.state !== 'playing') + return; + const dt = timestamp - this.lastTime; + this.lastTime = timestamp; + this.dropTimer += dt; + if (this.dropTimer >= levelInterval(this.level)) { + this.dropTimer = 0; + this.stepDown(); + } + this.draw(); + this.animId = requestAnimationFrame(t => this.loop(t)); + } + stepDown() { + if (!this.current) + return; + if (this.canMove(this.current, 0, 1)) { + this.current.y += 1; + } + else { + this.lock(); + } + } + lock() { + if (!this.current) + return; + const cells = this.getCells(this.current); + for (const [c, r] of cells) { + if (r < 0) { + // Piece locked above board → game over + this.gameOver(); + return; + } + this.board[r][c] = this.current.type; + } + this.clearLines(); + this.holdUsed = false; + this.current = this.next; + this.next = this.randomPiece(); + // Immediate collision check (block-out) + if (!this.canMove(this.current, 0, 0)) { + this.draw(); + this.gameOver(); + } + } + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every(cell => cell !== null)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check same index after splice + } + } + if (cleared > 0) { + this.score += LINE_POINTS[cleared] * this.level; + this.lines += cleared; + this.level = Math.floor(this.lines / 10) + 1; + this.updateHUD(); + } + } + // --------------- movement --------------------------------- + getCells(piece) { + const shape = SHAPES[piece.type][piece.rotation]; + return shape.map(([dc, dr]) => [piece.x + dc, piece.y + dr]); + } + canMove(piece, dx, dy, rotation) { + const rot = rotation !== undefined ? rotation : piece.rotation; + const shape = SHAPES[piece.type][rot]; + for (const [dc, dr] of shape) { + const nc = piece.x + dx + dc; + const nr = piece.y + dy + dr; + if (nc < 0 || nc >= COLS) + return false; + if (nr >= ROWS) + return false; + if (nr >= 0 && this.board[nr][nc] !== null) + return false; + } + return true; + } + rotate(dir) { + if (!this.current) + return; + const newRot = ((this.current.rotation + dir) + 4) % 4; + // Wall-kick offsets to try + const kicks = [[0, 0], [1, 0], [-1, 0], [2, 0], [-2, 0], [0, -1]]; + for (const [kx, ky] of kicks) { + if (this.canMove(this.current, kx, ky, newRot)) { + this.current.x += kx; + this.current.y += ky; + this.current.rotation = newRot; + return; + } + } + } + moveLeft() { + if (this.current && this.canMove(this.current, -1, 0)) + this.current.x--; + } + moveRight() { + if (this.current && this.canMove(this.current, 1, 0)) + this.current.x++; + } + softDrop() { + if (!this.current) + return; + if (this.canMove(this.current, 0, 1)) { + this.current.y++; + this.score++; + this.updateHUD(); + this.dropTimer = 0; + } + } + hardDrop() { + if (!this.current) + return; + while (this.canMove(this.current, 0, 1)) { + this.current.y++; + this.score += 2; + } + this.updateHUD(); + this.dropTimer = 0; + this.lock(); + } + holdPiece() { + if (!this.current || this.holdUsed) + return; + this.holdUsed = true; + const savedType = this.current.type; + if (this.held) { + this.current = { type: this.held.type, rotation: 0, x: 3, y: 0 }; + } + else { + this.current = this.next; + this.next = this.randomPiece(); + } + this.held = { type: savedType, rotation: 0, x: 3, y: 0 }; + } + // --------------- ghost piece ------------------------------ + getGhostY() { + if (!this.current) + return 0; + let gy = this.current.y; + while (this.canMove(this.current, 0, gy - this.current.y + 1)) + gy++; + return gy; + } + // --------------- game over / pause ------------------------ + gameOver() { + this.state = 'gameover'; + cancelAnimationFrame(this.animId); + this.statusEl.textContent = 'GAME OVER'; + this.draw(); + } + togglePause() { + if (this.state === 'playing') { + this.state = 'paused'; + cancelAnimationFrame(this.animId); + this.statusEl.textContent = 'PAUSED'; + this.draw(); + } + else if (this.state === 'paused') { + this.state = 'playing'; + this.statusEl.textContent = ''; + this.lastTime = performance.now(); + this.dropTimer = 0; + this.animId = requestAnimationFrame(t => this.loop(t)); + } + } + // --------------- drawing ---------------------------------- + drawBlock(ctx, c, r, color, alpha = 1) { + const x = c * BLOCK; + const y = r * BLOCK; + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x + 1, y + 1, BLOCK - 2, BLOCK - 2); + // Shine highlight + ctx.fillStyle = 'rgba(255,255,255,0.25)'; + ctx.fillRect(x + 2, y + 2, BLOCK - 4, 4); + ctx.globalAlpha = 1; + } + draw() { + const ctx = this.ctx; + ctx.clearRect(0, 0, CANVAS_W, CANVAS_H); + // Background grid + ctx.fillStyle = '#111'; + ctx.fillRect(0, 0, CANVAS_W, CANVAS_H); + ctx.strokeStyle = '#1e1e1e'; + ctx.lineWidth = 0.5; + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, CANVAS_H); + ctx.stroke(); + } + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(CANVAS_W, r * BLOCK); + ctx.stroke(); + } + // Locked board cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const cell = this.board[r][c]; + if (cell) + this.drawBlock(ctx, c, r, COLORS[cell]); + } + } + // Ghost piece + if (this.current && this.state === 'playing') { + const gy = this.getGhostY(); + for (const [dc, dr] of SHAPES[this.current.type][this.current.rotation]) { + const gr = gy + dr; + if (gr >= 0) { + this.drawBlock(ctx, this.current.x + dc, gr, COLORS[this.current.type], 0.2); + } + } + } + // Current piece + if (this.current) { + for (const [dc, dr] of SHAPES[this.current.type][this.current.rotation]) { + const r = this.current.y + dr; + if (r >= 0) { + this.drawBlock(ctx, this.current.x + dc, r, COLORS[this.current.type]); + } + } + } + // Overlay on pause / game over + if (this.state === 'paused' || this.state === 'gameover') { + ctx.fillStyle = 'rgba(0,0,0,0.55)'; + ctx.fillRect(0, 0, CANVAS_W, CANVAS_H); + } + // Draw next piece preview + this.drawPreview(this.nextCtx, this.nextCanvas, this.next); + // Draw held piece (if hold canvas exists) + const holdCanvas = document.getElementById('hold'); + if (holdCanvas) { + const holdCtx = holdCanvas.getContext('2d'); + this.drawPreview(holdCtx, holdCanvas, this.held, this.holdUsed); + } + } + drawPreview(ctx, canvas, piece, dimmed = false) { + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = '#111'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + if (!piece) + return; + const shape = SHAPES[piece.type][0]; + const minC = Math.min(...shape.map(([c]) => c)); + const maxC = Math.max(...shape.map(([c]) => c)); + const minR = Math.min(...shape.map(([, r]) => r)); + const maxR = Math.max(...shape.map(([, r]) => r)); + const pw = (maxC - minC + 1) * BLOCK; + const ph = (maxR - minR + 1) * BLOCK; + const ox = Math.floor((canvas.width - pw) / 2) / BLOCK - minC; + const oy = Math.floor((canvas.height - ph) / 2) / BLOCK - minR; + for (const [dc, dr] of shape) { + this.drawBlock(ctx, ox + dc, oy + dr, COLORS[piece.type], dimmed ? 0.35 : 1); + } + } + drawIdleScreen() { + const ctx = this.ctx; + ctx.fillStyle = '#111'; + ctx.fillRect(0, 0, CANVAS_W, CANVAS_H); + ctx.fillStyle = '#fff'; + ctx.font = 'bold 28px monospace'; + ctx.textAlign = 'center'; + ctx.fillText('TETRIS', CANVAS_W / 2, CANVAS_H / 2 - 20); + ctx.font = '16px monospace'; + ctx.fillStyle = '#aaa'; + ctx.fillText('Press Start', CANVAS_W / 2, CANVAS_H / 2 + 20); + ctx.textAlign = 'left'; + } + // --------------- HUD --------------------------------------- + updateHUD() { + this.scoreEl.textContent = String(this.score); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + } + // --------------- keyboard --------------------------------- + bindKeys() { + document.addEventListener('keydown', (e) => { + if (this.state !== 'playing' && e.key !== 'p' && e.key !== 'P' && e.code !== 'KeyP') + return; + switch (e.code) { + case 'ArrowLeft': + e.preventDefault(); + this.moveLeft(); + break; + case 'ArrowRight': + e.preventDefault(); + this.moveRight(); + break; + case 'ArrowDown': + e.preventDefault(); + this.softDrop(); + break; + case 'ArrowUp': + e.preventDefault(); + this.rotate(1); + break; + case 'KeyZ': + e.preventDefault(); + this.rotate(-1); + break; + case 'KeyX': + e.preventDefault(); + this.rotate(1); + break; + case 'Space': + e.preventDefault(); + this.hardDrop(); + break; + case 'KeyC': + e.preventDefault(); + this.holdPiece(); + break; + case 'KeyP': + e.preventDefault(); + this.togglePause(); + break; + case 'Escape': + e.preventDefault(); + this.togglePause(); + break; + } + }); + } +} +// --------------- bootstrap ---------------------------------- +window.addEventListener('DOMContentLoaded', () => { + new Tetris(); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,646 @@ +"use strict"; +// ─── Types ─────────────────────────────────────────────────────────────────── +// ─── Constants ──────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 32; // px per cell +const HIDDEN = 2; // hidden rows above visible area (spawn buffer) +const TOTAL_ROWS = ROWS + HIDDEN; +const COLORS = { + I: "#00d4ff", + O: "#ffd700", + T: "#bf5fff", + S: "#39d353", + Z: "#ff4d4d", + J: "#4d79ff", + L: "#ff9900", +}; +const TETROMINOES = { + I: [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + O: [[1, 1], [1, 1]], + T: [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + S: [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + Z: [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + J: [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + L: [[0, 0, 1], [1, 1, 1], [0, 0, 0]], +}; +// Scoring per lines cleared (multiplied by level) +const LINE_SCORES = [0, 100, 300, 500, 800]; +// Drop interval in ms at each level (capped at level 20) +function levelInterval(level) { + return Math.max(50, 1000 - (level - 1) * 47); +} +// ─── SRS Wall-Kick Data ─────────────────────────────────────────────────────── +// Kick table: [from_rotation][0..3] for J,L,S,T,Z pieces +const KICKS_JLSTZ = [ + // 0→1 + [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + // 1→2 + [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + // 2→3 + [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + // 3→0 + [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], +]; +// Kick table for I piece +const KICKS_I = [ + // 0→1 + [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + // 1→2 + [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + // 2→3 + [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + // 3→0 + [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], +]; +// ─── Utility ────────────────────────────────────────────────────────────────── +function rotateCW(m) { + const rows = m.length, cols = m[0].length; + return Array.from({ length: cols }, (_, c) => Array.from({ length: rows }, (_, r) => m[rows - 1 - r][c])); +} +function rotateCCW(m) { + return rotateCW(rotateCW(rotateCW(m))); +} +// ─── Board ──────────────────────────────────────────────────────────────────── +class Board { + constructor() { + this.grid = Array.from({ length: TOTAL_ROWS }, () => Array(COLS).fill("")); + } + isValid(piece) { + for (let r = 0; r < piece.matrix.length; r++) { + for (let c = 0; c < piece.matrix[r].length; c++) { + if (!piece.matrix[r][c]) + continue; + const x = piece.x + c; + const y = piece.y + r; + if (x < 0 || x >= COLS || y >= TOTAL_ROWS) + return false; + if (y >= 0 && this.grid[y][x]) + return false; + } + } + return true; + } + lock(piece) { + for (let r = 0; r < piece.matrix.length; r++) { + for (let c = 0; c < piece.matrix[r].length; c++) { + if (!piece.matrix[r][c]) + continue; + const y = piece.y + r; + const x = piece.x + c; + if (y >= 0) + this.grid[y][x] = piece.color; + } + } + } + clearLines() { + const cleared = []; + for (let r = 0; r < TOTAL_ROWS; r++) { + if (this.grid[r].every(cell => cell !== "")) + cleared.push(r); + } + for (const r of cleared) { + this.grid.splice(r, 1); + this.grid.unshift(Array(COLS).fill("")); + } + return cleared.length; + } + getGhostY(piece) { + let gy = piece.y; + while (this.isValid({ ...piece, y: gy + 1 })) + gy++; + return gy; + } +} +// ─── Random Bag ────────────────────────────────────────────────────────────── +class Bag { + constructor() { + this.queue = []; + } + refill() { + const keys = Object.keys(TETROMINOES); + for (let i = keys.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [keys[i], keys[j]] = [keys[j], keys[i]]; + } + this.queue.push(...keys); + } + next() { + if (this.queue.length < 5) + this.refill(); + return this.queue.shift(); + } + peek(n) { + while (this.queue.length < n + 5) + this.refill(); + return this.queue.slice(0, n); + } +} +// ─── Tetris Game ───────────────────────────────────────────────────────────── +class Tetris { + constructor() { + this.holdKey = null; + this.holdUsed = false; + this.rotation = 0; // 0..3 + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.started = false; + // Timers + this.dropTimer = 0; + this.lastTime = 0; + this.rafId = 0; + // Lock-delay + this.lockTimer = 0; + this.lockDelay = 500; // ms + this.lockMoves = 0; + this.maxLockMoves = 15; + this.onGround = false; + // Particles + this.particles = []; + this.canvas = document.getElementById("board"); + this.ctx = this.canvas.getContext("2d"); + this.nextCanvas = document.getElementById("next"); + this.nextCtx = this.nextCanvas.getContext("2d"); + this.holdCanvas = document.getElementById("hold"); + this.holdCtx = this.holdCanvas.getContext("2d"); + this.canvas.width = COLS * BLOCK; + this.canvas.height = ROWS * BLOCK; + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.overlayEl = document.getElementById("overlay"); + this.overlayTitle = document.getElementById("overlay-title"); + this.overlayMsg = document.getElementById("overlay-msg"); + this.board = new Board(); + this.bag = new Bag(); + this.bindKeys(); + this.showOverlay("TETRIS", "Press Space or Enter to start"); + } + // ── Spawn ──────────────────────────────────────────────────────────────── + spawn(key) { + const matrix = TETROMINOES[key].map(r => [...r]); + const color = COLORS[key]; + const x = Math.floor((COLS - matrix[0].length) / 2); + const y = key === "I" ? HIDDEN - 2 : HIDDEN - 1; + return { matrix, color, x, y }; + } + spawnNext() { + const key = this.bag.next(); + this.current = this.spawn(key); + this.rotation = 0; + this.lockTimer = 0; + this.lockMoves = 0; + this.onGround = false; + if (!this.board.isValid(this.current)) { + this.endGame(); + } + } + // ── Movement & Rotation ────────────────────────────────────────────────── + move(dx, dy, softDrop = false) { + const next = { ...this.current, x: this.current.x + dx, y: this.current.y + dy }; + if (!this.board.isValid(next)) + return false; + this.current = next; + if (softDrop && dy > 0) { + // +1 per row for player-initiated soft drop + this.score += 1; + this.updateHUD(); + } + return true; + } + rotate(dir) { + const fromRot = this.rotation; + const toRot = (fromRot + (dir === 1 ? 1 : 3)) % 4; + const newMatrix = dir === 1 ? rotateCW(this.current.matrix) : rotateCCW(this.current.matrix); + const isI = this.current.matrix.length === 4; + const kicks = isI ? KICKS_I : KICKS_JLSTZ; + const kickIdx = dir === 1 ? fromRot : toRot; + const kickSet = kicks[kickIdx]; + for (const [kx, ky] of kickSet) { + const nx = this.current.x + (dir === 1 ? kx : -kx); + const ny = this.current.y + (dir === 1 ? ky : -ky); + const candidate = { ...this.current, matrix: newMatrix, x: nx, y: ny }; + if (this.board.isValid(candidate)) { + this.current = candidate; + this.rotation = toRot; + this.resetLockDelay(); + return; + } + } + } + hardDrop() { + const gy = this.board.getGhostY(this.current); + const dropped = gy - this.current.y; + this.score += dropped * 2; + this.current = { ...this.current, y: gy }; + this.lockPiece(); + } + hold() { + if (this.holdUsed) + return; + this.holdUsed = true; + if (this.holdKey === null) { + // Infer key by matching the color + const key = Object.keys(COLORS).find(k => COLORS[k] === this.current.color); + this.holdKey = key; + this.spawnNext(); + } + else { + const key = Object.keys(COLORS).find(k => COLORS[k] === this.current.color); + const prev = this.holdKey; + this.holdKey = key; + this.current = this.spawn(prev); + this.rotation = 0; + this.lockTimer = 0; + this.lockMoves = 0; + this.onGround = false; + } + this.drawHold(); + } + // ── Lock Delay ─────────────────────────────────────────────────────────── + resetLockDelay() { + if (this.onGround && this.lockMoves < this.maxLockMoves) { + this.lockTimer = 0; + this.lockMoves++; + } + } + lockPiece() { + this.board.lock(this.current); + const cleared = this.board.clearLines(); + if (cleared > 0) { + this.spawnLineClearParticles(cleared); + this.score += LINE_SCORES[cleared] * this.level; + this.lines += cleared; + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel > this.level) + this.level = newLevel; + } + this.holdUsed = false; + this.updateHUD(); + this.spawnNext(); + } + // ── Particles ──────────────────────────────────────────────────────────── + spawnLineClearParticles(_count) { + const colors = ["#fff", "#ffd700", "#ff9900", "#39d353", "#00d4ff", "#bf5fff"]; + for (let i = 0; i < 80; i++) { + this.particles.push({ + x: Math.random() * this.canvas.width, + y: Math.random() * this.canvas.height, + vx: (Math.random() - 0.5) * 6, + vy: (Math.random() - 0.5) * 6, + alpha: 1, + color: colors[Math.floor(Math.random() * colors.length)], + size: Math.random() * 5 + 2, + }); + } + } + // ── Game Loop ──────────────────────────────────────────────────────────── + loop(time) { + const dt = Math.min(time - this.lastTime, 100); + this.lastTime = time; + if (!this.paused && !this.gameOver) { + this.dropTimer += dt; + const interval = levelInterval(this.level); + if (this.dropTimer >= interval) { + this.dropTimer = 0; + const moved = this.move(0, 1); + if (!moved) { + this.onGround = true; + } + } + // Lock delay + const landedNow = !this.board.isValid({ ...this.current, y: this.current.y + 1 }); + if (landedNow) { + this.onGround = true; + this.lockTimer += dt; + if (this.lockTimer >= this.lockDelay || this.lockMoves >= this.maxLockMoves) { + this.lockPiece(); + } + } + else { + this.onGround = false; + this.lockTimer = 0; + } + // Update particles + this.particles = this.particles.filter(p => p.alpha > 0.02); + for (const p of this.particles) { + p.x += p.vx; + p.y += p.vy; + p.vy += 0.15; + p.alpha *= 0.93; + } + } + this.draw(); + this.rafId = requestAnimationFrame(t => this.loop(t)); + } + // ── Start / Pause / End ────────────────────────────────────────────────── + start() { + if (this.started && !this.gameOver) { + this.togglePause(); + return; + } + this.board = new Board(); + this.bag = new Bag(); + this.holdKey = null; + this.holdUsed = false; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.started = true; + this.particles = []; + this.spawnNext(); + this.updateHUD(); + this.hideOverlay(); + this.lastTime = performance.now(); + this.dropTimer = 0; + cancelAnimationFrame(this.rafId); + this.rafId = requestAnimationFrame(t => this.loop(t)); + } + togglePause() { + this.paused = !this.paused; + if (this.paused) { + this.showOverlay("PAUSED", "Press P or Space to resume"); + } + else { + this.hideOverlay(); + this.lastTime = performance.now(); + } + } + endGame() { + this.gameOver = true; + this.showOverlay("GAME OVER", `Score: ${this.score.toLocaleString()}\nPress Space or Enter to restart`); + } + // ── Draw ───────────────────────────────────────────────────────────────── + draw() { + const ctx = this.ctx; + ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + this.drawBackground(); + this.drawBoard(); + this.drawGhost(); + this.drawPiece(ctx, this.current, -HIDDEN); + this.drawParticles(); + this.drawNext(); + this.drawHold(); + } + drawBackground() { + const ctx = this.ctx; + ctx.fillStyle = "#0e0e1a"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + ctx.lineWidth = 1; + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, this.canvas.height); + ctx.stroke(); + } + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(this.canvas.width, r * BLOCK); + ctx.stroke(); + } + } + drawBoard() { + const ctx = this.ctx; + for (let r = HIDDEN; r < TOTAL_ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const color = this.board.grid[r][c]; + if (color) { + this.drawBlock(ctx, c, r - HIDDEN, color); + } + } + } + } + drawGhost() { + const gy = this.board.getGhostY(this.current); + if (gy === this.current.y) + return; + const ctx = this.ctx; + ctx.globalAlpha = 0.25; + const ghost = { ...this.current, y: gy }; + this.drawPiece(ctx, ghost, -HIDDEN); + ctx.globalAlpha = 1; + } + drawPiece(ctx, piece, yOffset) { + for (let r = 0; r < piece.matrix.length; r++) { + for (let c = 0; c < piece.matrix[r].length; c++) { + if (!piece.matrix[r][c]) + continue; + const px = piece.x + c; + const py = piece.y + r + yOffset; + if (py < 0) + continue; + this.drawBlock(ctx, px, py, piece.color); + } + } + } + drawBlock(ctx, x, y, color, size = BLOCK) { + const px = x * size; + const py = y * size; + const pad = size * 0.05; + // Base fill + ctx.fillStyle = color; + ctx.fillRect(px + pad, py + pad, size - pad * 2, size - pad * 2); + // Highlight (top-left) + ctx.fillStyle = "rgba(255,255,255,0.35)"; + ctx.fillRect(px + pad, py + pad, size - pad * 2, pad * 2); + ctx.fillRect(px + pad, py + pad, pad * 2, size - pad * 2); + // Shadow (bottom-right) + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(px + pad, py + size - pad * 3, size - pad * 2, pad * 2); + ctx.fillRect(px + size - pad * 3, py + pad, pad * 2, size - pad * 2); + } + drawParticles() { + const ctx = this.ctx; + for (const p of this.particles) { + ctx.globalAlpha = p.alpha; + ctx.fillStyle = p.color; + ctx.beginPath(); + ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2); + ctx.fill(); + } + ctx.globalAlpha = 1; + } + drawNext() { + const ctx = this.nextCtx; + const next3 = this.bag.peek(3); + const cellW = 4; + const cellH = 3; + const bSize = 22; + ctx.clearRect(0, 0, this.nextCanvas.width, this.nextCanvas.height); + ctx.fillStyle = "#0e0e1a"; + ctx.fillRect(0, 0, this.nextCanvas.width, this.nextCanvas.height); + next3.forEach((key, idx) => { + const matrix = TETROMINOES[key]; + const color = COLORS[key]; + const offX = Math.floor((cellW - matrix[0].length) / 2); + const offY = Math.floor((cellH - matrix.length) / 2); + const baseY = idx * cellH; + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (!matrix[r][c]) + continue; + this.drawBlock(ctx, offX + c, baseY + offY + r, color, bSize); + } + } + }); + } + drawHold() { + const ctx = this.holdCtx; + const bSize = 22; + ctx.clearRect(0, 0, this.holdCanvas.width, this.holdCanvas.height); + ctx.fillStyle = "#0e0e1a"; + ctx.fillRect(0, 0, this.holdCanvas.width, this.holdCanvas.height); + if (!this.holdKey) + return; + const matrix = TETROMINOES[this.holdKey]; + const color = this.holdUsed ? "#555" : COLORS[this.holdKey]; + const offX = Math.floor((4 - matrix[0].length) / 2); + const offY = Math.floor((3 - matrix.length) / 2); + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (!matrix[r][c]) + continue; + this.drawBlock(ctx, offX + c, offY + r, color, bSize); + } + } + } + // ── HUD ────────────────────────────────────────────────────────────────── + updateHUD() { + this.scoreEl.textContent = this.score.toLocaleString(); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + } + showOverlay(title, msg) { + this.overlayTitle.textContent = title; + this.overlayMsg.textContent = msg; + this.overlayEl.classList.remove("hidden"); + } + hideOverlay() { + this.overlayEl.classList.add("hidden"); + } + // ── Key Bindings ───────────────────────────────────────────────────────── + bindKeys() { + // DAS (Delayed Auto Shift) state + const DAS_DELAY = 170; + const DAS_RATE = 50; + const dasState = {}; + const startDAS = (key, fn) => { + if (dasState[key]?.active) + return; + fn(); + dasState[key] = { + active: true, + timer: setTimeout(() => { + dasState[key].interval = setInterval(fn, DAS_RATE); + }, DAS_DELAY), + interval: null, + }; + }; + const stopDAS = (key) => { + if (!dasState[key]) + return; + clearTimeout(dasState[key].timer); + clearInterval(dasState[key].interval); + dasState[key].active = false; + }; + window.addEventListener("keydown", (e) => { + if (!this.started || this.gameOver) { + if (e.code === "Space" || e.code === "Enter") + this.start(); + return; + } + switch (e.code) { + case "ArrowLeft": + e.preventDefault(); + startDAS("left", () => { + if (!this.paused) { + this.move(-1, 0); + this.resetLockDelay(); + } + }); + break; + case "ArrowRight": + e.preventDefault(); + startDAS("right", () => { + if (!this.paused) { + this.move(1, 0); + this.resetLockDelay(); + } + }); + break; + case "ArrowDown": + e.preventDefault(); + startDAS("down", () => { + if (!this.paused) { + this.move(0, 1, true); + this.resetLockDelay(); + } + }); + break; + case "ArrowUp": + e.preventDefault(); + if (!this.paused) { + this.rotate(1); + } + break; + case "KeyZ": + e.preventDefault(); + if (!this.paused) { + this.rotate(-1); + } + break; + case "KeyX": + e.preventDefault(); + if (!this.paused) { + this.rotate(1); + } + break; + case "Space": + e.preventDefault(); + if (this.paused) { + this.togglePause(); + return; + } + this.hardDrop(); + break; + case "KeyC": + case "ShiftLeft": + case "ShiftRight": + e.preventDefault(); + if (!this.paused) + this.hold(); + break; + case "KeyP": + case "Escape": + e.preventDefault(); + this.togglePause(); + break; + case "Enter": + e.preventDefault(); + if (this.paused) + this.togglePause(); + break; + } + }); + window.addEventListener("keyup", (e) => { + if (e.code === "ArrowLeft") + stopDAS("left"); + if (e.code === "ArrowRight") + stopDAS("right"); + if (e.code === "ArrowDown") + stopDAS("down"); + }); + } +} +// ─── Bootstrap ─────────────────────────────────────────────────────────────── +window.addEventListener("DOMContentLoaded", () => { + new Tetris(); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=off_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,532 @@ +"use strict"; +// ============================================================ +// Tetris Game in TypeScript +// ============================================================ +// --- Constants --- +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 32; +const HIDDEN_ROWS = 2; // buffer above visible area +// Tetrominoes: each piece has 4 rotations, each rotation is a 4x4 matrix +// Represented as arrays of [row, col] offsets from piece origin +const TETROMINOES = { + I: [ + [[1, 0], [1, 1], [1, 2], [1, 3]], + [[0, 2], [1, 2], [2, 2], [3, 2]], + [[2, 0], [2, 1], [2, 2], [2, 3]], + [[0, 1], [1, 1], [2, 1], [3, 1]], + ], + O: [ + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + ], + T: [ + [[0, 1], [1, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [1, 2], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 1]], + [[0, 1], [1, 0], [1, 1], [2, 1]], + ], + S: [ + [[0, 1], [0, 2], [1, 0], [1, 1]], + [[0, 1], [1, 1], [1, 2], [2, 2]], + [[1, 1], [1, 2], [2, 0], [2, 1]], + [[0, 0], [1, 0], [1, 1], [2, 1]], + ], + Z: [ + [[0, 0], [0, 1], [1, 1], [1, 2]], + [[0, 2], [1, 1], [1, 2], [2, 1]], + [[1, 0], [1, 1], [2, 1], [2, 2]], + [[0, 1], [1, 0], [1, 1], [2, 0]], + ], + J: [ + [[0, 0], [1, 0], [1, 1], [1, 2]], + [[0, 1], [0, 2], [1, 1], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 2]], + [[0, 1], [1, 1], [2, 0], [2, 1]], + ], + L: [ + [[0, 2], [1, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [2, 1], [2, 2]], + [[1, 0], [1, 1], [1, 2], [2, 0]], + [[0, 0], [0, 1], [1, 1], [2, 1]], + ], +}; +const PIECE_COLORS = { + I: '#00f0f0', + O: '#f0f000', + T: '#a000f0', + S: '#00f000', + Z: '#f00000', + J: '#0000f0', + L: '#f0a000', +}; +const PIECE_NAMES = Object.keys(TETROMINOES); +// Scoring: points per lines cleared at once (classic Tetris) +const LINE_POINTS = [0, 100, 300, 500, 800]; +// Speed: milliseconds between automatic drops per level +function dropInterval(level) { + // Starts at 800ms, decreases by ~50ms per level, min 100ms + return Math.max(100, 800 - (level - 1) * 50); +} +// --- Game State --- +let board; +let currentPiece; +let nextPiece; +let score; +let lines; +let level; +let gameOver; +let paused; +let lastDropTime; +let animationId; +let lockDelay; +let lockTimer; +// --- Canvas elements --- +let canvas; +let ctx; +let nextCanvas; +let nextCtx; +// --- Utility functions --- +function createBoard() { + return Array.from({ length: ROWS + HIDDEN_ROWS }, () => Array(COLS).fill(null)); +} +function randomPiece() { + const type = PIECE_NAMES[Math.floor(Math.random() * PIECE_NAMES.length)]; + return { + type, + rotation: 0, + row: 0, + col: Math.floor((COLS - 4) / 2), + }; +} +function getBlocks(piece) { + const shape = TETROMINOES[piece.type][piece.rotation]; + return shape.map(([r, c]) => [piece.row + r, piece.col + c]); +} +function isValid(piece, board) { + const blocks = getBlocks(piece); + for (const [r, c] of blocks) { + if (c < 0 || c >= COLS) + return false; + if (r >= ROWS + HIDDEN_ROWS) + return false; + if (r >= 0 && board[r][c] !== null) + return false; + } + return true; +} +function placePiece(piece, board) { + const blocks = getBlocks(piece); + for (const [r, c] of blocks) { + if (r >= 0) { + board[r][c] = piece.type; + } + } +} +function clearLines(board) { + let cleared = 0; + for (let r = ROWS + HIDDEN_ROWS - 1; r >= 0; r--) { + if (board[r].every(cell => cell !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // recheck this row + } + } + return cleared; +} +// Wall kick data for SRS (Super Rotation System) +// Offsets to try when rotation is blocked (for J, L, S, T, Z pieces) +const WALL_KICKS = { + '0->1': [[0, 0], [0, -1], [+1, -1], [-2, 0], [-2, -1]], + '1->0': [[0, 0], [0, +1], [-1, +1], [+2, 0], [+2, +1]], + '1->2': [[0, 0], [0, +1], [-1, +1], [+2, 0], [+2, +1]], + '2->3': [[0, 0], [0, +1], [+1, +1], [-2, 0], [-2, +1]], + '3->2': [[0, 0], [0, -1], [-1, -1], [+2, 0], [+2, -1]], + '2->1': [[0, 0], [0, -1], [+1, -1], [-2, 0], [-2, -1]], + '3->0': [[0, 0], [0, -1], [-1, -1], [+2, 0], [+2, -1]], + '0->3': [[0, 0], [0, +1], [-1, +1], [+2, 0], [+2, +1]], +}; +// I piece has different wall kick data +const WALL_KICKS_I = { + '0->1': [[0, 0], [0, -2], [0, +1], [-1, -2], [+2, +1]], + '1->0': [[0, 0], [0, +2], [0, -1], [+1, +2], [-2, -1]], + '1->2': [[0, 0], [0, -1], [0, +2], [+2, -1], [-1, +2]], + '2->1': [[0, 0], [0, +1], [0, -2], [-2, +1], [+1, -2]], + '2->3': [[0, 0], [0, +2], [0, -1], [-1, +2], [+2, -1]], + '3->2': [[0, 0], [0, -2], [0, +1], [+1, -2], [-2, +1]], + '3->0': [[0, 0], [0, +1], [0, -2], [+2, +1], [-1, -2]], + '0->3': [[0, 0], [0, -1], [0, +2], [-2, -1], [+1, +2]], +}; +function tryRotate(piece, dir, board) { + const oldRot = piece.rotation; + const newRot = ((piece.rotation + dir) + 4) % 4; + const rotated = Object.assign(Object.assign({}, piece), { rotation: newRot }); + const kickKey = `${oldRot}->${newRot}`; + const kicks = piece.type === 'I' ? WALL_KICKS_I[kickKey] : WALL_KICKS[kickKey]; + if (!kicks) + return null; + for (const [dr, dc] of kicks) { + const kicked = Object.assign(Object.assign({}, rotated), { row: rotated.row + dr, col: rotated.col + dc }); + if (isValid(kicked, board)) + return kicked; + } + return null; +} +function ghostRow(piece, board) { + let ghost = Object.assign({}, piece); + while (isValid(Object.assign(Object.assign({}, ghost), { row: ghost.row + 1 }), board)) { + ghost.row++; + } + return ghost.row; +} +// --- Drawing --- +function drawBlock(ctx, col, row, color, size = BLOCK_SIZE, alpha = 1) { + const x = col * size; + const y = row * size; + const inset = 2; + ctx.globalAlpha = alpha; + // Main fill + ctx.fillStyle = color; + ctx.fillRect(x + inset, y + inset, size - inset * 2, size - inset * 2); + // Highlight (top-left) + ctx.fillStyle = 'rgba(255,255,255,0.4)'; + ctx.fillRect(x + inset, y + inset, size - inset * 2, 4); + ctx.fillRect(x + inset, y + inset, 4, size - inset * 2); + // Shadow (bottom-right) + ctx.fillStyle = 'rgba(0,0,0,0.3)'; + ctx.fillRect(x + inset, y + size - inset - 4, size - inset * 2, 4); + ctx.fillRect(x + size - inset - 4, y + inset, 4, size - inset * 2); + ctx.globalAlpha = 1; +} +function drawBoard() { + // Background + ctx.fillStyle = '#111827'; + ctx.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); + // Grid lines + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.stroke(); + } + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(COLS * BLOCK_SIZE, r * BLOCK_SIZE); + ctx.stroke(); + } + // Placed blocks (skip hidden rows) + for (let r = HIDDEN_ROWS; r < ROWS + HIDDEN_ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const type = board[r][c]; + if (type) { + drawBlock(ctx, c, r - HIDDEN_ROWS, PIECE_COLORS[type]); + } + } + } +} +function drawPiece(piece, ghostR) { + // Draw ghost + const ghostBlocks = getBlocks(Object.assign(Object.assign({}, piece), { row: ghostR })); + for (const [r, c] of ghostBlocks) { + const visRow = r - HIDDEN_ROWS; + if (visRow >= 0) { + ctx.strokeStyle = PIECE_COLORS[piece.type]; + ctx.lineWidth = 2; + ctx.globalAlpha = 0.3; + ctx.strokeRect(c * BLOCK_SIZE + 3, visRow * BLOCK_SIZE + 3, BLOCK_SIZE - 6, BLOCK_SIZE - 6); + ctx.globalAlpha = 1; + } + } + // Draw actual piece + const blocks = getBlocks(piece); + for (const [r, c] of blocks) { + const visRow = r - HIDDEN_ROWS; + if (visRow >= 0) { + drawBlock(ctx, c, visRow, PIECE_COLORS[piece.type]); + } + } +} +function drawNextPiece() { + const size = 28; + nextCtx.fillStyle = '#111827'; + nextCtx.fillRect(0, 0, 4 * size, 4 * size); + const shape = TETROMINOES[nextPiece.type][0]; + const color = PIECE_COLORS[nextPiece.type]; + // Center the piece in the preview box + const minR = Math.min(...shape.map(([r]) => r)); + const maxR = Math.max(...shape.map(([r]) => r)); + const minC = Math.min(...shape.map(([, c]) => c)); + const maxC = Math.max(...shape.map(([, c]) => c)); + const pieceH = maxR - minR + 1; + const pieceW = maxC - minC + 1; + const offsetR = Math.floor((4 - pieceH) / 2) - minR; + const offsetC = Math.floor((4 - pieceW) / 2) - minC; + for (const [r, c] of shape) { + const x = (c + offsetC) * size; + const y = (r + offsetR) * size; + const inset = 2; + nextCtx.fillStyle = color; + nextCtx.fillRect(x + inset, y + inset, size - inset * 2, size - inset * 2); + nextCtx.fillStyle = 'rgba(255,255,255,0.4)'; + nextCtx.fillRect(x + inset, y + inset, size - inset * 2, 4); + nextCtx.fillRect(x + inset, y + inset, 4, size - inset * 2); + nextCtx.fillStyle = 'rgba(0,0,0,0.3)'; + nextCtx.fillRect(x + inset, y + size - inset - 4, size - inset * 2, 4); + nextCtx.fillRect(x + size - inset - 4, y + inset, 4, size - inset * 2); + } +} +function drawOverlay(text, subtext = '') { + ctx.fillStyle = 'rgba(0,0,0,0.7)'; + ctx.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.fillStyle = '#ffffff'; + ctx.font = 'bold 36px "Courier New", monospace'; + ctx.textAlign = 'center'; + ctx.fillText(text, COLS * BLOCK_SIZE / 2, ROWS * BLOCK_SIZE / 2 - 20); + if (subtext) { + ctx.font = '18px "Courier New", monospace'; + ctx.fillStyle = '#aaaaaa'; + ctx.fillText(subtext, COLS * BLOCK_SIZE / 2, ROWS * BLOCK_SIZE / 2 + 20); + } + ctx.textAlign = 'left'; +} +// --- Game Logic --- +function initGame() { + board = createBoard(); + score = 0; + lines = 0; + level = 1; + gameOver = false; + paused = false; + lockDelay = 500; + lockTimer = null; + currentPiece = randomPiece(); + nextPiece = randomPiece(); + updateUI(); +} +function spawnPiece() { + currentPiece = Object.assign({}, nextPiece); + nextPiece = randomPiece(); + // Check if spawn position is valid (game over if not) + if (!isValid(currentPiece, board)) { + gameOver = true; + } + drawNextPiece(); +} +function movePiece(dr, dc) { + const moved = Object.assign(Object.assign({}, currentPiece), { row: currentPiece.row + dr, col: currentPiece.col + dc }); + if (isValid(moved, board)) { + currentPiece = moved; + return true; + } + return false; +} +function rotatePiece(dir) { + const rotated = tryRotate(currentPiece, dir, board); + if (rotated) { + currentPiece = rotated; + // Reset lock timer on successful rotation + if (lockTimer !== null) { + clearTimeout(lockTimer); + lockTimer = null; + } + } +} +function hardDrop() { + const gRow = ghostRow(currentPiece, board); + const dropped = gRow - currentPiece.row; + currentPiece = Object.assign(Object.assign({}, currentPiece), { row: gRow }); + score += dropped * 2; // 2 points per row hard dropped + updateUI(); + lockPiece(); +} +function lockPiece() { + if (lockTimer !== null) { + clearTimeout(lockTimer); + lockTimer = null; + } + placePiece(currentPiece, board); + const cleared = clearLines(board); + if (cleared > 0) { + score += LINE_POINTS[cleared] * level; + lines += cleared; + level = Math.floor(lines / 10) + 1; + updateUI(); + animateClear(); + } + spawnPiece(); + lastDropTime = performance.now(); +} +function softDrop() { + if (!movePiece(1, 0)) { + // At bottom, trigger lock + scheduleLock(); + } + else { + score += 1; // 1 point per soft drop row + updateUI(); + } +} +function scheduleLock() { + if (lockTimer === null) { + lockTimer = window.setTimeout(() => { + lockTimer = null; + lockPiece(); + }, lockDelay); + } +} +function animateClear() { + // Flash effect on canvas briefly + ctx.fillStyle = 'rgba(255,255,255,0.15)'; + ctx.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); +} +function updateUI() { + const scoreEl = document.getElementById('score'); + const linesEl = document.getElementById('lines'); + const levelEl = document.getElementById('level'); + if (scoreEl) + scoreEl.textContent = score.toString(); + if (linesEl) + linesEl.textContent = lines.toString(); + if (levelEl) + levelEl.textContent = level.toString(); +} +// --- Game Loop --- +function gameLoop(timestamp) { + if (gameOver) { + drawBoard(); + drawOverlay('GAME OVER', `Score: ${score} — Press R to restart`); + return; + } + if (paused) { + drawOverlay('PAUSED', 'Press P to resume'); + animationId = requestAnimationFrame(gameLoop); + return; + } + // Auto drop + const interval = dropInterval(level); + if (timestamp - lastDropTime >= interval) { + lastDropTime = timestamp; + if (!movePiece(1, 0)) { + scheduleLock(); + } + } + // Render + drawBoard(); + const gRow = ghostRow(currentPiece, board); + drawPiece(currentPiece, gRow); + animationId = requestAnimationFrame(gameLoop); +} +// --- Input handling --- +const keysHeld = new Set(); +const DAS_DELAY = 170; // ms before auto-repeat +const ARR_INTERVAL = 50; // ms between auto-repeat moves +let dasTimers = {}; +let arrTimers = {}; +function startDAS(key, action) { + action(); + dasTimers[key] = window.setTimeout(() => { + arrTimers[key] = window.setInterval(action, ARR_INTERVAL); + }, DAS_DELAY); +} +function stopDAS(key) { + clearTimeout(dasTimers[key]); + clearInterval(arrTimers[key]); + delete dasTimers[key]; + delete arrTimers[key]; +} +document.addEventListener('keydown', (e) => { + if (keysHeld.has(e.code)) + return; + keysHeld.add(e.code); + if (e.code === 'KeyR') { + cancelAnimationFrame(animationId); + initGame(); + lastDropTime = performance.now(); + drawNextPiece(); + animationId = requestAnimationFrame(gameLoop); + return; + } + if (e.code === 'KeyP' || e.code === 'Escape') { + if (!gameOver) + paused = !paused; + if (!paused) + lastDropTime = performance.now(); + return; + } + if (gameOver || paused) + return; + switch (e.code) { + case 'ArrowLeft': + case 'KeyA': + e.preventDefault(); + startDAS(e.code, () => { + movePiece(0, -1); + // Reset lock if piece moved + if (lockTimer !== null) { + clearTimeout(lockTimer); + lockTimer = null; + } + }); + break; + case 'ArrowRight': + case 'KeyD': + e.preventDefault(); + startDAS(e.code, () => { + movePiece(0, 1); + if (lockTimer !== null) { + clearTimeout(lockTimer); + lockTimer = null; + } + }); + break; + case 'ArrowDown': + case 'KeyS': + e.preventDefault(); + startDAS(e.code, () => softDrop()); + break; + case 'ArrowUp': + case 'KeyW': + e.preventDefault(); + rotatePiece(1); + break; + case 'KeyZ': + e.preventDefault(); + rotatePiece(-1); + break; + case 'KeyX': + e.preventDefault(); + rotatePiece(1); + break; + case 'Space': + e.preventDefault(); + if (!gameOver && !paused) + hardDrop(); + break; + } +}); +document.addEventListener('keyup', (e) => { + keysHeld.delete(e.code); + stopDAS(e.code); +}); +// --- Init --- +function main() { + canvas = document.getElementById('game-canvas'); + ctx = canvas.getContext('2d'); + nextCanvas = document.getElementById('next-canvas'); + nextCtx = nextCanvas.getContext('2d'); + canvas.width = COLS * BLOCK_SIZE; + canvas.height = ROWS * BLOCK_SIZE; + nextCanvas.width = 4 * 28; + nextCanvas.height = 4 * 28; + initGame(); + lastDropTime = performance.now(); + drawNextPiece(); + animationId = requestAnimationFrame(gameLoop); +} +window.addEventListener('DOMContentLoaded', main); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run1/dist/tetris.js @@ -0,0 +1,440 @@ +"use strict"; +// ─── Constants ──────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell +const PREVIEW_BLOCK = 25; +// Colours indexed by piece type (0 = empty) +const COLORS = [ + "transparent", // 0 – empty + "#00cfcf", // 1 – I (cyan) + "#cfcf00", // 2 – O (yellow) + "#cf00cf", // 3 – T (purple) + "#00cf00", // 4 – S (green) + "#cf0000", // 5 – Z (red) + "#0000cf", // 6 – J (blue) + "#cf6e00", // 7 – L (orange) +]; +// Tetromino shapes – each piece is an array of rotations, each rotation is a +// flat array of 0/1 values for a square grid. +const TETROMINOES = [ + // I – 4×4 grid + [ + [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0], + ], + // O – 2×2 grid + [ + [1, 1, 1, 1], + ], + // T – 3×3 grid + [ + [0, 1, 0, 1, 1, 1, 0, 0, 0], + [0, 1, 0, 0, 1, 1, 0, 1, 0], + [0, 0, 0, 1, 1, 1, 0, 1, 0], + [0, 1, 0, 1, 1, 0, 0, 1, 0], + ], + // S – 3×3 grid + [ + [0, 1, 1, 1, 1, 0, 0, 0, 0], + [0, 1, 0, 0, 1, 1, 0, 0, 1], + [0, 0, 0, 0, 1, 1, 1, 1, 0], + [1, 0, 0, 1, 1, 0, 0, 1, 0], + ], + // Z – 3×3 grid + [ + [1, 1, 0, 0, 1, 1, 0, 0, 0], + [0, 0, 1, 0, 1, 1, 0, 1, 0], + [0, 0, 0, 1, 1, 0, 0, 1, 1], + [0, 1, 0, 1, 1, 0, 1, 0, 0], + ], + // J – 3×3 grid + [ + [1, 0, 0, 1, 1, 1, 0, 0, 0], + [0, 1, 1, 0, 1, 0, 0, 1, 0], + [0, 0, 0, 1, 1, 1, 0, 0, 1], + [0, 1, 0, 0, 1, 0, 1, 1, 0], + ], + // L – 3×3 grid + [ + [0, 0, 1, 1, 1, 1, 0, 0, 0], + [0, 1, 0, 0, 1, 0, 0, 1, 1], + [0, 0, 0, 1, 1, 1, 1, 0, 0], + [1, 1, 0, 0, 1, 0, 0, 1, 0], + ], +]; +// Grid size (N) for each piece type (I=4, O=2, rest=3) +const PIECE_SIZE = [4, 2, 3, 3, 3, 3, 3]; +// Points awarded per number of lines cleared simultaneously +const LINE_POINTS = [0, 100, 300, 500, 800]; +// Drop interval in ms for each level (level 1–15+) +function dropInterval(level) { + return Math.max(50, 1000 - (level - 1) * 65); +} +function emptyBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(0)); +} +// ─── Piece helpers ──────────────────────────────────────────────────────────── +function pieceSize(type) { + return PIECE_SIZE[type - 1]; +} +function pieceCell(type, rot, row, col) { + const idx = type - 1; + const rotations = TETROMINOES[idx]; + const rotation = rotations[rot % rotations.length]; + const n = pieceSize(type); + return rotation[row * n + col]; +} +/** Return all occupied [row, col] pairs on the board for the given piece. */ +function pieceCells(p) { + const n = pieceSize(p.type); + const cells = []; + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + if (pieceCell(p.type, p.rot, r, c)) { + cells.push([p.y + r, p.x + c]); + } + } + } + return cells; +} +function isValid(board, p) { + for (const [r, c] of pieceCells(p)) { + if (c < 0 || c >= COLS || r >= ROWS) + return false; + if (r >= 0 && board[r][c] !== 0) + return false; + } + return true; +} +function randomPiece() { + const type = Math.floor(Math.random() * 7) + 1; + const n = pieceSize(type); + return { + type, + rot: 0, + x: Math.floor((COLS - n) / 2), + y: 0, + }; +} +// ─── Game class ─────────────────────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.board = emptyBoard(); + this.current = randomPiece(); + this.next = randomPiece(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.lastDrop = 0; + this.animId = 0; + const boardCanvas = document.getElementById("board"); + const nextCanvas = document.getElementById("next"); + this.boardCtx = boardCanvas.getContext("2d"); + this.nextCtx = nextCanvas.getContext("2d"); + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.overlay = document.getElementById("overlay"); + this.overlayTitle = document.getElementById("overlay-title"); + this.overlayMsg = document.getElementById("overlay-msg"); + document.addEventListener("keydown", (e) => this.onKey(e)); + document.getElementById("btn-start").addEventListener("click", () => this.startNew()); + document.getElementById("btn-pause").addEventListener("click", () => this.togglePause()); + // Touch / swipe support + this.setupTouch(boardCanvas); + this.showOverlay("TETRIS", "Press Start or Space to play"); + } + // ── Control ────────────────────────────────────────────────────────────── + startNew() { + this.board = emptyBoard(); + this.current = randomPiece(); + this.next = randomPiece(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.hideOverlay(); + this.updateHUD(); + cancelAnimationFrame(this.animId); + this.lastDrop = performance.now(); + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + togglePause() { + if (this.gameOver) + return; + this.paused = !this.paused; + const btn = document.getElementById("btn-pause"); + if (this.paused) { + btn.textContent = "Resume"; + this.showOverlay("PAUSED", "Press P or Resume to continue"); + } + else { + btn.textContent = "Pause"; + this.hideOverlay(); + this.lastDrop = performance.now(); + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + } + onKey(e) { + // Start game on Space from the title screen + if ((e.code === "Space") && !this.gameOver && !this.paused && this.overlay.classList.contains("hidden") === false && this.overlayTitle.textContent === "TETRIS") { + this.startNew(); + return; + } + if (e.code === "KeyP") { + this.togglePause(); + return; + } + if (this.paused || this.gameOver) + return; + switch (e.code) { + case "ArrowLeft": + case "KeyA": + this.move(-1, 0); + break; + case "ArrowRight": + case "KeyD": + this.move(1, 0); + break; + case "ArrowDown": + case "KeyS": + this.softDrop(); + break; + case "ArrowUp": + case "KeyW": + case "KeyX": + this.rotate(1); + break; + case "KeyZ": + this.rotate(-1); + break; + case "Space": + this.hardDrop(); + break; + } + e.preventDefault(); + } + setupTouch(canvas) { + let startX = 0, startY = 0; + canvas.addEventListener("touchstart", (e) => { + startX = e.touches[0].clientX; + startY = e.touches[0].clientY; + e.preventDefault(); + }, { passive: false }); + canvas.addEventListener("touchend", (e) => { + const dx = e.changedTouches[0].clientX - startX; + const dy = e.changedTouches[0].clientY - startY; + if (Math.abs(dx) > Math.abs(dy)) { + if (dx > 20) + this.move(1, 0); + else if (dx < -20) + this.move(-1, 0); + } + else { + if (dy > 30) + this.hardDrop(); + else if (dy < -30) + this.rotate(1); + } + e.preventDefault(); + }, { passive: false }); + } + // ── Mechanics ───────────────────────────────────────────────────────────── + move(dx, dy) { + const moved = Object.assign(Object.assign({}, this.current), { x: this.current.x + dx, y: this.current.y + dy }); + if (isValid(this.board, moved)) { + this.current = moved; + this.render(); + return true; + } + return false; + } + rotate(dir) { + const rotations = TETROMINOES[this.current.type - 1].length; + const newRot = ((this.current.rot + dir) % rotations + rotations) % rotations; + const rotated = Object.assign(Object.assign({}, this.current), { rot: newRot }); + // Wall-kick offsets to try + const kicks = [0, -1, 1, -2, 2]; + for (const kick of kicks) { + const kicked = Object.assign(Object.assign({}, rotated), { x: rotated.x + kick }); + if (isValid(this.board, kicked)) { + this.current = kicked; + this.render(); + return; + } + } + } + softDrop() { + if (!this.move(0, 1)) { + this.lock(); + } + this.lastDrop = performance.now(); + } + hardDrop() { + let dropped = 0; + while (this.move(0, 1)) { + dropped++; + } + this.score += dropped * 2; + this.lock(); + } + lock() { + // Place piece on board + for (const [r, c] of pieceCells(this.current)) { + if (r >= 0) + this.board[r][c] = this.current.type; + } + // Clear full lines + const cleared = this.clearLines(); + this.score += LINE_POINTS[cleared] * this.level; + this.lines += cleared; + this.level = Math.floor(this.lines / 10) + 1; + this.updateHUD(); + // Spawn next piece + this.current = this.next; + this.next = randomPiece(); + if (!isValid(this.board, this.current)) { + this.endGame(); + } + this.render(); + } + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every((c) => c !== 0)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(0)); + cleared++; + r++; // re-check same row index (rows shifted down) + } + } + return cleared; + } + // ── Game loop ───────────────────────────────────────────────────────────── + loop(ts) { + if (this.paused || this.gameOver) + return; + if (ts - this.lastDrop >= dropInterval(this.level)) { + this.lastDrop = ts; + if (!this.move(0, 1)) + this.lock(); + } + this.render(); + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + // ── Render ──────────────────────────────────────────────────────────────── + render() { + this.drawBoard(); + this.drawNext(); + } + drawBoard() { + const ctx = this.boardCtx; + ctx.clearRect(0, 0, COLS * BLOCK, ROWS * BLOCK); + // Draw board cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + this.drawCell(ctx, c, r, this.board[r][c], BLOCK); + } + } + // Draw ghost piece + const ghost = this.ghostPiece(); + for (const [r, c] of pieceCells(ghost)) { + if (r >= 0) { + ctx.fillStyle = "rgba(255,255,255,0.15)"; + ctx.fillRect(c * BLOCK + 1, r * BLOCK + 1, BLOCK - 2, BLOCK - 2); + ctx.strokeStyle = COLORS[this.current.type]; + ctx.lineWidth = 1; + ctx.strokeRect(c * BLOCK + 1, r * BLOCK + 1, BLOCK - 2, BLOCK - 2); + } + } + // Draw current piece + for (const [r, c] of pieceCells(this.current)) { + if (r >= 0) + this.drawCell(ctx, c, r, this.current.type, BLOCK); + } + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.05)"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(COLS * BLOCK, r * BLOCK); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, ROWS * BLOCK); + ctx.stroke(); + } + } + ghostPiece() { + let ghost = Object.assign({}, this.current); + while (isValid(this.board, Object.assign(Object.assign({}, ghost), { y: ghost.y + 1 }))) + ghost.y++; + return ghost; + } + drawCell(ctx, col, row, type, size) { + if (type === 0) + return; + const color = COLORS[type]; + const x = col * size; + const y = row * size; + // Main fill + ctx.fillStyle = color; + ctx.fillRect(x + 1, y + 1, size - 2, size - 2); + // Highlight (top-left bevel) + ctx.fillStyle = "rgba(255,255,255,0.35)"; + ctx.fillRect(x + 1, y + 1, size - 2, 4); + ctx.fillRect(x + 1, y + 1, 4, size - 2); + // Shadow (bottom-right bevel) + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(x + 1, y + size - 5, size - 2, 4); + ctx.fillRect(x + size - 5, y + 1, 4, size - 2); + } + drawNext() { + const ctx = this.nextCtx; + const size = PREVIEW_BLOCK; + const canvasSize = 4 * size; + ctx.clearRect(0, 0, canvasSize, canvasSize); + const n = pieceSize(this.next.type); + const offsetX = Math.floor((4 - n) / 2); + const offsetY = Math.floor((4 - n) / 2); + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + if (pieceCell(this.next.type, 0, r, c)) { + this.drawCell(ctx, offsetX + c, offsetY + r, this.next.type, size); + } + } + } + } + // ── HUD / overlay ───────────────────────────────────────────────────────── + updateHUD() { + this.scoreEl.textContent = String(this.score); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + } + endGame() { + this.gameOver = true; + cancelAnimationFrame(this.animId); + this.showOverlay("GAME OVER", `Score: ${this.score} | Lines: ${this.lines} | Level: ${this.level}`); + } + showOverlay(title, msg) { + this.overlayTitle.textContent = title; + this.overlayMsg.textContent = msg; + this.overlay.classList.remove("hidden"); + } + hideOverlay() { + this.overlay.classList.add("hidden"); + } +} +// ─── Bootstrap ──────────────────────────────────────────────────────────────── +window.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/tetris.js @@ -0,0 +1,582 @@ +"use strict"; +// ───────────────────────────────────────────────────────────────────────────── +// Tetris — TypeScript / Canvas implementation +// ───────────────────────────────────────────────────────────────────────────── +// ─── Constants ──────────────────────────────────────────────────────────────── +const BOARD_COLS = 10; +const BOARD_ROWS = 20; +const CELL = 30; // px per cell +const PREVIEW_CELL = 24; // px per cell in next-piece panel +// Drop-interval table (ms) indexed by level 0-29 +const LEVEL_SPEEDS = [ + 800, 717, 633, 550, 467, 383, 300, 217, 133, 100, + 83, 83, 83, 67, 67, 67, 50, 50, 50, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 17, +]; +// ─── Colours ────────────────────────────────────────────────────────────────── +const COLORS = { + I: '#00cfcf', + O: '#cfcf00', + T: '#9f00cf', + S: '#00cf00', + Z: '#cf0000', + J: '#0000cf', + L: '#cf7f00', +}; +const SHAPES = { + I: [ + [[0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0]], + [[0, 0, 1, 0], + [0, 0, 1, 0], + [0, 0, 1, 0], + [0, 0, 1, 0]], + [[0, 0, 0, 0], + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0]], + [[0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0]], + ], + O: [ + [[0, 1, 1, 0], + [0, 1, 1, 0], + [0, 0, 0, 0], + [0, 0, 0, 0]], + ], + T: [ + [[0, 1, 0], + [1, 1, 1], + [0, 0, 0]], + [[0, 1, 0], + [0, 1, 1], + [0, 1, 0]], + [[0, 0, 0], + [1, 1, 1], + [0, 1, 0]], + [[0, 1, 0], + [1, 1, 0], + [0, 1, 0]], + ], + S: [ + [[0, 1, 1], + [1, 1, 0], + [0, 0, 0]], + [[0, 1, 0], + [0, 1, 1], + [0, 0, 1]], + [[0, 0, 0], + [0, 1, 1], + [1, 1, 0]], + [[1, 0, 0], + [1, 1, 0], + [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], + [0, 1, 1], + [0, 0, 0]], + [[0, 0, 1], + [0, 1, 1], + [0, 1, 0]], + [[0, 0, 0], + [1, 1, 0], + [0, 1, 1]], + [[0, 1, 0], + [1, 1, 0], + [1, 0, 0]], + ], + J: [ + [[1, 0, 0], + [1, 1, 1], + [0, 0, 0]], + [[0, 1, 1], + [0, 1, 0], + [0, 1, 0]], + [[0, 0, 0], + [1, 1, 1], + [0, 0, 1]], + [[0, 1, 0], + [0, 1, 0], + [1, 1, 0]], + ], + L: [ + [[0, 0, 1], + [1, 1, 1], + [0, 0, 0]], + [[0, 1, 0], + [0, 1, 0], + [0, 1, 1]], + [[0, 0, 0], + [1, 1, 1], + [1, 0, 0]], + [[1, 1, 0], + [0, 1, 0], + [0, 1, 0]], + ], +}; +// Wall-kick offset candidates (SRS-lite): [dx, dy] tried in order +const WALL_KICKS = [ + [0, 0], [-1, 0], [1, 0], [-2, 0], [2, 0], [0, -1], [0, -2], +]; +// ─── Board helpers ──────────────────────────────────────────────────────────── +function createBoard() { + return Array.from({ length: BOARD_ROWS }, () => Array(BOARD_COLS).fill(null)); +} +function getMatrix(p) { + const states = SHAPES[p.type]; + return states[p.rotation % states.length]; +} +function collides(board, p, dx = 0, dy = 0, rot) { + const testPiece = Object.assign(Object.assign({}, p), { x: p.x + dx, y: p.y + dy, rotation: rot !== undefined ? rot : p.rotation }); + const mat = getMatrix(testPiece); + for (let r = 0; r < mat.length; r++) { + for (let c = 0; c < mat[r].length; c++) { + if (!mat[r][c]) + continue; + const nx = testPiece.x + c; + const ny = testPiece.y + r; + if (nx < 0 || nx >= BOARD_COLS || ny >= BOARD_ROWS) + return true; + if (ny < 0) + continue; + if (board[ny][nx]) + return true; + } + } + return false; +} +// ─── Scoring ────────────────────────────────────────────────────────────────── +const LINE_POINTS = [0, 100, 300, 500, 800]; +// ─── Bag randomiser (7-bag) ─────────────────────────────────────────────────── +const PIECE_TYPES = ['I', 'O', 'T', 'S', 'Z', 'J', 'L']; +class Bag { + constructor() { + this.bag = []; + } + next() { + if (this.bag.length === 0) { + this.bag = [...PIECE_TYPES].sort(() => Math.random() - 0.5); + } + return this.bag.pop(); + } +} +// ─── Game ───────────────────────────────────────────────────────────────────── +class Tetris { + constructor(canvas, infoCanvas) { + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + this.lastDrop = 0; // timestamp of last gravity tick + this.lockDelay = 0; // timestamp when piece first touched ground + this.onGround = false; + this.lockTimeout = 500; // ms before forced lock + this.animFrame = 0; + // Soft-drop key held + this.softDrop = false; + // ─── Game loop ───────────────────────────────────────────────────────────── + this.loop = (timestamp) => { + this.animFrame = requestAnimationFrame(this.loop); + if (this.gameOver || this.paused) { + this.render(); + return; + } + const interval = this.softDrop + ? Math.min(LEVEL_SPEEDS[this.level], 50) + : LEVEL_SPEEDS[this.level]; + if (timestamp - this.lastDrop >= interval) { + if (!collides(this.board, this.current, 0, 1)) { + this.current.y++; + if (this.softDrop) + this.score++; // 1pt per soft-drop row + this.onGround = false; + this.lastDrop = timestamp; + } + else { + // Piece is on ground + if (!this.onGround) { + this.onGround = true; + this.lockDelay = timestamp; + } + else if (timestamp - this.lockDelay >= this.lockTimeout) { + this.lock(); + this.lastDrop = timestamp; + } + } + } + this.render(); + }; + this.canvas = canvas; + this.ctx = canvas.getContext('2d'); + this.infoCanvas = infoCanvas; + this.infoCtx = infoCanvas.getContext('2d'); + this.board = createBoard(); + this.bag = new Bag(); + this.current = this.spawn(this.bag.next()); + this.next = this.spawn(this.bag.next()); + this.bindKeys(); + this.loop(0); + } + // ─── Spawning ────────────────────────────────────────────────────────────── + spawn(type) { + const mat = SHAPES[type][0]; + const cols = mat[0].length; + return { + type, + rotation: 0, + x: Math.floor((BOARD_COLS - cols) / 2), + y: 0, + }; + } + advance() { + this.current = this.next; + this.next = this.spawn(this.bag.next()); + this.onGround = false; + if (collides(this.board, this.current)) { + this.gameOver = true; + } + } + // ─── Movement ────────────────────────────────────────────────────────────── + moveLeft() { if (!collides(this.board, this.current, -1)) + this.current.x--; } + moveRight() { if (!collides(this.board, this.current, 1)) + this.current.x++; } + hardDrop() { + let dropped = 0; + while (!collides(this.board, this.current, 0, 1)) { + this.current.y++; + dropped++; + } + this.score += dropped * 2; + this.lock(); + } + rotate(dir = 1) { + const states = SHAPES[this.current.type].length; + const newRot = ((this.current.rotation + dir) % states + states) % states; + for (const [dx, dy] of WALL_KICKS) { + if (!collides(this.board, this.current, dx, dy, newRot)) { + this.current.x += dx; + this.current.y += dy; + this.current.rotation = newRot; + return; + } + } + } + // ─── Lock & Line-clear ───────────────────────────────────────────────────── + lock() { + const mat = getMatrix(this.current); + for (let r = 0; r < mat.length; r++) { + for (let c = 0; c < mat[r].length; c++) { + if (!mat[r][c]) + continue; + const ny = this.current.y + r; + const nx = this.current.x + c; + if (ny < 0) { + this.gameOver = true; + return; + } + this.board[ny][nx] = COLORS[this.current.type]; + } + } + this.clearLines(); + this.advance(); + this.onGround = false; + this.lastDrop = performance.now(); + } + clearLines() { + let cleared = 0; + for (let r = BOARD_ROWS - 1; r >= 0; r--) { + if (this.board[r].every(c => c !== null)) { + this.board.splice(r, 1); + this.board.unshift(Array(BOARD_COLS).fill(null)); + cleared++; + r++; // re-check same row index + } + } + if (cleared > 0) { + this.score += LINE_POINTS[cleared] * (this.level + 1); + this.lines += cleared; + this.level = Math.min(29, Math.floor(this.lines / 10)); + } + } + // ─── Ghost piece ─────────────────────────────────────────────────────────── + ghostY() { + let gy = this.current.y; + while (!collides(this.board, Object.assign(Object.assign({}, this.current), { y: gy + 1 }))) + gy++; + return gy; + } + // ─── Rendering ───────────────────────────────────────────────────────────── + render() { + this.drawBoard(); + this.drawInfo(); + } + drawBoard() { + const ctx = this.ctx; + const W = BOARD_COLS * CELL; + const H = BOARD_ROWS * CELL; + // Background + ctx.fillStyle = '#111'; + ctx.fillRect(0, 0, W, H); + // Grid lines + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 0.5; + for (let c = 0; c <= BOARD_COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, H); + ctx.stroke(); + } + for (let r = 0; r <= BOARD_ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(W, r * CELL); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < BOARD_ROWS; r++) { + for (let c = 0; c < BOARD_COLS; c++) { + if (this.board[r][c]) + this.drawCell(ctx, c, r, this.board[r][c], CELL, 1.0); + } + } + if (!this.gameOver) { + // Ghost + const gy = this.ghostY(); + const mat = getMatrix(this.current); + for (let r = 0; r < mat.length; r++) { + for (let c = 0; c < mat[r].length; c++) { + if (mat[r][c]) { + this.drawCell(ctx, this.current.x + c, gy + r, COLORS[this.current.type], CELL, 0.25); + } + } + } + // Current piece + for (let r = 0; r < mat.length; r++) { + for (let c = 0; c < mat[r].length; c++) { + if (mat[r][c]) { + this.drawCell(ctx, this.current.x + c, this.current.y + r, COLORS[this.current.type], CELL, 1.0); + } + } + } + } + // Overlays + if (this.paused) { + ctx.fillStyle = 'rgba(0,0,0,0.55)'; + ctx.fillRect(0, 0, W, H); + ctx.fillStyle = '#fff'; + ctx.font = 'bold 32px monospace'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText('PAUSED', W / 2, H / 2); + ctx.font = '16px monospace'; + ctx.fillStyle = '#aaa'; + ctx.fillText('press P to resume', W / 2, H / 2 + 40); + } + if (this.gameOver) { + ctx.fillStyle = 'rgba(0,0,0,0.65)'; + ctx.fillRect(0, 0, W, H); + ctx.fillStyle = '#ff4444'; + ctx.font = 'bold 36px monospace'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText('GAME OVER', W / 2, H / 2 - 20); + ctx.fillStyle = '#fff'; + ctx.font = '18px monospace'; + ctx.fillText(`Score: ${this.score}`, W / 2, H / 2 + 20); + ctx.fillStyle = '#aaa'; + ctx.font = '15px monospace'; + ctx.fillText('press R to restart', W / 2, H / 2 + 55); + } + } + drawCell(ctx, col, row, color, size, alpha, offsetX = 0, offsetY = 0) { + const x = col * size + offsetX; + const y = row * size + offsetY; + const pad = 1; + ctx.save(); + ctx.globalAlpha = alpha; + // Main fill + ctx.fillStyle = color; + ctx.fillRect(x + pad, y + pad, size - pad * 2, size - pad * 2); + // Highlight (top-left bevel) + ctx.fillStyle = 'rgba(255,255,255,0.35)'; + ctx.fillRect(x + pad, y + pad, size - pad * 2, 4); + ctx.fillRect(x + pad, y + pad, 4, size - pad * 2); + // Shadow (bottom-right bevel) + ctx.fillStyle = 'rgba(0,0,0,0.30)'; + ctx.fillRect(x + pad, y + size - pad - 4, size - pad * 2, 4); + ctx.fillRect(x + size - pad - 4, y + pad, 4, size - pad * 2); + ctx.restore(); + } + drawInfo() { + const ctx = this.infoCtx; + const W = this.infoCanvas.width; + const H = this.infoCanvas.height; + ctx.fillStyle = '#1a1a2e'; + ctx.fillRect(0, 0, W, H); + const label = (text, y) => { + ctx.fillStyle = '#888'; + ctx.font = '13px monospace'; + ctx.textAlign = 'left'; + ctx.textBaseline = 'alphabetic'; + ctx.fillText(text, 14, y); + }; + const value = (text, y) => { + ctx.fillStyle = '#fff'; + ctx.font = 'bold 22px monospace'; + ctx.textAlign = 'left'; + ctx.fillText(text, 14, y); + }; + // Score + label('SCORE', 40); + value(String(this.score), 65); + // Lines + label('LINES', 105); + value(String(this.lines), 130); + // Level + label('LEVEL', 170); + value(String(this.level + 1), 195); + // Next piece + label('NEXT', 235); + const previewBox = 4 * PREVIEW_CELL; + const bx = (W - previewBox) / 2; + const by = 250; + ctx.fillStyle = '#111'; + ctx.fillRect(bx - 2, by - 2, previewBox + 4, previewBox + 4); + const nmat = getMatrix(this.next); + // Centre the preview shape in the 4×4 box + let minC = 4, maxC = 0, minR = 4, maxR = 0; + for (let r = 0; r < nmat.length; r++) + for (let c = 0; c < nmat[r].length; c++) + if (nmat[r][c]) { + minC = Math.min(minC, c); + maxC = Math.max(maxC, c); + minR = Math.min(minR, r); + maxR = Math.max(maxR, r); + } + const shapeW = (maxC - minC + 1) * PREVIEW_CELL; + const shapeH = (maxR - minR + 1) * PREVIEW_CELL; + const startX = bx + (previewBox - shapeW) / 2 - minC * PREVIEW_CELL; + const startY = by + (previewBox - shapeH) / 2 - minR * PREVIEW_CELL; + for (let r = 0; r < nmat.length; r++) { + for (let c = 0; c < nmat[r].length; c++) { + if (nmat[r][c]) { + const px = startX + c * PREVIEW_CELL; + const py = startY + r * PREVIEW_CELL; + this.drawCell(ctx, 0, 0, COLORS[this.next.type], PREVIEW_CELL, 1.0, px, py); + } + } + } + // Controls hint + const hints = [ + ['← →', 'Move'], + ['↑ / Z', 'Rotate'], + ['↓', 'Soft drop'], + ['Space', 'Hard drop'], + ['P', 'Pause'], + ['R', 'Restart'], + ]; + ctx.fillStyle = '#444'; + ctx.fillRect(8, H - hints.length * 20 - 12, W - 16, hints.length * 20 + 8); + hints.forEach(([key, action], i) => { + const hy = H - hints.length * 20 - 4 + i * 20; + ctx.fillStyle = '#cf9f00'; + ctx.font = 'bold 11px monospace'; + ctx.textAlign = 'left'; + ctx.fillText(key.padEnd(6), 14, hy + 14); + ctx.fillStyle = '#aaa'; + ctx.font = '11px monospace'; + ctx.fillText(action, 58, hy + 14); + }); + } + // ─── Input ───────────────────────────────────────────────────────────────── + bindKeys() { + document.addEventListener('keydown', (e) => { + if (e.repeat && ['ArrowLeft', 'ArrowRight', 'ArrowDown'].includes(e.code)) { + // allow repeating for these + } + else if (e.repeat) + return; + if (e.code === 'KeyR') { + this.restart(); + return; + } + if (e.code === 'KeyP') { + this.togglePause(); + return; + } + if (this.gameOver || this.paused) + return; + switch (e.code) { + case 'ArrowLeft': + e.preventDefault(); + this.moveLeft(); + break; + case 'ArrowRight': + e.preventDefault(); + this.moveRight(); + break; + case 'ArrowDown': + e.preventDefault(); + this.softDrop = true; + break; + case 'ArrowUp': + e.preventDefault(); + this.rotate(1); + break; + case 'KeyZ': + e.preventDefault(); + this.rotate(-1); + break; + case 'Space': + e.preventDefault(); + this.hardDrop(); + break; + } + }); + document.addEventListener('keyup', (e) => { + if (e.code === 'ArrowDown') + this.softDrop = false; + }); + } + togglePause() { + if (this.gameOver) + return; + this.paused = !this.paused; + if (!this.paused) + this.lastDrop = performance.now(); + } + restart() { + cancelAnimationFrame(this.animFrame); + this.board = createBoard(); + this.bag = new Bag(); + this.current = this.spawn(this.bag.next()); + this.next = this.spawn(this.bag.next()); + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + this.softDrop = false; + this.onGround = false; + this.lastDrop = performance.now(); + this.loop(performance.now()); + } +} +// ─── Bootstrap ──────────────────────────────────────────────────────────────── +window.addEventListener('DOMContentLoaded', () => { + const board = document.getElementById('board'); + const info = document.getElementById('info'); + board.width = BOARD_COLS * CELL; + board.height = BOARD_ROWS * CELL; + info.width = 160; + info.height = BOARD_ROWS * CELL; + new Tetris(board, info); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=off_web_search=on_run3/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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CD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACT,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACT,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACT,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KACV;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACT,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACT,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACT,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KACV;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC;YACP,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CA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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js @@ -0,0 +1,762 @@ +"use strict"; +// ============================================================================= +// TETRIS · TypeScript · Browser Canvas +// ============================================================================= +// ─── Constants ──────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per board cell +const PB = 24; // px per preview cell +// Input timing (ms) +const DAS = 150; // Delayed Auto‑Shift +const ARR = 50; // Auto‑Repeat Rate +const SOFT_ARR = 50; // Soft‑drop repeat rate +// Lock‑delay (ms) +const LOCK_DELAY = 500; +const MAX_RESETS = 15; +// Line‑clear flash (ms) +const CLEAR_MS = 350; +// Scoring: [0 lines, 1 line, 2, 3, 4] +const LINE_SCORE = [0, 100, 300, 500, 800]; +const LINES_PER_LEVEL = 10; +// Fall speed table (ms / row) indexed by level‑1 (capped at index 19) +const FALL_SPEEDS = [ + 800, 717, 633, 550, 467, 383, 300, 217, 133, 100, + 83, 83, 83, 67, 67, 67, 50, 50, 50, 33, +]; +// ─── Piece colours ──────────────────────────────────────────────────────────── +const COLORS = { + I: '#00f0f0', + O: '#f0d000', + T: '#a000f0', + S: '#30d000', + Z: '#e02000', + J: '#2050f0', + L: '#f07800', +}; +// ─── Piece shapes (4 rotations each, [row][col] = 0|1) ─────────────────────── +// Rotations: 0=spawn, 1=CW90, 2=180, 3=CCW90 +const SHAPES = { + // 4×4 bounding box + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + // 4×3 bounding box (stays the same all rotations — O doesn't truly rotate) + O: [ + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]], + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]], + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]], + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]], + ], + // 3×3 bounding box + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +// ─── SRS Wall‑kick tables ───────────────────────────────────────────────────── +// Offsets [dx, dy] in SCREEN coordinates (y ↓ positive). +// Source: Tetris Guideline standard orientation table, y‑axis flipped for canvas. +const KICKS_JLSTZ = { + '0>1': [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + '1>0': [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + '1>2': [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + '2>1': [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + '2>3': [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + '3>2': [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + '3>0': [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + '0>3': [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], +}; +const KICKS_I = { + '0>1': [[0, 0], [-2, 0], [1, 0], [-2, 1], [1, -2]], + '1>0': [[0, 0], [2, 0], [-1, 0], [2, -1], [-1, 2]], + '1>2': [[0, 0], [-1, 0], [2, 0], [-1, -2], [2, 1]], + '2>1': [[0, 0], [1, 0], [-2, 0], [1, 2], [-2, -1]], + '2>3': [[0, 0], [2, 0], [-1, 0], [2, -1], [-1, 2]], + '3>2': [[0, 0], [-2, 0], [1, 0], [-2, 1], [1, -2]], + '3>0': [[0, 0], [1, 0], [-2, 0], [1, 2], [-2, -1]], + '0>3': [[0, 0], [-1, 0], [2, 0], [-1, -2], [2, 1]], +}; +// ─── 7‑Bag Randomiser ───────────────────────────────────────────────────────── +class Bag { + constructor() { + this.q = []; + } + next() { + this.ensure(1); + return this.q.shift(); + } + peek(n) { + this.ensure(n); + return this.q.slice(0, n); + } + ensure(min) { + while (this.q.length < min) { + const bag = ['I', 'O', 'T', 'S', 'Z', 'J', 'L']; + for (let i = bag.length - 1; i > 0; i--) { + const j = (Math.random() * (i + 1)) | 0; + [bag[i], bag[j]] = [bag[j], bag[i]]; + } + this.q.push(...bag); + } + } +} +// ─── TetrisGame ─────────────────────────────────────────────────────────────── +class TetrisGame { + // ──────────────────────────────────────────────────────────────────────────── + constructor() { + // ── Game state ────────────────────────────────────────────────────────────── + this.board = []; + this.piece = null; + this.holdType = null; + this.holdUsed = false; + this.bag = new Bag(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.state = 'idle'; + // ── Timing ────────────────────────────────────────────────────────────────── + this.rafId = 0; + this.lastTs = 0; + this.fallAcc = 0; + // ── Lock delay ────────────────────────────────────────────────────────────── + this.lockAcc = 0; + this.onGround = false; + this.lockResets = 0; + // ── Line‑clear animation ──────────────────────────────────────────────────── + this.clearRows = []; + this.clearAcc = 0; + // ── DAS / ARR key tracking ────────────────────────────────────────────────── + this.keys = {}; + this.dasL = 0; + this.arrL = 0; + this.dasR = 0; + this.arrR = 0; + this.dasSoft = 0; + this.arrSoft = 0; + this.canvas = this.el('board'); + this.ctx = this.canvas.getContext('2d'); + this.holdCvs = this.el('hold-cvs'); + this.holdCtx = this.holdCvs.getContext('2d'); + this.nextCvss = [0, 1, 2, 3, 4].map(i => this.el(`next-${i}`)); + this.nextCtxs = this.nextCvss.map(c => c.getContext('2d')); + this.scoreEl = this.el('score'); + this.linesEl = this.el('lines'); + this.levelEl = this.el('level'); + this.overlayEl = this.el('overlay'); + this.msgEl = this.el('overlay-msg'); + this.bindInput(); + this.showOverlay('TETRIS', '← → &nbsp; Move<br>↑ / X &nbsp; Rotate CW<br>Z &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Rotate CCW<br>↓ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Soft Drop<br>Space&nbsp; Hard Drop<br>C / ⇧ &nbsp; Hold<br>P / Esc &nbsp;Pause', 'Press Enter or Space to start'); + this.draw(); + } + // ─── Helpers ───────────────────────────────────────────────────────────────── + el(id) { + return document.getElementById(id); + } + fallMs() { + return FALL_SPEEDS[Math.min(this.level - 1, FALL_SPEEDS.length - 1)]; + } + // ─── Input ─────────────────────────────────────────────────────────────────── + bindInput() { + window.addEventListener('keydown', e => { + const fresh = !this.keys[e.code]; + this.keys[e.code] = true; + if (fresh) + this.onKey(e.code); + // Prevent page scrolling for arrow / space keys + if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Space'].includes(e.code)) + e.preventDefault(); + }); + window.addEventListener('keyup', e => { + this.keys[e.code] = false; + if (e.code === 'ArrowLeft') { + this.dasL = 0; + this.arrL = 0; + } + if (e.code === 'ArrowRight') { + this.dasR = 0; + this.arrR = 0; + } + if (e.code === 'ArrowDown') { + this.dasSoft = 0; + this.arrSoft = 0; + } + }); + // Clear all key states when window loses focus (prevents stuck keys) + window.addEventListener('blur', () => { + this.keys = {}; + this.dasL = 0; + this.arrL = 0; + this.dasR = 0; + this.arrR = 0; + this.dasSoft = 0; + this.arrSoft = 0; + }); + } + onKey(code) { + if (this.state === 'idle' || this.state === 'gameover') { + if (code === 'Enter' || code === 'Space') + this.startGame(); + return; + } + if (this.state === 'paused') { + if (code === 'KeyP' || code === 'Escape') + this.resume(); + return; + } + // Playing + switch (code) { + case 'ArrowLeft': + this.shiftL(); + break; + case 'ArrowRight': + this.shiftR(); + break; + case 'ArrowDown': + this.softDrop(); + break; + case 'ArrowUp': + case 'KeyX': + this.rotate(1); + break; + case 'KeyZ': + case 'KeyA': + this.rotate(-1); + break; + case 'Space': + this.hardDrop(); + break; + case 'KeyC': + case 'ShiftLeft': + case 'ShiftRight': + this.doHold(); + break; + case 'KeyP': + case 'Escape': + this.pause(); + break; + } + } + // ─── DAS / ARR (called every frame) ───────────────────────────────────────── + handleDAS(dt) { + if (this.keys['ArrowLeft']) { + this.dasL += dt; + if (this.dasL >= DAS) { + this.arrL += dt; + while (this.arrL >= ARR) { + this.arrL -= ARR; + this.shiftL(); + } + } + } + if (this.keys['ArrowRight']) { + this.dasR += dt; + if (this.dasR >= DAS) { + this.arrR += dt; + while (this.arrR >= ARR) { + this.arrR -= ARR; + this.shiftR(); + } + } + } + if (this.keys['ArrowDown']) { + this.dasSoft += dt; + if (this.dasSoft >= DAS / 2) { + this.arrSoft += dt; + while (this.arrSoft >= SOFT_ARR) { + this.arrSoft -= SOFT_ARR; + this.softDrop(); + } + } + } + } + // ─── Game control ───────────────────────────────────────────────────────────── + startGame() { + this.board = Array.from({ length: ROWS }, () => Array(COLS).fill(null)); + this.bag = new Bag(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.holdType = null; + this.holdUsed = false; + this.clearRows = []; + this.piece = null; + this.state = 'playing'; + this.fallAcc = 0; + this.lockAcc = 0; + this.onGround = false; + this.lockResets = 0; + this.overlayEl.classList.add('hidden'); + this.updateStats(); + this.spawnPiece(); + cancelAnimationFrame(this.rafId); + this.lastTs = performance.now(); + this.rafId = requestAnimationFrame(ts => this.loop(ts)); + } + pause() { + this.state = 'paused'; + cancelAnimationFrame(this.rafId); + this.showOverlay('PAUSED', '', 'Press P or Esc to resume'); + } + resume() { + this.state = 'playing'; + this.lastTs = performance.now(); + this.overlayEl.classList.add('hidden'); + this.rafId = requestAnimationFrame(ts => this.loop(ts)); + } + endGame() { + this.state = 'gameover'; + this.piece = null; + this.draw(); + this.showOverlay('GAME OVER', `Score: ${this.score.toLocaleString()}<br>Level: ${this.level} · Lines: ${this.lines}`, 'Press Enter or Space to restart'); + } + // ─── Piece management ───────────────────────────────────────────────────────── + spawnPiece() { + const type = this.bag.next(); + const shape = SHAPES[type][0]; + const x = Math.floor((COLS - shape[0].length) / 2); + this.piece = { type, x, y: 0, rot: 0 }; + this.holdUsed = false; + this.lockAcc = 0; + this.onGround = false; + this.lockResets = 0; + if (!this.fits(this.piece)) + this.endGame(); + } + spawnType(type) { + const shape = SHAPES[type][0]; + const x = Math.floor((COLS - shape[0].length) / 2); + this.piece = { type, x, y: 0, rot: 0 }; + this.lockAcc = 0; + this.onGround = false; + this.lockResets = 0; + if (!this.fits(this.piece)) + this.endGame(); + } + doHold() { + if (!this.piece || this.holdUsed) + return; + const cur = this.piece.type; + if (this.holdType) { + const saved = this.holdType; + this.holdType = cur; + this.spawnType(saved); + } + else { + this.holdType = cur; + this.spawnPiece(); + } + this.holdUsed = true; + } + // ─── Movement & rotation ────────────────────────────────────────────────────── + shiftL() { + if (!this.piece) + return; + if (this.fits({ ...this.piece, x: this.piece.x - 1 })) { + this.piece.x--; + this.onMovedWhileGrounded(); + } + } + shiftR() { + if (!this.piece) + return; + if (this.fits({ ...this.piece, x: this.piece.x + 1 })) { + this.piece.x++; + this.onMovedWhileGrounded(); + } + } + softDrop() { + if (!this.piece) + return; + if (this.fits({ ...this.piece, y: this.piece.y + 1 })) { + this.piece.y++; + this.score++; + this.fallAcc = 0; + this.onGround = false; + this.lockAcc = 0; + } + else { + this.lockPiece(); + } + } + hardDrop() { + if (!this.piece) + return; + let dropped = 0; + while (this.fits({ ...this.piece, y: this.piece.y + 1 })) { + this.piece.y++; + dropped++; + } + this.score += dropped * 2; + this.lockPiece(); + } + rotate(dir) { + if (!this.piece) + return; + const from = this.piece.rot; + const to = (from + dir + 4) % 4; + const key = `${from}>${to}`; + const kicks = (this.piece.type === 'I') ? KICKS_I[key] : KICKS_JLSTZ[key]; + if (!kicks) + return; + for (const [dx, dy] of kicks) { + const candidate = { ...this.piece, x: this.piece.x + dx, y: this.piece.y + dy, rot: to }; + if (this.fits(candidate)) { + this.piece = candidate; + this.onMovedWhileGrounded(); + return; + } + } + } + /** Reset lock‑delay timer when the player moves/rotates while piece rests on surface. */ + onMovedWhileGrounded() { + if (!this.piece) + return; + if (!this.fits({ ...this.piece, y: this.piece.y + 1 }) && this.onGround) { + if (this.lockResets < MAX_RESETS) { + this.lockAcc = 0; + this.lockResets++; + } + } + } + // ─── Collision ──────────────────────────────────────────────────────────────── + fits(p) { + const shape = SHAPES[p.type][p.rot]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = p.x + c; + const by = p.y + r; + if (bx < 0 || bx >= COLS || by >= ROWS) + return false; + if (by >= 0 && this.board[by][bx] !== null) + return false; + } + } + return true; + } + // ─── Lock & line‑clear ──────────────────────────────────────────────────────── + lockPiece() { + if (!this.piece) + return; + const { type, x, y, rot } = this.piece; + const shape = SHAPES[type][rot]; + let aboveBoard = false; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + if (y + r < 0) { + aboveBoard = true; + continue; + } + this.board[y + r][x + c] = COLORS[type]; + } + } + this.piece = null; + if (aboveBoard) { + this.endGame(); + return; + } + // Detect full rows + const full = []; + for (let row = 0; row < ROWS; row++) { + if (this.board[row].every(c => c !== null)) + full.push(row); + } + if (full.length > 0) { + this.clearRows = full; + this.clearAcc = 0; + this.score += LINE_SCORE[full.length] * this.level; + this.lines += full.length; + this.level = Math.floor(this.lines / LINES_PER_LEVEL) + 1; + this.updateStats(); + } + else { + this.spawnPiece(); + } + } + finishClear() { + // Remove rows from bottom‑up to keep indices stable + for (const row of [...this.clearRows].sort((a, b) => b - a)) { + this.board.splice(row, 1); + this.board.unshift(Array(COLS).fill(null)); + } + this.clearRows = []; + this.spawnPiece(); + } + // ─── Ghost piece ────────────────────────────────────────────────────────────── + ghostY() { + if (!this.piece) + return 0; + let gy = this.piece.y; + while (this.fits({ ...this.piece, y: gy + 1 })) + gy++; + return gy; + } + // ─── Main loop ──────────────────────────────────────────────────────────────── + loop(ts) { + const dt = Math.min(ts - this.lastTs, 100); // cap delta to avoid spiral + this.lastTs = ts; + if (this.state !== 'playing') + return; + // ── Line‑clear animation ──────────────────────────────────────────────── + if (this.clearRows.length > 0) { + this.clearAcc += dt; + if (this.clearAcc >= CLEAR_MS) + this.finishClear(); + this.draw(); + this.rafId = requestAnimationFrame(t => this.loop(t)); + return; + } + if (!this.piece) { + this.rafId = requestAnimationFrame(t => this.loop(t)); + return; + } + // ── DAS / ARR ─────────────────────────────────────────────────────────── + this.handleDAS(dt); + // ── Gravity ───────────────────────────────────────────────────────────── + this.fallAcc += dt; + if (this.fallAcc >= this.fallMs()) { + this.fallAcc -= this.fallMs(); + if (this.fits({ ...this.piece, y: this.piece.y + 1 })) { + this.piece.y++; + this.onGround = false; + } + } + // ── Lock delay ────────────────────────────────────────────────────────── + const canFall = this.fits({ ...this.piece, y: this.piece.y + 1 }); + if (!canFall) { + if (!this.onGround) { + this.onGround = true; + this.lockAcc = 0; + } + this.lockAcc += dt; + if (this.lockAcc >= LOCK_DELAY) + this.lockPiece(); + } + else { + if (this.onGround) { + this.onGround = false; + this.lockAcc = 0; + this.lockResets = 0; + } + } + this.draw(); + this.rafId = requestAnimationFrame(t => this.loop(t)); + } + // ─── Drawing ───────────────────────────────────────────────────────────────── + draw() { + this.drawBoard(); + this.drawHold(); + this.drawNext(); + } + drawBoard() { + const ctx = this.ctx; + const W = COLS * BLOCK; + const H = ROWS * BLOCK; + // Background + ctx.fillStyle = '#0d1117'; + ctx.fillRect(0, 0, W, H); + // Subtle grid lines + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK + 0.5, 0); + ctx.lineTo(c * BLOCK + 0.5, H); + ctx.stroke(); + } + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK + 0.5); + ctx.lineTo(W, r * BLOCK + 0.5); + ctx.stroke(); + } + // Locked cells (with optional line‑clear flash) + const flashPhase = Math.floor(this.clearAcc / 70) % 2 === 0; + for (let r = 0; r < ROWS; r++) { + const isClear = this.clearRows.includes(r); + for (let c = 0; c < COLS; c++) { + const cell = this.board[r][c]; + if (!cell) + continue; + if (isClear) { + // Alternating white flash + const col = flashPhase ? '#ffffff' : cell; + this.drawCell(ctx, c * BLOCK, r * BLOCK, BLOCK, col, 1); + } + else { + this.drawCell(ctx, c * BLOCK, r * BLOCK, BLOCK, cell, 1); + } + } + } + if (this.clearRows.length > 0) + return; // Don't draw live piece during clear animation + // Ghost piece + if (this.piece && this.state === 'playing') { + const gy = this.ghostY(); + if (gy > this.piece.y) + this.drawPiece(ctx, this.piece, gy, BLOCK, true); + } + // Active piece + if (this.piece) { + this.drawPiece(ctx, this.piece, this.piece.y, BLOCK, false); + } + // Lock‑delay gauge: thin bar at bottom of lowest cell when almost locking + if (this.piece && this.onGround && this.lockAcc > 0) { + const ratio = Math.min(this.lockAcc / LOCK_DELAY, 1); + const shape = SHAPES[this.piece.type][this.piece.rot]; + let maxRow = 0; + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c] && r > maxRow) + maxRow = r; + const barY = (this.piece.y + maxRow + 1) * BLOCK - 3; + const barX = this.piece.x * BLOCK; + const barW = shape[0].length * BLOCK; + ctx.fillStyle = 'rgba(255,255,255,0.15)'; + ctx.fillRect(barX, barY, barW, 3); + ctx.fillStyle = COLORS[this.piece.type]; + ctx.globalAlpha = 0.6; + ctx.fillRect(barX, barY, barW * (1 - ratio), 3); + ctx.globalAlpha = 1; + } + } + drawPiece(ctx, p, drawY, bs, ghost) { + const shape = SHAPES[p.type][p.rot]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const px = (p.x + c) * bs; + const py = (drawY + r) * bs; + if (py + bs <= 0) + continue; // above viewport + if (ghost) + this.drawGhost(ctx, px, py, bs, COLORS[p.type]); + else + this.drawCell(ctx, px, py, bs, COLORS[p.type], 1); + } + } + } + /** Draw a filled, bevelled block. */ + drawCell(ctx, x, y, s, color, alpha) { + ctx.save(); + ctx.globalAlpha = alpha; + const p = 1; // padding + // Main face + ctx.fillStyle = color; + ctx.fillRect(x + p, y + p, s - p * 2, s - p * 2); + // Top‑left highlight + ctx.fillStyle = 'rgba(255,255,255,0.28)'; + ctx.fillRect(x + p, y + p, s - p * 2, 4); + ctx.fillRect(x + p, y + p, 4, s - p * 2); + // Bottom‑right shadow + ctx.fillStyle = 'rgba(0,0,0,0.30)'; + ctx.fillRect(x + p, y + s - p - 4, s - p * 2, 4); + ctx.fillRect(x + s - p - 4, y + p, 4, s - p * 2); + ctx.restore(); + } + /** Draw a ghost‑piece outline. */ + drawGhost(ctx, x, y, s, color) { + ctx.save(); + ctx.globalAlpha = 0.18; + ctx.fillStyle = color; + ctx.fillRect(x + 1, y + 1, s - 2, s - 2); + ctx.globalAlpha = 0.55; + ctx.strokeStyle = color; + ctx.lineWidth = 1.5; + ctx.strokeRect(x + 2.5, y + 2.5, s - 5, s - 5); + ctx.restore(); + } + // ─── Side panels ───────────────────────────────────────────────────────────── + drawHold() { + const ctx = this.holdCtx; + const { width: w, height: h } = this.holdCvs; + ctx.fillStyle = '#0d1117'; + ctx.fillRect(0, 0, w, h); + if (this.holdType) + this.drawMini(ctx, this.holdType, w, h, PB, this.holdUsed ? 0.35 : 1); + } + drawNext() { + const pieces = this.bag.peek(5); + for (let i = 0; i < 5; i++) { + const ctx = this.nextCtxs[i]; + const cvs = this.nextCvss[i]; + ctx.fillStyle = '#0d1117'; + ctx.fillRect(0, 0, cvs.width, cvs.height); + if (pieces[i]) + this.drawMini(ctx, pieces[i], cvs.width, cvs.height, i === 0 ? PB : PB - 4, 1); + } + } + /** Draw a piece centred inside a small canvas (used for hold/next). */ + drawMini(ctx, type, w, h, bs, alpha) { + const shape = SHAPES[type][0]; + let rMin = shape.length, rMax = -1, cMin = shape[0].length, cMax = -1; + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c]) { + rMin = Math.min(rMin, r); + rMax = Math.max(rMax, r); + cMin = Math.min(cMin, c); + cMax = Math.max(cMax, c); + } + if (rMax < 0) + return; + const pw = (cMax - cMin + 1) * bs; + const ph = (rMax - rMin + 1) * bs; + const ox = Math.floor((w - pw) / 2); + const oy = Math.floor((h - ph) / 2); + for (let r = rMin; r <= rMax; r++) + for (let c = cMin; c <= cMax; c++) + if (shape[r][c]) + this.drawCell(ctx, ox + (c - cMin) * bs, oy + (r - rMin) * bs, bs, COLORS[type], alpha); + } + // ─── UI helpers ─────────────────────────────────────────────────────────────── + updateStats() { + this.scoreEl.textContent = this.score.toLocaleString(); + this.linesEl.textContent = this.lines.toString(); + this.levelEl.textContent = this.level.toString(); + } + showOverlay(title, body, sub) { + this.msgEl.innerHTML = + `<div class="ov-title">${title}</div>` + + (body ? `<div class="ov-body">${body}</div>` : '') + + `<div class="ov-sub">${sub}</div>`; + this.overlayEl.classList.remove('hidden'); + } +} +// ─── Bootstrap ──────────────────────────────────────────────────────────────── +document.addEventListener('DOMContentLoaded', () => { new TetrisGame(); }); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run1/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CA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CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAE,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAC,CAAE,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/tetris.js @@ -0,0 +1,626 @@ +"use strict"; +// ───────────────────────────────────────────────────────────── +// Constants +// ───────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell +// ───────────────────────────────────────────────────────────── +// Piece definitions +// ───────────────────────────────────────────────────────────── +const COLORS = { + I: '#00e5e5', + O: '#e5e500', + T: '#aa00ff', + S: '#00cc44', + Z: '#ee2222', + J: '#2255ee', + L: '#ee8800', +}; +/** Spawn-state (rotation 0) matrices */ +const SHAPES = { + I: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + O: [ + [1, 1], + [1, 1], + ], + T: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + S: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + Z: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + J: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + L: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], +}; +// ───────────────────────────────────────────────────────────── +// SRS wall-kick tables (screen coords: y-down) +// Derived from the Tetris Guideline by negating the y component. +// ───────────────────────────────────────────────────────────── +const KICKS_JLSTZ = { + '0->1': [[0, 0], [-1, 0], [-1, -1], [0, +2], [-1, +2]], + '1->0': [[0, 0], [+1, 0], [+1, +1], [0, -2], [+1, -2]], + '1->2': [[0, 0], [+1, 0], [+1, +1], [0, -2], [+1, -2]], + '2->1': [[0, 0], [-1, 0], [-1, -1], [0, +2], [-1, +2]], + '2->3': [[0, 0], [+1, 0], [+1, -1], [0, +2], [+1, +2]], + '3->2': [[0, 0], [-1, 0], [-1, +1], [0, -2], [-1, -2]], + '3->0': [[0, 0], [-1, 0], [-1, +1], [0, -2], [-1, -2]], + '0->3': [[0, 0], [+1, 0], [+1, -1], [0, +2], [+1, +2]], +}; +const KICKS_I = { + '0->1': [[0, 0], [-2, 0], [+1, 0], [-2, +1], [+1, -2]], + '1->0': [[0, 0], [+2, 0], [-1, 0], [+2, -1], [-1, +2]], + '1->2': [[0, 0], [-1, 0], [+2, 0], [-1, -2], [+2, +1]], + '2->1': [[0, 0], [+1, 0], [-2, 0], [+1, +2], [-2, -1]], + '2->3': [[0, 0], [+2, 0], [-1, 0], [+2, -1], [-1, +2]], + '3->2': [[0, 0], [-2, 0], [+1, 0], [-2, +1], [+1, -2]], + '3->0': [[0, 0], [+1, 0], [-2, 0], [+1, +2], [-2, -1]], + '0->3': [[0, 0], [-1, 0], [+2, 0], [-1, -2], [+2, +1]], +}; +// ───────────────────────────────────────────────────────────── +// Scoring +// ───────────────────────────────────────────────────────────── +const LINE_SCORE = [0, 100, 300, 500, 800]; // indexed by lines cleared +/** Drop speed: milliseconds per automatic row drop, by level */ +function dropInterval(level) { + return Math.max(50, Math.round(800 - (level - 1) * 72)); +} +// ───────────────────────────────────────────────────────────── +// TetrisGame class +// ───────────────────────────────────────────────────────────── +class TetrisGame { + // ── Constructor ───────────────────────────────────────────── + constructor() { + // Game state + this.board = []; + this.current = null; + this.next = null; + this.held = null; + this.canHold = true; + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameOver = false; + this.paused = false; + // Timing + this.dropMs = 800; + this.dropAcc = 0; + this.lastTime = 0; + this.rafId = 0; + // 7-bag randomiser + this.bag = []; + // DAS / ARR for horizontal movement + this.DAS = 150; // ms before auto-repeat + this.ARR = 50; // ms between auto-repeat steps + this.dasTimer = null; + this.arrTimer = null; + // Soft-drop repeat + this.sdTimer = null; + this.boardCanvas = document.getElementById('board'); + this.boardCtx = this.boardCanvas.getContext('2d'); + this.nextCanvas = document.getElementById('next-canvas'); + this.nextCtx = this.nextCanvas.getContext('2d'); + this.holdCanvas = document.getElementById('hold-canvas'); + this.holdCtx = this.holdCanvas.getContext('2d'); + this.boardCanvas.width = COLS * BLOCK; + this.boardCanvas.height = ROWS * BLOCK; + this.bindKeys(); + this.newGame(); + } + // ── Game lifecycle ─────────────────────────────────────────── + newGame() { + this.board = Array.from({ length: ROWS }, () => new Array(COLS).fill(null)); + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameOver = false; + this.paused = false; + this.canHold = true; + this.held = null; + this.bag = []; + this.dropMs = dropInterval(1); + this.dropAcc = 0; + this.lastTime = 0; + this.stopDAS(); + this.stopSD(); + this.next = this.makePiece(); + this.spawn(); + this.updateStats(); + this.renderSide(this.holdCtx, this.holdCanvas, null); + this.renderSide(this.nextCtx, this.nextCanvas, this.next); + cancelAnimationFrame(this.rafId); + this.rafId = requestAnimationFrame(t => this.loop(t)); + } + // ── Bag / piece creation ───────────────────────────────────── + nextFromBag() { + if (this.bag.length === 0) { + this.bag = Object.keys(SHAPES); + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop(); + } + makePiece(type) { + const t = type !== null && type !== void 0 ? type : this.nextFromBag(); + const matrix = SHAPES[t].map(row => [...row]); + const x = Math.floor((COLS - matrix[0].length) / 2); + // Place piece so its first occupied row starts at board row 0 + let firstRow = 0; + for (let r = 0; r < matrix.length; r++) { + if (matrix[r].some(v => v !== 0)) { + firstRow = r; + break; + } + } + return { type: t, matrix, x, y: -firstRow, rotation: 0 }; + } + spawn() { + this.current = this.next; + this.next = this.makePiece(); + this.canHold = true; + this.renderSide(this.nextCtx, this.nextCanvas, this.next); + if (this.current && !this.valid(this.current, this.current.x, this.current.y)) { + this.gameOver = true; + this.current = null; + } + } + // ── Collision ──────────────────────────────────────────────── + valid(piece, px, py, mat) { + const m = mat !== null && mat !== void 0 ? mat : piece.matrix; + for (let r = 0; r < m.length; r++) { + for (let c = 0; c < m[r].length; c++) { + if (!m[r][c]) + continue; + const nx = px + c; + const ny = py + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return false; + if (ny >= 0 && this.board[ny][nx] !== null) + return false; + } + } + return true; + } + // ── Rotation (SRS) ─────────────────────────────────────────── + rotateCW(m) { + const R = m.length, C = m[0].length; + const out = Array.from({ length: C }, () => new Array(R).fill(0)); + for (let r = 0; r < R; r++) + for (let c = 0; c < C; c++) + out[c][R - 1 - r] = m[r][c]; + return out; + } + rotateCCW(m) { + const R = m.length, C = m[0].length; + const out = Array.from({ length: C }, () => new Array(R).fill(0)); + for (let r = 0; r < R; r++) + for (let c = 0; c < C; c++) + out[C - 1 - c][r] = m[r][c]; + return out; + } + rotate(dir) { + var _a; + const p = this.current; + if (!p || this.gameOver || this.paused) + return; + const newMat = dir === 1 ? this.rotateCW(p.matrix) : this.rotateCCW(p.matrix); + const newRot = (p.rotation + (dir === 1 ? 1 : 3)) % 4; + const key = `${p.rotation}->${newRot}`; + const kicks = p.type === 'I' ? KICKS_I : KICKS_JLSTZ; + const tests = (_a = kicks[key]) !== null && _a !== void 0 ? _a : [[0, 0]]; + for (const [dx, dy] of tests) { + if (this.valid(p, p.x + dx, p.y + dy, newMat)) { + p.matrix = newMat; + p.x += dx; + p.y += dy; + p.rotation = newRot; + return; + } + } + } + // ── Movement ───────────────────────────────────────────────── + moveLeft() { + const p = this.current; + if (!p || this.gameOver || this.paused) + return; + if (this.valid(p, p.x - 1, p.y)) + p.x--; + } + moveRight() { + const p = this.current; + if (!p || this.gameOver || this.paused) + return; + if (this.valid(p, p.x + 1, p.y)) + p.x++; + } + softDrop() { + const p = this.current; + if (!p || this.gameOver || this.paused) + return; + if (this.valid(p, p.x, p.y + 1)) { + p.y++; + this.score++; + this.dropAcc = 0; + } + else { + this.lock(); + } + } + hardDrop() { + const p = this.current; + if (!p || this.gameOver || this.paused) + return; + let dist = 0; + while (this.valid(p, p.x, p.y + 1)) { + p.y++; + dist++; + } + this.score += dist * 2; + this.lock(); + } + // ── Hold ───────────────────────────────────────────────────── + holdPiece() { + const p = this.current; + if (!p || !this.canHold || this.gameOver || this.paused) + return; + const curType = p.type; + if (this.held !== null) { + const heldType = this.held.type; + this.held = this.makePiece(curType); + this.current = this.makePiece(heldType); + } + else { + this.held = this.makePiece(curType); + this.current = this.next; + this.next = this.makePiece(); + this.renderSide(this.nextCtx, this.nextCanvas, this.next); + } + // Game-over check for the newly active piece + if (!this.valid(this.current, this.current.x, this.current.y)) { + this.gameOver = true; + this.current = null; + } + this.canHold = false; + this.dropAcc = 0; + this.renderSide(this.holdCtx, this.holdCanvas, this.held); + } + // ── Locking & line clear ───────────────────────────────────── + lock() { + const p = this.current; + if (!p) + return; + for (let r = 0; r < p.matrix.length; r++) { + for (let c = 0; c < p.matrix[r].length; c++) { + if (!p.matrix[r][c]) + continue; + const row = p.y + r; + const col = p.x + c; + if (row < 0) { + this.gameOver = true; + this.current = null; + return; + } + this.board[row][col] = COLORS[p.type]; + } + } + this.clearLines(); + this.spawn(); + this.dropAcc = 0; + } + clearLines() { + var _a; + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every(c => c !== null)) { + this.board.splice(r, 1); + this.board.unshift(new Array(COLS).fill(null)); + cleared++; + r++; // recheck this index + } + } + if (cleared === 0) + return; + this.lines += cleared; + this.score += ((_a = LINE_SCORE[cleared]) !== null && _a !== void 0 ? _a : 800) * this.level; + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel > this.level) { + this.level = newLevel; + this.dropMs = dropInterval(this.level); + } + this.updateStats(); + } + // ── Ghost ──────────────────────────────────────────────────── + ghostY() { + const p = this.current; + if (!p) + return 0; + let gy = p.y; + while (this.valid(p, p.x, gy + 1)) + gy++; + return gy; + } + // ── Main loop ──────────────────────────────────────────────── + loop(time) { + const delta = time - this.lastTime; + this.lastTime = time; + if (!this.paused && !this.gameOver) { + this.dropAcc += delta; + if (this.dropAcc >= this.dropMs) { + this.dropAcc = 0; + const p = this.current; + if (p) { + if (this.valid(p, p.x, p.y + 1)) + p.y++; + else + this.lock(); + } + } + } + this.render(); + this.rafId = requestAnimationFrame(t => this.loop(t)); + } + // ── Rendering ──────────────────────────────────────────────── + drawBlock(ctx, col, row, color, size = BLOCK, alpha = 1) { + if (row < 0) + return; + ctx.globalAlpha = alpha; + const x = col * size + 1; + const y = row * size + 1; + const s = size - 2; + // Fill + ctx.fillStyle = color; + ctx.fillRect(x, y, s, s); + // Top-left highlight + ctx.fillStyle = 'rgba(255,255,255,0.28)'; + ctx.fillRect(x, y, s, 4); + ctx.fillRect(x, y, 4, s); + // Bottom-right shadow + ctx.fillStyle = 'rgba(0,0,0,0.30)'; + ctx.fillRect(x, y + s - 4, s, 4); + ctx.fillRect(x + s - 4, y, 4, s); + ctx.globalAlpha = 1; + } + render() { + const { boardCtx: ctx, boardCanvas: cv } = this; + // Background + ctx.fillStyle = '#111128'; + ctx.fillRect(0, 0, cv.width, cv.height); + // Grid + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let r = 0; r < ROWS; r++) + for (let c = 0; c < COLS; c++) + ctx.strokeRect(c * BLOCK, r * BLOCK, BLOCK, BLOCK); + // Locked cells + for (let r = 0; r < ROWS; r++) + for (let c = 0; c < COLS; c++) + if (this.board[r][c]) + this.drawBlock(ctx, c, r, this.board[r][c]); + // Ghost piece + if (this.current && !this.gameOver) { + const gy = this.ghostY(); + const p = this.current; + for (let r = 0; r < p.matrix.length; r++) + for (let c = 0; c < p.matrix[r].length; c++) + if (p.matrix[r][c]) + this.drawBlock(ctx, p.x + c, gy + r, COLORS[p.type], BLOCK, 0.18); + } + // Active piece + if (this.current) { + const p = this.current; + for (let r = 0; r < p.matrix.length; r++) + for (let c = 0; c < p.matrix[r].length; c++) + if (p.matrix[r][c]) + this.drawBlock(ctx, p.x + c, p.y + r, COLORS[p.type]); + } + // ── Overlays ──────────────────────────────────────────────── + if (this.gameOver) { + ctx.fillStyle = 'rgba(0,0,0,0.72)'; + ctx.fillRect(0, 0, cv.width, cv.height); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = '#ff4444'; + ctx.font = 'bold 34px "Courier New", monospace'; + ctx.fillText('GAME OVER', cv.width / 2, cv.height / 2 - 52); + ctx.fillStyle = '#ddddff'; + ctx.font = '18px "Courier New", monospace'; + ctx.fillText(`Score: ${this.score.toLocaleString()}`, cv.width / 2, cv.height / 2 - 8); + ctx.font = '14px "Courier New", monospace'; + ctx.fillStyle = '#aaaacc'; + ctx.fillText('Press R to restart', cv.width / 2, cv.height / 2 + 34); + } + if (this.paused && !this.gameOver) { + ctx.fillStyle = 'rgba(0,0,0,0.60)'; + ctx.fillRect(0, 0, cv.width, cv.height); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = '#ffffff'; + ctx.font = 'bold 34px "Courier New", monospace'; + ctx.fillText('PAUSED', cv.width / 2, cv.height / 2 - 22); + ctx.font = '14px "Courier New", monospace'; + ctx.fillStyle = '#aaaacc'; + ctx.fillText('Press P to resume', cv.width / 2, cv.height / 2 + 18); + } + } + /** Renders a piece preview onto the hold/next mini-canvases */ + renderSide(ctx, canvas, piece) { + ctx.fillStyle = '#0e0e22'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + if (!piece) + return; + const BS = 22; // block size for preview + const m = piece.matrix; + const R = m.length, C = m[0].length; + // Bounding box of occupied cells + let minR = R, maxR = 0, minC = C, maxC = 0; + for (let r = 0; r < R; r++) + for (let c = 0; c < C; c++) + if (m[r][c]) { + if (r < minR) + minR = r; + if (r > maxR) + maxR = r; + if (c < minC) + minC = c; + if (c > maxC) + maxC = c; + } + const pw = (maxC - minC + 1) * BS; + const ph = (maxR - minR + 1) * BS; + const ox = Math.floor((canvas.width - pw) / 2); + const oy = Math.floor((canvas.height - ph) / 2); + const color = COLORS[piece.type]; + for (let r = minR; r <= maxR; r++) { + for (let c = minC; c <= maxC; c++) { + if (!m[r][c]) + continue; + const bx = ox + (c - minC) * BS + 1; + const by = oy + (r - minR) * BS + 1; + const s = BS - 2; + ctx.fillStyle = color; + ctx.fillRect(bx, by, s, s); + ctx.fillStyle = 'rgba(255,255,255,0.28)'; + ctx.fillRect(bx, by, s, 4); + ctx.fillRect(bx, by, 4, s); + ctx.fillStyle = 'rgba(0,0,0,0.30)'; + ctx.fillRect(bx, by + s - 4, s, 4); + ctx.fillRect(bx + s - 4, by, 4, s); + } + } + } + // ── UI ─────────────────────────────────────────────────────── + updateStats() { + document.getElementById('score').textContent = + this.score.toLocaleString(); + document.getElementById('level').textContent = + String(this.level); + document.getElementById('lines').textContent = + String(this.lines); + } + // ── DAS / ARR ──────────────────────────────────────────────── + startDAS(dir) { + this.stopDAS(); + const fn = dir === 'left' ? () => this.moveLeft() : () => this.moveRight(); + fn(); // immediate first step + this.dasTimer = setTimeout(() => { + this.arrTimer = setInterval(fn, this.ARR); + }, this.DAS); + } + stopDAS() { + if (this.dasTimer !== null) { + clearTimeout(this.dasTimer); + this.dasTimer = null; + } + if (this.arrTimer !== null) { + clearInterval(this.arrTimer); + this.arrTimer = null; + } + } + startSD() { + this.softDrop(); + if (this.sdTimer === null) + this.sdTimer = setInterval(() => this.softDrop(), 50); + } + stopSD() { + if (this.sdTimer !== null) { + clearInterval(this.sdTimer); + this.sdTimer = null; + } + } + // ── Keyboard ───────────────────────────────────────────────── + bindKeys() { + document.addEventListener('keydown', e => { + if (e.repeat) + return; // DAS handles repeats manually + switch (e.code) { + case 'ArrowLeft': + e.preventDefault(); + this.startDAS('left'); + break; + case 'ArrowRight': + e.preventDefault(); + this.startDAS('right'); + break; + case 'ArrowDown': + e.preventDefault(); + this.startSD(); + break; + case 'ArrowUp': + e.preventDefault(); + this.rotate(1); + break; + case 'KeyX': + this.rotate(1); + break; + case 'KeyZ': + this.rotate(-1); + break; + case 'Space': + e.preventDefault(); + this.hardDrop(); + break; + case 'KeyC': + case 'ShiftLeft': + case 'ShiftRight': + this.holdPiece(); + break; + case 'KeyP': + case 'Escape': + if (!this.gameOver) { + this.paused = !this.paused; + if (!this.paused) { + // Reset timers so the piece doesn't teleport after unpausing + this.lastTime = performance.now(); + this.dropAcc = 0; + } + } + break; + case 'KeyR': + this.stopDAS(); + this.stopSD(); + this.newGame(); + break; + } + }); + document.addEventListener('keyup', e => { + switch (e.code) { + case 'ArrowLeft': + case 'ArrowRight': + this.stopDAS(); + break; + case 'ArrowDown': + this.stopSD(); + break; + } + }); + } +} +// ───────────────────────────────────────────────────────────── +// Bootstrap +// ───────────────────────────────────────────────────────────── +window.addEventListener('DOMContentLoaded', () => { new TetrisGame(); }); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=off_run3/dist/tetris.js @@ -0,0 +1,606 @@ +"use strict"; +// ============================================================ +// Tetris – Complete TypeScript implementation +// ============================================================ +// --------------- Constants --------------- +const COLS = 10; +const ROWS = 20; +const HIDDEN_ROWS = 2; // rows above visible area for spawn +const TOTAL_ROWS = ROWS + HIDDEN_ROWS; +const BLOCK_SIZE = 30; // px +const NEXT_BLOCK_SIZE = 24; // px +// Colors matching classic Tetris +const COLORS = { + I: "#00cfcf", + O: "#cfcf00", + T: "#9f00cf", + S: "#00cf00", + Z: "#cf0000", + J: "#0000cf", + L: "#cf7f00", +}; +// SRS (Super Rotation System) piece definitions +// Each piece has 4 rotation states +const PIECES = { + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + O: [ + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + ], + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +// SRS wall kick data for J, L, S, T, Z pieces +const WALL_KICKS_JLSTZ = { + "0>1": [{ x: 0, y: 0 }, { x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "1>0": [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], + "1>2": [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], + "2>1": [{ x: 0, y: 0 }, { x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "2>3": [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: -1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], + "3>2": [{ x: 0, y: 0 }, { x: -1, y: 0 }, { x: -1, y: 1 }, { x: 0, y: -2 }, { x: -1, y: -2 }], + "3>0": [{ x: 0, y: 0 }, { x: -1, y: 0 }, { x: -1, y: 1 }, { x: 0, y: -2 }, { x: -1, y: -2 }], + "0>3": [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: -1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], +}; +// SRS wall kick data for I piece +const WALL_KICKS_I = { + "0>1": [{ x: 0, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 1 }, { x: 1, y: -2 }], + "1>0": [{ x: 0, y: 0 }, { x: 2, y: 0 }, { x: -1, y: 0 }, { x: 2, y: -1 }, { x: -1, y: 2 }], + "1>2": [{ x: 0, y: 0 }, { x: -1, y: 0 }, { x: 2, y: 0 }, { x: -1, y: -2 }, { x: 2, y: 1 }], + "2>1": [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 2 }, { x: -2, y: -1 }], + "2>3": [{ x: 0, y: 0 }, { x: 2, y: 0 }, { x: -1, y: 0 }, { x: 2, y: -1 }, { x: -1, y: 2 }], + "3>2": [{ x: 0, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 1 }, { x: 1, y: -2 }], + "3>0": [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 2 }, { x: -2, y: -1 }], + "0>3": [{ x: 0, y: 0 }, { x: -1, y: 0 }, { x: 2, y: 0 }, { x: -1, y: -2 }, { x: 2, y: 1 }], +}; +// Scoring table: points for clearing n lines at once +const LINE_POINTS = [0, 100, 300, 500, 800]; +// Drop speed (ms per row) by level +function dropInterval(level) { + // Formula from original Tetris + return Math.max(50, Math.floor(1000 * Math.pow(0.85, level))); +} +// --------------- Bag randomizer --------------- +class BagRandomizer { + constructor() { + this.bag = []; + } + next() { + if (this.bag.length === 0) { + this.bag = Object.keys(PIECES); + // Fisher–Yates shuffle + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop(); + } +} +// --------------- Game state --------------- +class TetrisGame { + constructor() { + this.current = null; + this.next = null; + this.held = null; + this.canHold = true; + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + this.started = false; + this.dropTimer = 0; + this.lastTime = 0; + this.animFrameId = 0; + this.bag = new BagRandomizer(); + this.board = this.emptyBoard(); + this.canvas = document.getElementById("game-canvas"); + this.ctx = this.canvas.getContext("2d"); + this.nextCanvas = document.getElementById("next-canvas"); + this.nextCtx = this.nextCanvas.getContext("2d"); + this.holdCanvas = document.getElementById("hold-canvas"); + this.holdCtx = this.holdCanvas.getContext("2d"); + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.messageEl = document.getElementById("message-overlay"); + this.messageTextEl = document.getElementById("message-text"); + this.bindKeys(); + this.showMessage("TETRIS", "Press Enter or Space to start"); + this.render(); + } + emptyBoard() { + return Array.from({ length: TOTAL_ROWS }, () => Array(COLS).fill(null)); + } + spawnPiece(type) { + const t = type ?? this.bag.next(); + const rotations = PIECES[t]; + const shape = rotations[0]; + // Spawn near top of playfield + const startX = Math.floor((COLS - shape[0].length) / 2); + return { + shape: shape, + color: COLORS[t], + x: startX, + y: 0, // top of hidden area + rotationIndex: 0, + }; + } + pieceType(piece) { + return Object.keys(COLORS).find(k => COLORS[k] === piece.color); + } + start() { + this.board = this.emptyBoard(); + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + this.started = true; + this.canHold = true; + this.held = null; + this.bag = new BagRandomizer(); + this.next = this.spawnPiece(); + this.spawnNext(); + this.hideMessage(); + this.updateUI(); + cancelAnimationFrame(this.animFrameId); + this.lastTime = performance.now(); + this.loop(this.lastTime); + } + spawnNext() { + this.current = this.next; + this.next = this.spawnPiece(); + this.canHold = true; + if (!this.isValid(this.current, this.current.x, this.current.y, this.current.shape)) { + this.endGame(); + } + } + loop(time) { + const delta = time - this.lastTime; + this.lastTime = time; + if (!this.paused && !this.gameOver && this.started) { + this.dropTimer += delta; + const interval = dropInterval(this.level); + if (this.dropTimer >= interval) { + this.dropTimer = 0; + this.moveDown(); + } + } + this.render(); + this.animFrameId = requestAnimationFrame(t => this.loop(t)); + } + // --------------- Movement --------------- + isValid(piece, nx, ny, shape) { + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (!shape[row][col]) + continue; + const gx = nx + col; + const gy = ny + row; + if (gx < 0 || gx >= COLS) + return false; + if (gy >= TOTAL_ROWS) + return false; + if (gy >= 0 && this.board[gy][gx] !== null) + return false; + } + } + return true; + } + moveDown() { + if (!this.current) + return; + if (this.isValid(this.current, this.current.x, this.current.y + 1, this.current.shape)) { + this.current.y++; + } + else { + this.lockPiece(); + } + } + moveLeft() { + if (!this.current || this.paused || this.gameOver) + return; + if (this.isValid(this.current, this.current.x - 1, this.current.y, this.current.shape)) { + this.current.x--; + } + } + moveRight() { + if (!this.current || this.paused || this.gameOver) + return; + if (this.isValid(this.current, this.current.x + 1, this.current.y, this.current.shape)) { + this.current.x++; + } + } + softDrop() { + if (!this.current || this.paused || this.gameOver) + return; + if (this.isValid(this.current, this.current.x, this.current.y + 1, this.current.shape)) { + this.current.y++; + this.score += 1; + this.scoreEl.textContent = String(this.score); + this.dropTimer = 0; + } + } + hardDrop() { + if (!this.current || this.paused || this.gameOver) + return; + let dropped = 0; + while (this.isValid(this.current, this.current.x, this.current.y + 1, this.current.shape)) { + this.current.y++; + dropped++; + } + this.score += dropped * 2; + this.dropTimer = 0; + this.lockPiece(); + } + rotate(dir) { + if (!this.current || this.paused || this.gameOver) + return; + const type = this.pieceType(this.current); + const rotations = PIECES[type]; + const fromRot = this.current.rotationIndex; + const toRot = (fromRot + dir + 4) % 4; + const newShape = rotations[toRot]; + const kickKey = `${fromRot}>${toRot}`; + const kicks = type === "I" ? WALL_KICKS_I : WALL_KICKS_JLSTZ; + const kickData = kicks[kickKey] ?? [{ x: 0, y: 0 }]; + for (const kick of kickData) { + const nx = this.current.x + kick.x; + const ny = this.current.y - kick.y; // SRS uses opposite y convention + if (this.isValid(this.current, nx, ny, newShape)) { + this.current.x = nx; + this.current.y = ny; + this.current.shape = newShape; + this.current.rotationIndex = toRot; + return; + } + } + } + hold() { + if (!this.current || !this.canHold || this.paused || this.gameOver) + return; + this.canHold = false; + const type = this.pieceType(this.current); + if (this.held === null) { + this.held = this.spawnPiece(type); + this.spawnNext(); + } + else { + const heldType = this.pieceType(this.held); + this.held = this.spawnPiece(type); + this.current = this.spawnPiece(heldType); + } + } + lockPiece() { + if (!this.current) + return; + // Place piece on board + const shape = this.current.shape; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (!shape[row][col]) + continue; + const gy = this.current.y + row; + const gx = this.current.x + col; + if (gy >= 0 && gy < TOTAL_ROWS && gx >= 0 && gx < COLS) { + this.board[gy][gx] = this.current.color; + } + } + } + this.clearLines(); + this.spawnNext(); + } + clearLines() { + let cleared = 0; + for (let row = TOTAL_ROWS - 1; row >= 0; row--) { + if (this.board[row].every(cell => cell !== null)) { + this.board.splice(row, 1); + this.board.unshift(Array(COLS).fill(null)); + cleared++; + row++; // recheck same index after splice + } + } + if (cleared > 0) { + this.lines += cleared; + this.score += LINE_POINTS[cleared] * (this.level + 1); + this.level = Math.floor(this.lines / 10); + this.updateUI(); + } + } + endGame() { + this.gameOver = true; + this.showMessage("GAME OVER", `Score: ${this.score}\nPress Enter or Space to restart`); + } + togglePause() { + if (!this.started || this.gameOver) + return; + this.paused = !this.paused; + if (this.paused) { + this.showMessage("PAUSED", "Press P or Escape to resume"); + } + else { + this.hideMessage(); + this.lastTime = performance.now(); + } + } + // --------------- Ghost piece --------------- + getGhostY() { + if (!this.current) + return 0; + let gy = this.current.y; + while (this.isValid(this.current, this.current.x, gy + 1, this.current.shape)) { + gy++; + } + return gy; + } + // --------------- Rendering --------------- + render() { + this.drawBoard(); + this.drawNext(); + this.drawHold(); + } + drawBoard() { + const ctx = this.ctx; + const W = COLS * BLOCK_SIZE; + const H = ROWS * BLOCK_SIZE; + // Background + ctx.fillStyle = "#0a0a1a"; + ctx.fillRect(0, 0, W, H); + // Draw grid lines + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + ctx.lineWidth = 0.5; + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, H); + ctx.stroke(); + } + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(W, r * BLOCK_SIZE); + ctx.stroke(); + } + // Draw locked pieces (skip hidden rows) + for (let row = HIDDEN_ROWS; row < TOTAL_ROWS; row++) { + for (let col = 0; col < COLS; col++) { + const color = this.board[row][col]; + if (color) { + this.drawBlock(ctx, col, row - HIDDEN_ROWS, color, BLOCK_SIZE); + } + } + } + // Ghost piece + if (this.current && !this.gameOver) { + const ghostY = this.getGhostY(); + const shape = this.current.shape; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (!shape[row][col]) + continue; + const gy = ghostY + row - HIDDEN_ROWS; + if (gy < 0) + continue; + this.drawGhostBlock(ctx, this.current.x + col, gy, this.current.color, BLOCK_SIZE); + } + } + } + // Current piece + if (this.current && !this.gameOver) { + const shape = this.current.shape; + for (let row = 0; row < shape.length; row++) { + for (let col = 0; col < shape[row].length; col++) { + if (!shape[row][col]) + continue; + const gy = this.current.y + row - HIDDEN_ROWS; + if (gy < 0) + continue; + this.drawBlock(ctx, this.current.x + col, gy, this.current.color, BLOCK_SIZE); + } + } + } + } + drawBlock(ctx, x, y, color, size) { + const px = x * size; + const py = y * size; + const pad = 1; + // Main fill + ctx.fillStyle = color; + ctx.fillRect(px + pad, py + pad, size - pad * 2, size - pad * 2); + // Highlight (top-left) + ctx.fillStyle = "rgba(255,255,255,0.35)"; + ctx.fillRect(px + pad, py + pad, size - pad * 2, 3); + ctx.fillRect(px + pad, py + pad, 3, size - pad * 2); + // Shadow (bottom-right) + ctx.fillStyle = "rgba(0,0,0,0.35)"; + ctx.fillRect(px + pad, py + size - pad - 3, size - pad * 2, 3); + ctx.fillRect(px + size - pad - 3, py + pad, 3, size - pad * 2); + } + drawGhostBlock(ctx, x, y, color, size) { + const px = x * size; + const py = y * size; + const pad = 1; + ctx.strokeStyle = color; + ctx.globalAlpha = 0.3; + ctx.lineWidth = 2; + ctx.strokeRect(px + pad, py + pad, size - pad * 2, size - pad * 2); + ctx.globalAlpha = 1; + } + drawNext() { + const ctx = this.nextCtx; + const W = this.nextCanvas.width; + const H = this.nextCanvas.height; + ctx.fillStyle = "#0a0a1a"; + ctx.fillRect(0, 0, W, H); + if (!this.next) + return; + this.drawMiniPiece(ctx, this.next, W, H, NEXT_BLOCK_SIZE); + } + drawHold() { + const ctx = this.holdCtx; + const W = this.holdCanvas.width; + const H = this.holdCanvas.height; + ctx.fillStyle = "#0a0a1a"; + ctx.fillRect(0, 0, W, H); + if (!this.held) + return; + ctx.globalAlpha = this.canHold ? 1.0 : 0.4; + this.drawMiniPiece(ctx, this.held, W, H, NEXT_BLOCK_SIZE); + ctx.globalAlpha = 1.0; + } + drawMiniPiece(ctx, piece, W, H, size) { + const shape = PIECES[this.pieceType(piece)][0]; + const rows = shape.length; + const cols = shape[0].length; + const totalW = cols * size; + const totalH = rows * size; + const offX = Math.floor((W - totalW) / 2); + const offY = Math.floor((H - totalH) / 2); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (!shape[r][c]) + continue; + const px = offX + c * size; + const py = offY + r * size; + const pad = 1; + ctx.fillStyle = piece.color; + ctx.fillRect(px + pad, py + pad, size - pad * 2, size - pad * 2); + ctx.fillStyle = "rgba(255,255,255,0.35)"; + ctx.fillRect(px + pad, py + pad, size - pad * 2, 3); + ctx.fillRect(px + pad, py + pad, 3, size - pad * 2); + ctx.fillStyle = "rgba(0,0,0,0.35)"; + ctx.fillRect(px + pad, py + size - pad - 3, size - pad * 2, 3); + ctx.fillRect(px + size - pad - 3, py + pad, 3, size - pad * 2); + } + } + } + // --------------- UI helpers --------------- + updateUI() { + this.scoreEl.textContent = String(this.score); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + } + showMessage(title, subtitle) { + this.messageTextEl.innerHTML = `<div class="msg-title">${title}</div><div class="msg-sub">${subtitle}</div>`; + this.messageEl.style.display = "flex"; + } + hideMessage() { + this.messageEl.style.display = "none"; + } + // --------------- Key bindings --------------- + bindKeys() { + const keyState = {}; + const DAS_DELAY = 170; // ms before auto-repeat + const DAS_RATE = 50; // ms between repeats + const dasTimers = {}; + const dasIntervals = {}; + const startDAS = (key, action) => { + action(); + dasTimers[key] = setTimeout(() => { + dasIntervals[key] = setInterval(action, DAS_RATE); + }, DAS_DELAY); + }; + const stopDAS = (key) => { + clearTimeout(dasTimers[key]); + clearInterval(dasIntervals[key]); + }; + document.addEventListener("keydown", (e) => { + if (keyState[e.code]) + return; // already held + keyState[e.code] = true; + if (e.code === "Enter" || e.code === "Space") { + e.preventDefault(); + if (!this.started || this.gameOver) { + this.start(); + return; + } + } + if (e.code === "KeyP" || e.code === "Escape") { + e.preventDefault(); + this.togglePause(); + return; + } + if (this.paused || !this.started || this.gameOver) + return; + switch (e.code) { + case "ArrowLeft": + e.preventDefault(); + startDAS("ArrowLeft", () => this.moveLeft()); + break; + case "ArrowRight": + e.preventDefault(); + startDAS("ArrowRight", () => this.moveRight()); + break; + case "ArrowDown": + e.preventDefault(); + startDAS("ArrowDown", () => this.softDrop()); + break; + case "ArrowUp": + case "KeyX": + e.preventDefault(); + this.rotate(1); + break; + case "KeyZ": + case "ControlLeft": + case "ControlRight": + e.preventDefault(); + this.rotate(-1); + break; + case "Space": + e.preventDefault(); + this.hardDrop(); + break; + case "ShiftLeft": + case "ShiftRight": + case "KeyC": + e.preventDefault(); + this.hold(); + break; + } + }); + document.addEventListener("keyup", (e) => { + keyState[e.code] = false; + stopDAS(e.code); + }); + } +} +// --------------- Bootstrap --------------- +window.addEventListener("load", () => { + new TetrisGame(); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,523 @@ +"use strict"; +// ============================================================ +// Tetris – fully playable browser implementation in TypeScript +// ============================================================ +// --------------- Constants ---------------------------------- +const COLS = 10; +const ROWS = 20; +const CELL = 30; // px per cell +const PREVIEW_CELL = 25; +// Colours per tetromino type (0 = empty) +const COLORS = [ + "", // 0 – empty + "#00f0f0", // 1 – I cyan + "#f0a000", // 2 – J orange (actually J is blue, but classic NES uses this) + "#0000f0", // 3 – J blue + "#f00000", // 4 – S red + "#00f000", // 5 – Z green (swapped for contrast) + "#a000f0", // 6 – T purple + "#f0f000", // 7 – O yellow +]; +// Each piece defined as [color_index, ...rotation_matrices (flat arrays, 4×4)] +// Rotations listed as 0°, 90°, 180°, 270° +const TETROMINOES = [ + // I + { + color: 1, + rotations: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + }, + // J + { + color: 3, + rotations: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + }, + // L + { + color: 2, + rotations: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], + }, + // O + { + color: 7, + rotations: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + }, + // S + { + color: 5, + rotations: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + }, + // T + { + color: 6, + rotations: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + }, + // Z + { + color: 4, + rotations: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + }, +]; +// --------------- Game State --------------------------------- +class Tetris { + constructor() { + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.dropTimer = 0; + this.lastTime = 0; + this.animId = 0; + this.lockDelay = 0; + this.lockMax = 500; // ms + this.canvas = document.getElementById("board"); + this.ctx = this.canvas.getContext("2d"); + this.nextCanvas = document.getElementById("next"); + this.nextCtx = this.nextCanvas.getContext("2d"); + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.msgEl = document.getElementById("message"); + this.canvas.width = COLS * CELL; + this.canvas.height = ROWS * CELL; + this.board = this.emptyBoard(); + this.dropInterval = this.calcInterval(1); + this.current = this.newPiece(); + this.next = this.newPiece(); + this.bindKeys(); + this.bindButtons(); + this.showMessage("Press Enter / Start"); + } + // ---- Board helpers ---------------------------------------- + emptyBoard() { + return Array.from({ length: ROWS }, () => new Array(COLS).fill(0)); + } + shape(p) { + return TETROMINOES[p.type].rotations[p.rot]; + } + colorOf(p) { + return COLORS[TETROMINOES[p.type].color]; + } + newPiece() { + const type = Math.floor(Math.random() * TETROMINOES.length); + const shape = TETROMINOES[type].rotations[0]; + const w = shape[0].length; + return { type, rot: 0, x: Math.floor((COLS - w) / 2), y: 0 }; + } + // ---- Collision detection ---------------------------------- + collides(p, dx = 0, dy = 0, rot = p.rot) { + const s = TETROMINOES[p.type].rotations[rot]; + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const nx = p.x + c + dx; + const ny = p.y + r + dy; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && this.board[ny][nx]) + return true; + } + } + return false; + } + // ---- SRS wall-kick offsets -------------------------------- + // Returns offset pairs [dx, dy] to try for a given piece/rotation transition + wallKickOffsets(type, fromRot, toRot) { + var _a, _b; + // I-piece uses different kick table + if (type === 0) { + const table = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + }; + return (_a = table[`${fromRot}>${toRot}`]) !== null && _a !== void 0 ? _a : [[0, 0]]; + } + // All other pieces + const table = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + }; + return (_b = table[`${fromRot}>${toRot}`]) !== null && _b !== void 0 ? _b : [[0, 0]]; + } + // ---- Actions ---------------------------------------------- + rotate(dir) { + const toRot = ((this.current.rot + dir) % 4 + 4) % 4; + const kicks = this.wallKickOffsets(this.current.type, this.current.rot, toRot); + for (const [dx, dy] of kicks) { + if (!this.collides(this.current, dx, dy, toRot)) { + this.current.rot = toRot; + this.current.x += dx; + this.current.y += dy; + this.lockDelay = 0; + return; + } + } + } + moveLeft() { if (!this.collides(this.current, -1)) { + this.current.x--; + this.lockDelay = 0; + } } + moveRight() { if (!this.collides(this.current, 1)) { + this.current.x++; + this.lockDelay = 0; + } } + softDrop() { + if (!this.collides(this.current, 0, 1)) { + this.current.y++; + this.dropTimer = 0; + this.score++; + this.updateUI(); + } + } + hardDrop() { + let dropped = 0; + while (!this.collides(this.current, 0, 1)) { + this.current.y++; + dropped++; + } + this.score += dropped * 2; + this.lock(); + } + ghostY() { + let gy = this.current.y; + while (!this.collides(Object.assign(Object.assign({}, this.current), { y: gy + 1 }))) + gy++; + return gy; + } + // ---- Lock / Line clear ------------------------------------ + lock() { + const s = this.shape(this.current); + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const ny = this.current.y + r; + const nx = this.current.x + c; + if (ny < 0) { + this.triggerGameOver(); + return; + } + this.board[ny][nx] = TETROMINOES[this.current.type].color; + } + } + this.clearLines(); + this.current = this.next; + this.next = this.newPiece(); + this.lockDelay = 0; + if (this.collides(this.current)) { + this.triggerGameOver(); + } + } + clearLines() { + var _a; + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every(v => v !== 0)) { + this.board.splice(r, 1); + this.board.unshift(new Array(COLS).fill(0)); + cleared++; + r++; // recheck same row index + } + } + if (cleared === 0) + return; + const pts = [0, 100, 300, 500, 800]; + this.score += ((_a = pts[cleared]) !== null && _a !== void 0 ? _a : 800) * this.level; + this.lines += cleared; + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel !== this.level) { + this.level = newLevel; + this.dropInterval = this.calcInterval(this.level); + } + this.updateUI(); + } + calcInterval(level) { + // Classic Tetris-style gravity curve (ms per cell) + return Math.max(50, 1000 - (level - 1) * 90); + } + // ---- Game loop -------------------------------------------- + start() { + this.gameOver = false; + this.paused = false; + this.board = this.emptyBoard(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.dropInterval = this.calcInterval(1); + this.current = this.newPiece(); + this.next = this.newPiece(); + this.lastTime = 0; + this.lockDelay = 0; + this.hideMessage(); + this.updateUI(); + if (this.animId) + cancelAnimationFrame(this.animId); + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + loop(timestamp) { + if (this.gameOver || this.paused) + return; + const dt = this.lastTime ? timestamp - this.lastTime : 0; + this.lastTime = timestamp; + // Gravity + this.dropTimer += dt; + if (this.dropTimer >= this.dropInterval) { + this.dropTimer = 0; + if (!this.collides(this.current, 0, 1)) { + this.current.y++; + this.lockDelay = 0; + } + else { + // Piece resting on something + this.lockDelay += dt; + if (this.lockDelay >= this.lockMax) { + this.lock(); + } + } + } + this.draw(); + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + pause() { + if (this.gameOver) + return; + this.paused = !this.paused; + if (this.paused) { + this.showMessage("Paused"); + } + else { + this.hideMessage(); + this.lastTime = 0; + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + } + triggerGameOver() { + this.gameOver = true; + this.showMessage(`Game Over\nScore: ${this.score}\n\nPress Enter to restart`); + } + // ---- Drawing ---------------------------------------------- + draw() { + const ctx = this.ctx; + ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + // Grid background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, ROWS * CELL); + ctx.stroke(); + } + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(COLS * CELL, r * CELL); + ctx.stroke(); + } + // Board cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.board[r][c]) { + this.drawCell(ctx, c, r, COLORS[this.board[r][c]], CELL); + } + } + } + // Ghost piece + const gy = this.ghostY(); + const gs = this.shape(this.current); + const gc = this.colorOf(this.current); + ctx.globalAlpha = 0.25; + for (let r = 0; r < gs.length; r++) { + for (let c = 0; c < gs[r].length; c++) { + if (gs[r][c]) { + this.drawCell(ctx, this.current.x + c, gy + r, gc, CELL); + } + } + } + ctx.globalAlpha = 1; + // Active piece + const s = this.shape(this.current); + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (s[r][c]) { + this.drawCell(ctx, this.current.x + c, this.current.y + r, this.colorOf(this.current), CELL); + } + } + } + // Next piece preview + this.drawNext(); + } + drawCell(ctx, col, row, color, size) { + const x = col * size; + const y = row * size; + const pad = 1; + ctx.fillStyle = color; + ctx.fillRect(x + pad, y + pad, size - pad * 2, size - pad * 2); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x + pad, y + pad, size - pad * 2, 4); + ctx.fillRect(x + pad, y + pad, 4, size - pad * 2); + // Shadow + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(x + size - pad - 4, y + pad, 4, size - pad * 2); + ctx.fillRect(x + pad, y + size - pad - 4, size - pad * 2, 4); + } + drawNext() { + const ctx = this.nextCtx; + const size = PREVIEW_CELL; + ctx.clearRect(0, 0, this.nextCanvas.width, this.nextCanvas.height); + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, this.nextCanvas.width, this.nextCanvas.height); + const s = this.shape(this.next); + const rows = s.length; + const cols = s[0].length; + const offX = Math.floor((this.nextCanvas.width / size - cols) / 2); + const offY = Math.floor((this.nextCanvas.height / size - rows) / 2); + const color = this.colorOf(this.next); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (s[r][c]) { + this.drawCell(ctx, offX + c, offY + r, color, size); + } + } + } + } + // ---- UI --------------------------------------------------- + updateUI() { + this.scoreEl.textContent = String(this.score); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + } + showMessage(msg) { + this.msgEl.style.display = "flex"; + this.msgEl.innerHTML = msg.replace(/\n/g, "<br>"); + } + hideMessage() { + this.msgEl.style.display = "none"; + } + // ---- Input ------------------------------------------------ + bindKeys() { + document.addEventListener("keydown", (e) => { + if (this.gameOver) { + if (e.key === "Enter") { + this.start(); + } + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.pause(); + return; + } + if (this.paused) + return; + switch (e.key) { + case "ArrowLeft": + e.preventDefault(); + this.moveLeft(); + break; + case "ArrowRight": + e.preventDefault(); + this.moveRight(); + break; + case "ArrowDown": + e.preventDefault(); + this.softDrop(); + break; + case "ArrowUp": + e.preventDefault(); + this.rotate(1); + break; + case "z": + case "Z": + this.rotate(-1); + break; + case "x": + case "X": + this.rotate(1); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + case "Enter": + this.start(); + break; + } + }); + } + bindButtons() { + const btn = (id, fn) => { + const el = document.getElementById(id); + if (el) + el.addEventListener("click", fn); + }; + btn("btn-start", () => this.start()); + btn("btn-pause", () => this.pause()); + btn("btn-left", () => { if (!this.paused && !this.gameOver) + this.moveLeft(); }); + btn("btn-right", () => { if (!this.paused && !this.gameOver) + this.moveRight(); }); + btn("btn-down", () => { if (!this.paused && !this.gameOver) + this.softDrop(); }); + btn("btn-rotate", () => { if (!this.paused && !this.gameOver) + this.rotate(1); }); + btn("btn-drop", () => { if (!this.paused && !this.gameOver) + this.hardDrop(); }); + } +} +// ---- Bootstrap -------------------------------------------- +window.addEventListener("DOMContentLoaded", () => { + new Tetris(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,577 @@ +"use strict"; +// ─── Constants ──────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const CELL = 32; // px per grid cell +const DAS = 170; // Delayed Auto Shift (ms) +const ARR = 50; // Auto Repeat Rate (ms) +const FLASH_MS = 280; // Line-clear flash duration (ms) +const LOCK_DELAY = 500; // Lock delay after piece hits floor (ms) +// ─── Piece Definitions ──────────────────────────────────────────────────────── +const COLORS = { + I: '#00c8ff', + O: '#ffd700', + T: '#c040f0', + S: '#10e060', + Z: '#ff3030', + J: '#3878ff', + L: '#ff8800', +}; +// All pieces use square bounding boxes (2×2, 3×3, or 4×4) +const SHAPES = { + I: [[0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0]], + O: [[1, 1], + [1, 1]], + T: [[0, 1, 0], + [1, 1, 1], + [0, 0, 0]], + S: [[0, 1, 1], + [1, 1, 0], + [0, 0, 0]], + Z: [[1, 1, 0], + [0, 1, 1], + [0, 0, 0]], + J: [[1, 0, 0], + [1, 1, 1], + [0, 0, 0]], + L: [[0, 0, 1], + [1, 1, 1], + [0, 0, 0]], +}; +// Standard speed curve (ms per gravity drop) for levels 1-13 +const SPEED_CURVE = [800, 717, 633, 550, 467, 383, 300, 217, 133, 100, 83, 67, 50]; +// ─── Utility Functions ──────────────────────────────────────────────────────── +function createBoard() { + return Array.from({ length: ROWS }, () => new Array(COLS).fill(null)); +} +/** Rotate matrix 90° clockwise */ +function rotateCW(m) { + return m[0].map((_, i) => m.map(row => row[i]).reverse()); +} +/** Rotate matrix 90° counter-clockwise */ +function rotateCCW(m) { + return m[0].map((_, i) => m.map(row => row[row.length - 1 - i])).reverse(); +} +/** Spawn a new piece centered at the top */ +function makePiece(type) { + const shape = SHAPES[type].map(r => [...r]); + return { + type, + shape, + color: COLORS[type], + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + }; +} +/** Returns true if the piece (optionally with offsets / alternate shape) fits on the board */ +function fits(board, piece, dx = 0, dy = 0, shape = piece.shape) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = piece.x + c + dx; + const ny = piece.y + r + dy; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return false; + if (ny >= 0 && board[ny][nx]) + return false; + } + } + return true; +} +/** Place the piece onto the board, returning a new board */ +function stamp(board, piece) { + const b = board.map(r => [...r]); + piece.shape.forEach((row, r) => { + row.forEach((cell, c) => { + if (cell) { + const ny = piece.y + r; + const nx = piece.x + c; + if (ny >= 0 && ny < ROWS && nx >= 0 && nx < COLS) + b[ny][nx] = piece.color; + } + }); + }); + return b; +} +/** Return indices of completely filled rows */ +function fullRows(board) { + return board.reduce((acc, row, i) => { + if (row.every(c => c !== null)) + acc.push(i); + return acc; + }, []); +} +/** Remove the specified rows and prepend empty rows at the top */ +function removeRows(board, rows) { + const kept = board.filter((_, i) => !rows.includes(i)); + const empties = Array.from({ length: rows.length }, () => new Array(COLS).fill(null)); + return [...empties, ...kept]; +} +const SCORE_TABLE = [0, 100, 300, 500, 800]; +function lineScore(n, level) { + var _a; + return ((_a = SCORE_TABLE[n]) !== null && _a !== void 0 ? _a : 0) * level; +} +function dropInterval(level) { + return SPEED_CURVE[Math.min(level - 1, SPEED_CURVE.length - 1)]; +} +// ─── 7-Bag Randomiser ───────────────────────────────────────────────────────── +class Bag { + constructor() { + this.items = []; + } + refill() { + this.items = Object.keys(SHAPES); + for (let i = this.items.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.items[i], this.items[j]] = [this.items[j], this.items[i]]; + } + } + draw() { + if (this.items.length === 0) + this.refill(); + return this.items.pop(); + } +} +// ─── Main Game Class ────────────────────────────────────────────────────────── +class TetrisGame { + // ── Constructor ───────────────────────────────────────────────────────────── + constructor() { + var _a; + this.held = null; + // Timing + this.lastTime = 0; + // Line-clear flash + this.flashTimer = 0; + this.flashRows = []; + this.pendingClr = 0; + this.pendingScr = 0; + // Input + this.keysDown = new Set(); + this.dasTimer = 0; + this.arrTimer = 0; + const get = (id) => document.getElementById(id); + this.boardCanvas = get('board'); + this.boardCtx = this.boardCanvas.getContext('2d'); + this.nextCanvas = get('next'); + this.nextCtx = this.nextCanvas.getContext('2d'); + this.holdCanvas = get('hold'); + this.holdCtx = this.holdCanvas.getContext('2d'); + this.boardCanvas.width = COLS * CELL; + this.boardCanvas.height = ROWS * CELL; + this.nextCanvas.width = 4 * CELL; + this.nextCanvas.height = 4 * CELL; + this.holdCanvas.width = 4 * CELL; + this.holdCanvas.height = 4 * CELL; + this.highScore = parseInt((_a = localStorage.getItem('tetris-hs')) !== null && _a !== void 0 ? _a : '0', 10); + this.setupInput(); + this.init(); + requestAnimationFrame(t => this.loop(t)); + } + // ── Initialisation ────────────────────────────────────────────────────────── + init() { + this.bag = new Bag(); + this.board = createBoard(); + this.current = makePiece(this.bag.draw()); + this.next = makePiece(this.bag.draw()); + this.held = null; + this.canHold = true; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.dropCounter = 0; + this.lockTimer = 0; + this.onFloor = false; + this.flashTimer = 0; + this.flashRows = []; + this.pendingClr = 0; + this.pendingScr = 0; + this.updateHUD(); + } + // ── Input ─────────────────────────────────────────────────────────────────── + setupInput() { + // Prevent page scroll for game keys + window.addEventListener('keydown', e => { + if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Space'].includes(e.code)) + e.preventDefault(); + if (!e.repeat) { + this.keysDown.add(e.code); + this.onFirstPress(e.code); + } + }, { passive: false }); + window.addEventListener('keyup', e => { + this.keysDown.delete(e.code); + if (e.code === 'ArrowLeft' || e.code === 'ArrowRight') { + this.dasTimer = 0; + this.arrTimer = 0; + } + }); + // Clear all held keys when window loses focus (prevents stuck movement) + window.addEventListener('blur', () => { + this.keysDown.clear(); + this.dasTimer = 0; + this.arrTimer = 0; + }); + } + onFirstPress(code) { + if (code === 'KeyP') { + if (!this.gameOver) + this.paused = !this.paused; + return; + } + if (this.gameOver) { + if (code === 'Enter' || code === 'KeyR') + this.init(); + return; + } + if (this.paused || this.flashTimer > 0) + return; + switch (code) { + case 'ArrowLeft': + this.move(-1); + this.dasTimer = 0; + this.arrTimer = 0; + break; + case 'ArrowRight': + this.move(1); + this.dasTimer = 0; + this.arrTimer = 0; + break; + case 'ArrowDown': + this.softDrop(); + break; + case 'ArrowUp': + this.rotate(1); + break; + case 'KeyZ': + this.rotate(-1); + break; + case 'KeyX': + this.rotate(1); + break; + case 'Space': + this.hardDrop(); + break; + case 'ShiftLeft': + case 'ShiftRight': + case 'KeyC': + this.holdPiece(); + break; + } + } + // ── Actions ───────────────────────────────────────────────────────────────── + move(dx) { + if (fits(this.board, this.current, dx)) { + this.current.x += dx; + if (this.onFloor) + this.lockTimer = 0; // reset lock delay on successful move + return true; + } + return false; + } + softDrop() { + if (fits(this.board, this.current, 0, 1)) { + this.current.y++; + this.score++; + this.dropCounter = 0; + this.lockTimer = 0; + this.updateHUD(); + } + } + hardDrop() { + let n = 0; + while (fits(this.board, this.current, 0, 1)) { + this.current.y++; + n++; + } + this.score += n * 2; + this.lock(); + } + rotate(dir) { + const rotated = dir === 1 ? rotateCW(this.current.shape) : rotateCCW(this.current.shape); + // Wall-kick offsets: try center, then nudge left/right, then further + const kicks = [0, -1, 1, -2, 2]; + for (const kick of kicks) { + if (fits(this.board, this.current, kick, 0, rotated)) { + this.current.shape = rotated; + this.current.x += kick; + if (this.onFloor) + this.lockTimer = 0; // reset lock delay on successful rotate + return; + } + } + } + holdPiece() { + if (!this.canHold) + return; + const savedType = this.current.type; + if (this.held) { + this.current = makePiece(this.held.type); + } + else { + this.current = this.next; + this.next = makePiece(this.bag.draw()); + } + this.held = makePiece(savedType); + this.canHold = false; + this.onFloor = false; + this.lockTimer = 0; + this.dropCounter = 0; + } + lock() { + this.board = stamp(this.board, this.current); + this.canHold = true; + this.onFloor = false; + const fr = fullRows(this.board); + if (fr.length > 0) { + this.flashRows = fr; + this.flashTimer = FLASH_MS; + this.pendingClr = fr.length; + this.pendingScr = lineScore(fr.length, this.level); + } + else { + this.spawnNext(); + } + } + spawnNext() { + this.current = this.next; + this.next = makePiece(this.bag.draw()); + this.dropCounter = 0; + this.lockTimer = 0; + this.onFloor = false; + if (!fits(this.board, this.current)) { + this.gameOver = true; + if (this.score > this.highScore) { + this.highScore = this.score; + localStorage.setItem('tetris-hs', String(this.highScore)); + } + } + this.updateHUD(); + } + // ── HUD ───────────────────────────────────────────────────────────────────── + updateHUD() { + const el = (id) => document.getElementById(id); + el('score').textContent = this.score.toLocaleString(); + el('lines').textContent = String(this.lines); + el('level').textContent = String(this.level); + el('high-score').textContent = Math.max(this.highScore, this.score).toLocaleString(); + } + // ── Rendering ──────────────────────────────────────────────────────────────── + ghostOffset() { + let dy = 0; + while (fits(this.board, this.current, 0, dy + 1)) + dy++; + return dy; + } + drawBlock(ctx, x, y, color, alpha = 1) { + const px = x * CELL; + const py = y * CELL; + const m = 1; // margin between cells + const s = CELL - m * 2; + ctx.globalAlpha = alpha; + // Base fill + ctx.fillStyle = color; + ctx.fillRect(px + m, py + m, s, s); + // Gradient sheen + const g = ctx.createLinearGradient(px, py, px, py + CELL); + g.addColorStop(0, 'rgba(255,255,255,0.38)'); + g.addColorStop(0.40, 'rgba(255,255,255,0.04)'); + g.addColorStop(1, 'rgba(0,0,0,0.22)'); + ctx.fillStyle = g; + ctx.fillRect(px + m, py + m, s, s); + // Top-left highlight bevel + ctx.fillStyle = 'rgba(255,255,255,0.55)'; + ctx.fillRect(px + m, py + m, s, 3); // top edge + ctx.fillRect(px + m, py + m, 3, s); // left edge + // Bottom-right shadow bevel + ctx.fillStyle = 'rgba(0,0,0,0.35)'; + ctx.fillRect(px + m, py + CELL - m - 3, s, 3); // bottom edge + ctx.fillRect(px + CELL - m - 3, py + m, 3, s); // right edge + ctx.globalAlpha = 1; + } + renderBoard() { + const ctx = this.boardCtx; + const W = this.boardCanvas.width; + const H = this.boardCanvas.height; + // Background + ctx.fillStyle = '#0d1117'; + ctx.fillRect(0, 0, W, H); + // Subtle grid lines + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 1; + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, H); + ctx.stroke(); + } + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(W, r * CELL); + ctx.stroke(); + } + // Placed board cells (with flash effect on clearing rows) + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const cell = this.board[r][c]; + if (!cell) + continue; + if (this.flashRows.includes(r)) { + // Alternate white / colour every ~35ms + const t = this.flashTimer / FLASH_MS; + const flash = Math.floor(t * 8) % 2 === 0; + this.drawBlock(ctx, c, r, flash ? '#ffffff' : cell); + } + else { + this.drawBlock(ctx, c, r, cell); + } + } + } + // Ghost & active piece — hidden during flash animation + if (this.flashTimer <= 0 && !this.gameOver) { + const gDy = this.ghostOffset(); + // Ghost + if (gDy > 0) { + this.current.shape.forEach((row, r) => { + row.forEach((cell, c) => { + const gy = this.current.y + r + gDy; + if (cell && gy >= 0) { + this.drawBlock(ctx, this.current.x + c, gy, this.current.color, 0.18); + } + }); + }); + } + // Active piece + this.current.shape.forEach((row, r) => { + row.forEach((cell, c) => { + const py = this.current.y + r; + if (cell && py >= 0) { + this.drawBlock(ctx, this.current.x + c, py, this.current.color); + } + }); + }); + } + // ── Overlays ────────────────────────────────────────────────────────────── + if (this.paused) { + ctx.fillStyle = 'rgba(0,0,0,0.72)'; + ctx.fillRect(0, 0, W, H); + this.cText(ctx, 'PAUSED', W / 2, H / 2 - 22, '#ffffff', 'bold 34px monospace'); + this.cText(ctx, 'P — resume', W / 2, H / 2 + 18, '#778899', '15px monospace'); + } + if (this.gameOver) { + ctx.fillStyle = 'rgba(0,0,0,0.80)'; + ctx.fillRect(0, 0, W, H); + this.cText(ctx, 'GAME OVER', W / 2, H / 2 - 46, '#ff4040', 'bold 36px monospace'); + this.cText(ctx, `Score: ${this.score.toLocaleString()}`, W / 2, H / 2 - 2, '#e0e0e0', '20px monospace'); + this.cText(ctx, 'Enter — play again', W / 2, H / 2 + 38, '#778899', '14px monospace'); + } + } + cText(ctx, text, x, y, color, font) { + ctx.save(); + ctx.fillStyle = color; + ctx.font = font; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText(text, x, y); + ctx.restore(); + } + renderPreview(ctx, canvas, piece, dimmed = false) { + ctx.fillStyle = '#0d1117'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + if (!piece) + return; + const s = piece.shape; + const ox = Math.floor((4 - s[0].length) / 2); + const oy = Math.floor((4 - s.length) / 2); + s.forEach((row, r) => { + row.forEach((cell, c) => { + if (cell) + this.drawBlock(ctx, ox + c, oy + r, piece.color, dimmed ? 0.38 : 1); + }); + }); + } + // ── Game Loop ──────────────────────────────────────────────────────────────── + loop(time) { + const dt = Math.min(time - (this.lastTime || time), 100); // cap at 100ms + this.lastTime = time; + if (!this.paused && !this.gameOver) { + // ── Flash timer (line-clear animation) ────────────────────────────────── + if (this.flashTimer > 0) { + this.flashTimer -= dt; + if (this.flashTimer <= 0) { + this.flashTimer = 0; + this.board = removeRows(this.board, this.flashRows); + this.flashRows = []; + this.lines += this.pendingClr; + this.score += this.pendingScr; + this.level = Math.floor(this.lines / 10) + 1; + this.pendingClr = 0; + this.pendingScr = 0; + this.spawnNext(); + } + } + else { + // ── DAS / ARR horizontal movement ───────────────────────────────────── + const leftDown = this.keysDown.has('ArrowLeft'); + const rightDown = this.keysDown.has('ArrowRight'); + if (leftDown || rightDown) { + this.dasTimer += dt; + if (this.dasTimer > DAS) { + this.arrTimer += dt; + if (this.arrTimer >= ARR) { + const steps = Math.floor(this.arrTimer / ARR); + this.arrTimer -= steps * ARR; + for (let i = 0; i < steps; i++) { + if (leftDown && !rightDown) + this.move(-1); + if (rightDown && !leftDown) + this.move(1); + } + } + } + } + // ── Gravity ─────────────────────────────────────────────────────────── + const softDropping = this.keysDown.has('ArrowDown'); + const interval = softDropping ? 50 : dropInterval(this.level); + this.dropCounter += dt; + if (this.dropCounter >= interval) { + this.dropCounter = 0; + if (fits(this.board, this.current, 0, 1)) { + this.current.y++; + this.onFloor = false; + this.lockTimer = 0; + if (softDropping) { + this.score++; + this.updateHUD(); + } + } + else { + // Piece can't fall — mark as on floor; lock delay handled below + this.onFloor = true; + } + } + // Accumulate lock delay every frame while piece rests on something + if (this.onFloor && !fits(this.board, this.current, 0, 1)) { + this.lockTimer += dt; + if (this.lockTimer >= LOCK_DELAY) { + this.lock(); + } + } + } + } + // ── Render ──────────────────────────────────────────────────────────────── + this.renderBoard(); + this.renderPreview(this.nextCtx, this.nextCanvas, this.next); + this.renderPreview(this.holdCtx, this.holdCanvas, this.held, !this.canHold); + requestAnimationFrame(t => this.loop(t)); + } +} +// ─── Bootstrap ─────────────────────────────────────────────────────────────── +window.addEventListener('load', () => new TetrisGame()); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,439 @@ +"use strict"; +// ============================================================ +// Tetris — Full browser game in TypeScript +// ============================================================ +// ----- Constants ----- +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 32; +const PREVIEW_BLOCK = 20; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const SHAPES = { + I: [ + [[0, 0], [1, 0], [2, 0], [3, 0]], + [[0, 0], [0, 1], [0, 2], [0, 3]], + [[0, 0], [1, 0], [2, 0], [3, 0]], + [[0, 0], [0, 1], [0, 2], [0, 3]], + ], + O: [ + [[0, 0], [1, 0], [0, 1], [1, 1]], + [[0, 0], [1, 0], [0, 1], [1, 1]], + [[0, 0], [1, 0], [0, 1], [1, 1]], + [[0, 0], [1, 0], [0, 1], [1, 1]], + ], + T: [ + [[0, 0], [1, 0], [2, 0], [1, 1]], + [[1, 0], [1, 1], [1, 2], [0, 1]], + [[0, 1], [1, 1], [2, 1], [1, 0]], + [[0, 0], [0, 1], [0, 2], [1, 1]], + ], + S: [ + [[1, 0], [2, 0], [0, 1], [1, 1]], + [[0, 0], [0, 1], [1, 1], [1, 2]], + [[1, 0], [2, 0], [0, 1], [1, 1]], + [[0, 0], [0, 1], [1, 1], [1, 2]], + ], + Z: [ + [[0, 0], [1, 0], [1, 1], [2, 1]], + [[1, 0], [0, 1], [1, 1], [0, 2]], + [[0, 0], [1, 0], [1, 1], [2, 1]], + [[1, 0], [0, 1], [1, 1], [0, 2]], + ], + J: [ + [[0, 0], [0, 1], [1, 1], [2, 1]], + [[0, 0], [1, 0], [0, 1], [0, 2]], + [[0, 0], [1, 0], [2, 0], [2, 1]], + [[1, 0], [1, 1], [0, 2], [1, 2]], + ], + L: [ + [[2, 0], [0, 1], [1, 1], [2, 1]], + [[0, 0], [0, 1], [0, 2], [1, 2]], + [[0, 0], [1, 0], [2, 0], [0, 1]], + [[0, 0], [1, 0], [1, 1], [1, 2]], + ], +}; +const PIECE_NAMES = Object.keys(SHAPES); +const LEVEL_SPEEDS = [ + 800, 720, 630, 550, 470, 380, 300, 220, 140, 100, + 80, 70, 60, 50, 40, 30, 20, 15, 10, 8, 5, +]; +const LINE_SCORES = [0, 100, 300, 500, 800]; +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +// ----- Piece helpers ----- +function getBlocks(piece) { + return SHAPES[piece.type][piece.rotation % 4]; +} +function spawnPiece(type) { + return { type, rotation: 0, x: 3, y: 0 }; +} +function randomType() { + return PIECE_NAMES[Math.floor(Math.random() * PIECE_NAMES.length)]; +} +function collides(board, piece) { + for (const [bx, by] of getBlocks(piece)) { + const nx = piece.x + bx; + const ny = piece.y + by; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && board[ny][nx] !== null) + return true; + } + return false; +} +function lockPiece(board, piece) { + for (const [bx, by] of getBlocks(piece)) { + const nx = piece.x + bx; + const ny = piece.y + by; + if (ny >= 0 && ny < ROWS && nx >= 0 && nx < COLS) { + board[ny][nx] = piece.type; + } + } +} +function clearLines(board) { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every((c) => c !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check same row index + } + } + return cleared; +} +// ----- Ghost piece (drop preview) ----- +function ghostY(board, piece) { + let gy = piece.y; + while (true) { + const test = { ...piece, y: gy + 1 }; + if (collides(board, test)) + break; + gy++; + } + return gy; +} +// ----- Rendering ----- +function drawBlock(ctx, x, y, color, size, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size, y * size, size, size); + // highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x * size, y * size, size, size * 0.15); + ctx.fillRect(x * size, y * size, size * 0.15, size); + // shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x * size, y * size + size * 0.85, size, size * 0.15); + ctx.fillRect(x * size + size * 0.85, y * size, size * 0.15, size); + // border + ctx.strokeStyle = "rgba(0,0,0,0.4)"; + ctx.lineWidth = 1; + ctx.strokeRect(x * size + 0.5, y * size + 0.5, size - 1, size - 1); + ctx.globalAlpha = 1; +} +function drawBoard(ctx, board) { + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + ctx.lineWidth = 1; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(COLS * BLOCK_SIZE, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.stroke(); + } + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c]) { + drawBlock(ctx, c, r, COLORS[board[r][c]], BLOCK_SIZE); + } + } + } +} +function drawPiece(ctx, piece, alpha = 1, overrideY) { + const py = overrideY !== undefined ? overrideY : piece.y; + for (const [bx, by] of getBlocks(piece)) { + drawBlock(ctx, piece.x + bx, py + by, COLORS[piece.type], BLOCK_SIZE, alpha); + } +} +function drawPreview(ctx, type, canvasW, canvasH) { + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, canvasW, canvasH); + const blocks = SHAPES[type][0]; + // centre the piece + let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity; + for (const [bx, by] of blocks) { + minX = Math.min(minX, bx); + maxX = Math.max(maxX, bx); + minY = Math.min(minY, by); + maxY = Math.max(maxY, by); + } + const pw = maxX - minX + 1; + const ph = maxY - minY + 1; + const ox = Math.floor((canvasW / PREVIEW_BLOCK - pw) / 2); + const oy = Math.floor((canvasH / PREVIEW_BLOCK - ph) / 2); + for (const [bx, by] of blocks) { + drawBlock(ctx, ox + bx - minX, oy + by - minY, COLORS[type], PREVIEW_BLOCK); + } +} +// ----- Game State ----- +class TetrisGame { + constructor() { + const gameCanvas = document.getElementById("game-canvas"); + this.previewCanvas = document.getElementById("preview-canvas"); + this.ctx = gameCanvas.getContext("2d"); + this.previewCtx = this.previewCanvas.getContext("2d"); + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.overlayEl = document.getElementById("overlay"); + this.overlayTextEl = document.getElementById("overlay-text"); + gameCanvas.width = COLS * BLOCK_SIZE; + gameCanvas.height = ROWS * BLOCK_SIZE; + this.board = createBoard(); + this.next = randomType(); + this.current = spawnPiece(randomType()); + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + this.dropInterval = LEVEL_SPEEDS[0]; + this.lastDrop = performance.now(); + this.lockDelay = 500; + this.lockTimer = 0; + this.animatingLines = []; + this.animStart = 0; + this.bindInput(); + this.updateHUD(); + requestAnimationFrame((t) => this.loop(t)); + } + restart() { + this.board = createBoard(); + this.next = randomType(); + this.current = spawnPiece(randomType()); + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + this.dropInterval = LEVEL_SPEEDS[0]; + this.lastDrop = performance.now(); + this.lockTimer = 0; + this.animatingLines = []; + this.overlayEl.classList.add("hidden"); + this.updateHUD(); + } + bindInput() { + document.addEventListener("keydown", (e) => { + if (this.gameOver) { + if (e.key === "Enter" || e.key === " ") { + this.restart(); + } + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.togglePause(); + return; + } + if (this.paused) + return; + if (this.animatingLines.length > 0) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + this.move(-1, 0); + e.preventDefault(); + break; + case "ArrowRight": + case "d": + this.move(1, 0); + e.preventDefault(); + break; + case "ArrowDown": + case "s": + this.softDrop(); + e.preventDefault(); + break; + case "ArrowUp": + case "w": + this.rotate(); + e.preventDefault(); + break; + case " ": + this.hardDrop(); + e.preventDefault(); + break; + } + }); + } + togglePause() { + this.paused = !this.paused; + if (this.paused) { + this.overlayTextEl.textContent = "PAUSA"; + this.overlayEl.classList.remove("hidden"); + } + else { + this.overlayEl.classList.add("hidden"); + this.lastDrop = performance.now(); + } + } + move(dx, dy) { + const test = { ...this.current, x: this.current.x + dx, y: this.current.y + dy }; + if (!collides(this.board, test)) { + this.current = test; + return true; + } + return false; + } + rotate() { + const newRotation = (this.current.rotation + 1) % 4; + const test = { ...this.current, rotation: newRotation }; + // Try basic rotation + if (!collides(this.board, test)) { + this.current = test; + return; + } + // Wall kicks: try offsets + const kicks = [ + [1, 0], [-1, 0], [0, -1], [2, 0], [-2, 0], + [1, -1], [-1, -1], + ]; + for (const [kx, ky] of kicks) { + const kicked = { ...test, x: test.x + kx, y: test.y + ky }; + if (!collides(this.board, kicked)) { + this.current = kicked; + return; + } + } + } + softDrop() { + if (this.move(0, 1)) { + this.score += 1; + this.lastDrop = performance.now(); + } + } + hardDrop() { + const gy = ghostY(this.board, this.current); + this.score += (gy - this.current.y) * 2; + this.current.y = gy; + this.placePiece(); + } + placePiece() { + lockPiece(this.board, this.current); + // Check for filled lines + const filledRows = []; + for (let r = 0; r < ROWS; r++) { + if (this.board[r].every((c) => c !== null)) { + filledRows.push(r); + } + } + if (filledRows.length > 0) { + this.animatingLines = filledRows; + this.animStart = performance.now(); + } + else { + this.spawnNext(); + } + } + finishLineClear() { + const cleared = clearLines(this.board); + this.lines += cleared; + this.score += LINE_SCORES[cleared] * (this.level + 1); + this.level = Math.floor(this.lines / 10); + this.dropInterval = LEVEL_SPEEDS[Math.min(this.level, LEVEL_SPEEDS.length - 1)]; + this.animatingLines = []; + this.updateHUD(); + this.spawnNext(); + } + spawnNext() { + this.current = spawnPiece(this.next); + this.next = randomType(); + this.lastDrop = performance.now(); + this.lockTimer = 0; + if (collides(this.board, this.current)) { + this.gameOver = true; + this.overlayTextEl.innerHTML = `GAME OVER<br><span style="font-size:0.5em">Pulsa Enter para reiniciar</span>`; + this.overlayEl.classList.remove("hidden"); + } + } + updateHUD() { + this.scoreEl.textContent = this.score.toString(); + this.linesEl.textContent = this.lines.toString(); + this.levelEl.textContent = this.level.toString(); + drawPreview(this.previewCtx, this.next, this.previewCanvas.width, this.previewCanvas.height); + } + // ----- Game Loop ----- + loop(now) { + if (!this.gameOver && !this.paused) { + // Line-clear animation (flash ~300ms) + if (this.animatingLines.length > 0) { + if (now - this.animStart > 300) { + this.finishLineClear(); + } + } + else { + // Gravity + if (now - this.lastDrop > this.dropInterval) { + if (!this.move(0, 1)) { + // On ground – lock delay + this.lockTimer += now - this.lastDrop; + if (this.lockTimer >= this.lockDelay) { + this.placePiece(); + } + } + else { + this.lockTimer = 0; + } + this.lastDrop = now; + } + } + } + this.render(now); + requestAnimationFrame((t) => this.loop(t)); + } + render(now) { + drawBoard(this.ctx, this.board); + // Animate clearing lines (flash effect) + if (this.animatingLines.length > 0) { + const elapsed = now - this.animStart; + const flash = Math.floor(elapsed / 60) % 2 === 0; + for (const row of this.animatingLines) { + for (let c = 0; c < COLS; c++) { + this.ctx.fillStyle = flash ? "#fff" : "#333"; + this.ctx.fillRect(c * BLOCK_SIZE + 1, row * BLOCK_SIZE + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + } + } + } + if (!this.gameOver && this.animatingLines.length === 0) { + // Ghost piece + const gy = ghostY(this.board, this.current); + drawPiece(this.ctx, this.current, 0.2, gy); + // Current piece + drawPiece(this.ctx, this.current); + } + // Preview is updated via HUD + } +} +// ----- Bootstrap ----- +window.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,583 @@ +"use strict"; +// ============================================================ +// Tetris – Full browser game (single-file TypeScript) +// ============================================================ +// ----- Constants ------------------------------------------- +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 30; +const PREVIEW_BLOCK = 20; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const GHOST_ALPHA = 0.25; +const SHAPES = { + I: [ + [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + [ + [0, 0, 1, 0], + [0, 0, 1, 0], + [0, 0, 1, 0], + [0, 0, 1, 0], + ], + [ + [0, 0, 0, 0], + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + ], + [ + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0], + ], + ], + O: [ + [ + [1, 1], + [1, 1], + ], + [ + [1, 1], + [1, 1], + ], + [ + [1, 1], + [1, 1], + ], + [ + [1, 1], + [1, 1], + ], + ], + T: [ + [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + [ + [0, 1, 0], + [0, 1, 1], + [0, 1, 0], + ], + [ + [0, 0, 0], + [1, 1, 1], + [0, 1, 0], + ], + [ + [0, 1, 0], + [1, 1, 0], + [0, 1, 0], + ], + ], + S: [ + [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + [ + [0, 1, 0], + [0, 1, 1], + [0, 0, 1], + ], + [ + [0, 0, 0], + [0, 1, 1], + [1, 1, 0], + ], + [ + [1, 0, 0], + [1, 1, 0], + [0, 1, 0], + ], + ], + Z: [ + [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + [ + [0, 0, 1], + [0, 1, 1], + [0, 1, 0], + ], + [ + [0, 0, 0], + [1, 1, 0], + [0, 1, 1], + ], + [ + [0, 1, 0], + [1, 1, 0], + [1, 0, 0], + ], + ], + J: [ + [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + [ + [0, 1, 1], + [0, 1, 0], + [0, 1, 0], + ], + [ + [0, 0, 0], + [1, 1, 1], + [0, 0, 1], + ], + [ + [0, 1, 0], + [0, 1, 0], + [1, 1, 0], + ], + ], + L: [ + [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], + [ + [0, 1, 0], + [0, 1, 0], + [0, 1, 1], + ], + [ + [0, 0, 0], + [1, 1, 1], + [1, 0, 0], + ], + [ + [1, 1, 0], + [0, 1, 0], + [0, 1, 0], + ], + ], +}; +// SRS wall-kick data (J, L, S, T, Z) +const WALL_KICKS = { + "0>1": [[-1, 0], [-1, -1], [0, 2], [-1, 2]], + "1>0": [[1, 0], [1, 1], [0, -2], [1, -2]], + "1>2": [[1, 0], [1, 1], [0, -2], [1, -2]], + "2>1": [[-1, 0], [-1, -1], [0, 2], [-1, 2]], + "2>3": [[1, 0], [1, -1], [0, 2], [1, 2]], + "3>2": [[-1, 0], [-1, 1], [0, -2], [-1, -2]], + "3>0": [[-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[1, 0], [1, 1], [0, -2], [1, -2]], +}; +// SRS wall-kick data for I piece +const WALL_KICKS_I = { + "0>1": [[-2, 0], [1, 0], [-2, 1], [1, -2]], + "1>0": [[2, 0], [-1, 0], [2, -1], [-1, 2]], + "1>2": [[-1, 0], [2, 0], [-1, -2], [2, 1]], + "2>1": [[1, 0], [-2, 0], [1, 2], [-2, -1]], + "2>3": [[2, 0], [-1, 0], [2, -1], [-1, 2]], + "3>2": [[-2, 0], [1, 0], [-2, 1], [1, -2]], + "3>0": [[1, 0], [-2, 0], [1, 2], [-2, -1]], + "0>3": [[-1, 0], [2, 0], [-1, -2], [2, 1]], +}; +// Points per lines cleared (classic NES scoring × (level+1)) +const LINE_POINTS = [0, 100, 300, 500, 800]; +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +// ----- Helpers --------------------------------------------- +function getShape(piece) { + return SHAPES[piece.type][piece.rotation]; +} +function collides(board, piece, dx = 0, dy = 0) { + const shape = getShape(piece); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = piece.x + c + dx; + const ny = piece.y + r + dy; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny < 0) + continue; // above board is ok + if (board[ny][nx]) + return true; + } + } + return false; +} +function lock(board, piece) { + const shape = getShape(piece); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = piece.x + c; + const ny = piece.y + r; + if (ny >= 0 && ny < ROWS && nx >= 0 && nx < COLS) { + board[ny][nx] = piece.type; + } + } + } +} +function clearLines(board) { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every((cell) => cell !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check same index + } + } + return cleared; +} +// 7-bag randomiser +function createBag() { + const types = Object.keys(SHAPES); + for (let i = types.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [types[i], types[j]] = [types[j], types[i]]; + } + return types; +} +function spawnPiece(type) { + return { type, rotation: 0, x: Math.floor((COLS - SHAPES[type][0][0].length) / 2), y: -1 }; +} +function ghostY(board, piece) { + let dy = 0; + while (!collides(board, piece, 0, dy + 1)) + dy++; + return piece.y + dy; +} +function nextFromBag(state) { + if (state.bag.length === 0) { + state.bag = createBag(); + } + return state.bag.pop(); +} +function initState() { + const bag = createBag(); + const first = bag.pop(); + const second = bag.pop(); + return { + board: createBoard(), + current: spawnPiece(first), + next: spawnPiece(second), + bag, + score: 0, + lines: 0, + level: 0, + gameOver: false, + paused: false, + dropInterval: 1000, + lastDrop: performance.now(), + softDrop: false, + }; +} +function calcDropInterval(level) { + // NES-style speed curve (ms) + const speeds = [1000, 900, 800, 717, 633, 550, 467, 383, 300, 217, 167, 133, 100, 83, 67, 50, 33, 17]; + return level < speeds.length ? speeds[level] : 17; +} +// ----- Drawing --------------------------------------------- +function drawBlock(ctx, x, y, color, size, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size, y * size, size, size); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x * size, y * size, size, 3); + ctx.fillRect(x * size, y * size, 3, size); + // Shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x * size + size - 3, y * size, 3, size); + ctx.fillRect(x * size, y * size + size - 3, size, 3); + // Border + ctx.strokeStyle = "rgba(0,0,0,0.4)"; + ctx.lineWidth = 1; + ctx.strokeRect(x * size + 0.5, y * size + 0.5, size - 1, size - 1); + ctx.globalAlpha = 1; +} +function drawBoard(ctx, board) { + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); + // Grid + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK_SIZE + 0.5, r * BLOCK_SIZE + 0.5, BLOCK_SIZE - 1, BLOCK_SIZE - 1); + } + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c]) { + drawBlock(ctx, c, r, COLORS[board[r][c]], BLOCK_SIZE); + } + } + } +} +function drawPiece(ctx, piece, alpha = 1) { + const shape = getShape(piece); + const color = COLORS[piece.type]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const py = piece.y + r; + if (py < 0) + continue; + drawBlock(ctx, piece.x + c, py, color, BLOCK_SIZE, alpha); + } + } +} +function drawGhost(ctx, board, piece) { + const gy = ghostY(board, piece); + const shape = getShape(piece); + const color = COLORS[piece.type]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const py = gy + r; + if (py < 0) + continue; + drawBlock(ctx, piece.x + c, py, color, BLOCK_SIZE, GHOST_ALPHA); + } + } +} +function drawPreview(ctx, piece) { + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, 6 * PREVIEW_BLOCK, 6 * PREVIEW_BLOCK); + const shape = SHAPES[piece.type][0]; + const color = COLORS[piece.type]; + const offsetX = (6 - shape[0].length) / 2; + const offsetY = (6 - shape.length) / 2; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + drawBlock(ctx, offsetX + c, offsetY + r, color, PREVIEW_BLOCK); + } + } +} +// ----- Rotation with SRS wall kicks ------------------------- +function tryRotate(board, piece, dir) { + const from = piece.rotation; + const to = (piece.rotation + dir + 4) % 4; + const original = piece.rotation; + piece.rotation = to; + // Basic rotation + if (!collides(board, piece)) + return true; + // Wall kicks + const key = `${from}>${to}`; + const kicks = piece.type === "I" ? WALL_KICKS_I[key] : WALL_KICKS[key]; + if (kicks) { + for (const [kx, ky] of kicks) { + if (!collides(board, piece, kx, -ky)) { + piece.x += kx; + piece.y -= ky; + return true; + } + } + } + // Revert + piece.rotation = original; + return false; +} +// ----- Main game loop -------------------------------------- +function main() { + // --- Canvas setup --- + const boardCanvas = document.getElementById("board"); + const previewCanvas = document.getElementById("preview"); + const boardCtx = boardCanvas.getContext("2d"); + const previewCtx = previewCanvas.getContext("2d"); + boardCanvas.width = COLS * BLOCK_SIZE; + boardCanvas.height = ROWS * BLOCK_SIZE; + previewCanvas.width = 6 * PREVIEW_BLOCK; + previewCanvas.height = 6 * PREVIEW_BLOCK; + const scoreEl = document.getElementById("score"); + const linesEl = document.getElementById("lines"); + const levelEl = document.getElementById("level"); + const overlayEl = document.getElementById("overlay"); + const overlayText = document.getElementById("overlay-text"); + const startBtn = document.getElementById("start-btn"); + let state = initState(); + let animationId = null; + let running = false; + function updateHUD() { + scoreEl.textContent = state.score.toString(); + linesEl.textContent = state.lines.toString(); + levelEl.textContent = state.level.toString(); + } + function showOverlay(msg, btnText) { + overlayText.textContent = msg; + startBtn.textContent = btnText; + overlayEl.style.display = "flex"; + } + function hideOverlay() { + overlayEl.style.display = "none"; + } + function draw() { + drawBoard(boardCtx, state.board); + if (!state.gameOver) { + drawGhost(boardCtx, state.board, state.current); + drawPiece(boardCtx, state.current); + } + drawPreview(previewCtx, state.next); + updateHUD(); + } + function advancePiece() { + lock(state.board, state.current); + const cleared = clearLines(state.board); + if (cleared > 0) { + state.lines += cleared; + state.score += LINE_POINTS[cleared] * (state.level + 1); + const newLevel = Math.floor(state.lines / 10); + if (newLevel !== state.level) { + state.level = newLevel; + state.dropInterval = calcDropInterval(state.level); + } + } + // Next piece + state.current = { ...state.next, x: spawnPiece(state.next.type).x, y: spawnPiece(state.next.type).y }; + const nextType = nextFromBag(state); + state.next = spawnPiece(nextType); + if (collides(state.board, state.current)) { + state.gameOver = true; + showOverlay("GAME OVER", "Reiniciar"); + } + } + function tick(now) { + if (!running) + return; + if (state.paused || state.gameOver) { + draw(); + animationId = requestAnimationFrame(tick); + return; + } + const interval = state.softDrop ? Math.min(state.dropInterval, 50) : state.dropInterval; + if (now - state.lastDrop > interval) { + if (!collides(state.board, state.current, 0, 1)) { + state.current.y++; + if (state.softDrop) { + state.score += 1; + } + } + else { + advancePiece(); + } + state.lastDrop = now; + } + draw(); + animationId = requestAnimationFrame(tick); + } + function startGame() { + state = initState(); + hideOverlay(); + running = true; + state.lastDrop = performance.now(); + if (animationId !== null) + cancelAnimationFrame(animationId); + animationId = requestAnimationFrame(tick); + } + // --- Controls --- + document.addEventListener("keydown", (e) => { + if (state.gameOver) + return; + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + state.paused = !state.paused; + if (state.paused) { + showOverlay("PAUSA", "Continuar"); + } + else { + hideOverlay(); + state.lastDrop = performance.now(); + } + return; + } + if (state.paused) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + if (!collides(state.board, state.current, -1, 0)) + state.current.x--; + e.preventDefault(); + break; + case "ArrowRight": + case "d": + if (!collides(state.board, state.current, 1, 0)) + state.current.x++; + e.preventDefault(); + break; + case "ArrowDown": + case "s": + state.softDrop = true; + e.preventDefault(); + break; + case "ArrowUp": + case "w": + tryRotate(state.board, state.current, 1); + e.preventDefault(); + break; + case "z": + case "Z": + tryRotate(state.board, state.current, -1); + e.preventDefault(); + break; + case " ": + // Hard drop + while (!collides(state.board, state.current, 0, 1)) { + state.current.y++; + state.score += 2; + } + advancePiece(); + state.lastDrop = performance.now(); + e.preventDefault(); + break; + } + draw(); + }); + document.addEventListener("keyup", (e) => { + if (e.key === "ArrowDown" || e.key === "s") { + state.softDrop = false; + } + }); + startBtn.addEventListener("click", () => { + if (state.paused && !state.gameOver) { + state.paused = false; + hideOverlay(); + state.lastDrop = performance.now(); + } + else { + startGame(); + } + }); + // --- Initial draw --- + draw(); + showOverlay("TETRIS", "Jugar"); +} +// ----- Boot ------------------------------------------------ +document.addEventListener("DOMContentLoaded", main); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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E,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD;YACE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;KACF;IACD,CAAC,EAAE;QACD;YACE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD;YACE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD;YACE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD;YACE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;KACF;IACD,CAAC,EAAE;QACD;YACE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD;YACE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD;YACE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACT,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACV;QACD;YACE,CAA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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.d.ts b/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.d.ts @@ -0,0 +1,30 @@ +declare const COLS = 10; +declare const ROWS = 20; +declare const BLOCK_SIZE = 30; +declare const COLORS: Record<string, string>; +declare const LINES_PER_LEVEL = 10; +declare const SCORE_TABLE: number[]; +declare function dropInterval(level: number): number; +type Shape = number[][]; +interface TetrominoDef { + type: string; + rotations: Shape[]; +} +declare function buildRotations(base: Shape): Shape[]; +declare const TETROMINOES: TetrominoDef[]; +interface Piece { + def: TetrominoDef; + rotation: number; + x: number; + y: number; +} +declare function createPiece(def: TetrominoDef): Piece; +type Cell = string | null; +type Board = Cell[][]; +declare function createBoard(): Board; +declare function isValidPosition(board: Board, piece: Piece, dx: number, dy: number, rotation?: number): boolean; +declare function lockPiece(board: Board, piece: Piece): void; +declare function clearLines(board: Board): number; +declare function tryRotate(board: Board, piece: Piece, direction: 1 | -1): boolean; +declare function ghostY(board: Board, piece: Piece): number; +export { COLS, ROWS, BLOCK_SIZE, COLORS, TETROMINOES, createBoard, clearLines, isValidPosition, createPiece, buildRotations, lockPiece, ghostY, tryRotate, dropInterval, SCORE_TABLE, LINES_PER_LEVEL }; diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,619 @@ +// ============================================================ +// TETRIS — Full browser game in TypeScript +// ============================================================ +// ----- Constants -------------------------------------------- +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 30; +const PREVIEW_BLOCK = 20; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const GHOST_ALPHA = 0.25; +// Lines needed per level (cumulative thresholds per level) +const LINES_PER_LEVEL = 10; +// Points awarded: index = number of lines cleared at once (1-4) +const SCORE_TABLE = [0, 100, 300, 500, 800]; +// Speed curve: milliseconds per drop at each level +function dropInterval(level) { + // NES-style curve, capped at level 29 + const frames = [ + 48, 43, 38, 33, 28, 23, 18, 13, 8, 6, + 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, + ]; + const idx = Math.min(level, frames.length - 1); + return frames[idx] * (1000 / 60); // ~60 fps frame to ms +} +function buildRotations(base) { + const rots = [base]; + let prev = base; + for (let r = 0; r < 3; r++) { + const size = prev.length; + const rotated = Array.from({ length: size }, () => Array(size).fill(0)); + for (let y = 0; y < size; y++) { + for (let x = 0; x < size; x++) { + rotated[x][size - 1 - y] = prev[y][x]; + } + } + rots.push(rotated); + prev = rotated; + } + return rots; +} +const TETROMINOES = [ + { + type: "I", + rotations: buildRotations([ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ]), + }, + { + type: "O", + rotations: buildRotations([ + [1, 1], + [1, 1], + ]), + }, + { + type: "T", + rotations: buildRotations([ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ]), + }, + { + type: "S", + rotations: buildRotations([ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ]), + }, + { + type: "Z", + rotations: buildRotations([ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ]), + }, + { + type: "J", + rotations: buildRotations([ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ]), + }, + { + type: "L", + rotations: buildRotations([ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ]), + }, +]; +// SRS wall-kick data (non-I pieces) +const WALL_KICKS_NORMAL = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// SRS wall-kick data (I piece) +const WALL_KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +function createPiece(def) { + const size = def.rotations[0].length; + return { + def, + rotation: 0, + x: Math.floor((COLS - size) / 2), + y: 0, + }; +} +function getShape(piece) { + return piece.def.rotations[piece.rotation]; +} +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function isValidPosition(board, piece, dx, dy, rotation) { + const shape = piece.def.rotations[rotation ?? piece.rotation]; + const size = shape.length; + for (let row = 0; row < size; row++) { + for (let col = 0; col < size; col++) { + if (!shape[row][col]) + continue; + const nx = piece.x + col + dx; + const ny = piece.y + row + dy; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return false; + if (ny < 0) + continue; // above screen is ok + if (board[ny][nx]) + return false; + } + } + return true; +} +function lockPiece(board, piece) { + const shape = getShape(piece); + const size = shape.length; + const color = COLORS[piece.def.type]; + for (let row = 0; row < size; row++) { + for (let col = 0; col < size; col++) { + if (!shape[row][col]) + continue; + const bx = piece.x + col; + const by = piece.y + row; + if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) { + board[by][bx] = color; + } + } + } +} +function clearLines(board) { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every((c) => c !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check this row index + } + } + return cleared; +} +// ----- Random bag generator --------------------------------- +function createBag() { + const bag = [...TETROMINOES]; + // Fisher-Yates shuffle + for (let i = bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [bag[i], bag[j]] = [bag[j], bag[i]]; + } + return bag; +} +function nextFromBag(bag) { + if (bag.length === 0) { + bag.push(...createBag()); + } + return bag.pop(); +} +function initGame() { + const bag = createBag(); + const first = nextFromBag(bag); + const next = nextFromBag(bag); + return { + board: createBoard(), + current: createPiece(first), + next, + bag, + score: 0, + level: 0, + lines: 0, + gameOver: false, + paused: false, + lastDrop: performance.now(), + lockDelay: 500, + lockTimer: 0, + softDropping: false, + }; +} +// ----- Rotation with SRS wall kicks ------------------------- +function tryRotate(board, piece, direction) { + const from = piece.rotation; + const to = (piece.rotation + direction + 4) % 4; + const key = `${from}>${to}`; + const kicks = piece.def.type === "I" ? WALL_KICKS_I : WALL_KICKS_NORMAL; + const tests = kicks[key]; + if (!tests) + return false; + for (const [kx, ky] of tests) { + if (isValidPosition(board, piece, kx, -ky, to)) { + piece.x += kx; + piece.y -= ky; + piece.rotation = to; + return true; + } + } + return false; +} +// ----- Ghost piece y ---------------------------------------- +function ghostY(board, piece) { + let dy = 0; + while (isValidPosition(board, piece, 0, dy + 1)) { + dy++; + } + return piece.y + dy; +} +// ----- Rendering -------------------------------------------- +function drawBlock(ctx, x, y, size, color, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size, y * size, size, size); + // highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x * size, y * size, size, 2); + ctx.fillRect(x * size, y * size, 2, size); + // shadow + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x * size + size - 2, y * size, 2, size); + ctx.fillRect(x * size, y * size + size - 2, size, 2); + ctx.globalAlpha = 1; +} +function drawBoard(ctx, board) { + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(COLS * BLOCK_SIZE, r * BLOCK_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, ROWS * BLOCK_SIZE); + ctx.stroke(); + } + // Locked blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c]) { + drawBlock(ctx, c, r, BLOCK_SIZE, board[r][c]); + } + } + } +} +function drawPiece(ctx, piece, offsetY = 0, alpha = 1) { + const shape = getShape(piece); + const size = shape.length; + const color = COLORS[piece.def.type]; + for (let row = 0; row < size; row++) { + for (let col = 0; col < size; col++) { + if (!shape[row][col]) + continue; + const bx = piece.x + col; + const by = piece.y + row + offsetY; + if (by < 0) + continue; + drawBlock(ctx, bx, by, BLOCK_SIZE, color, alpha); + } + } +} +function drawGhost(ctx, board, piece) { + const gy = ghostY(board, piece); + const shape = getShape(piece); + const size = shape.length; + const color = COLORS[piece.def.type]; + for (let row = 0; row < size; row++) { + for (let col = 0; col < size; col++) { + if (!shape[row][col]) + continue; + const bx = piece.x + col; + const by = gy + row; + if (by < 0) + continue; + drawBlock(ctx, bx, by, BLOCK_SIZE, color, GHOST_ALPHA); + } + } +} +function drawPreview(ctx, def) { + const canvas = ctx.canvas; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + const shape = def.rotations[0]; + const size = shape.length; + const color = COLORS[def.type]; + const offsetX = (canvas.width - size * PREVIEW_BLOCK) / 2; + const offsetY = (canvas.height - size * PREVIEW_BLOCK) / 2; + for (let row = 0; row < size; row++) { + for (let col = 0; col < size; col++) { + if (!shape[row][col]) + continue; + ctx.fillStyle = color; + const px = offsetX + col * PREVIEW_BLOCK; + const py = offsetY + row * PREVIEW_BLOCK; + ctx.fillRect(px, py, PREVIEW_BLOCK, PREVIEW_BLOCK); + ctx.fillStyle = "rgba(255,255,255,0.2)"; + ctx.fillRect(px, py, PREVIEW_BLOCK, 2); + ctx.fillRect(px, py, 2, PREVIEW_BLOCK); + ctx.fillStyle = "rgba(0,0,0,0.2)"; + ctx.fillRect(px + PREVIEW_BLOCK - 2, py, 2, PREVIEW_BLOCK); + ctx.fillRect(px, py + PREVIEW_BLOCK - 2, PREVIEW_BLOCK, 2); + } + } +} +// ----- Main game loop --------------------------------------- +function main() { + // --- DOM setup --- + const gameCanvas = document.getElementById("game-canvas"); + const previewCanvas = document.getElementById("preview-canvas"); + const scoreEl = document.getElementById("score"); + const levelEl = document.getElementById("level"); + const linesEl = document.getElementById("lines"); + const overlayEl = document.getElementById("overlay"); + const overlayText = document.getElementById("overlay-text"); + const startBtn = document.getElementById("start-btn"); + gameCanvas.width = COLS * BLOCK_SIZE; + gameCanvas.height = ROWS * BLOCK_SIZE; + const ctx = gameCanvas.getContext("2d"); + const pctx = previewCanvas.getContext("2d"); + let state = initGame(); + let animationId = 0; + let running = false; + function updateHUD() { + scoreEl.textContent = state.score.toLocaleString(); + levelEl.textContent = String(state.level); + linesEl.textContent = String(state.lines); + } + function spawnNext() { + const def = state.next; + state.next = nextFromBag(state.bag); + state.current = createPiece(def); + state.lockTimer = 0; + // Check game over + if (!isValidPosition(state.board, state.current, 0, 0)) { + state.gameOver = true; + overlayText.textContent = "GAME OVER"; + startBtn.textContent = "Reiniciar"; + overlayEl.classList.remove("hidden"); + running = false; + } + } + function lockAndClear() { + lockPiece(state.board, state.current); + const cleared = clearLines(state.board); + if (cleared > 0) { + state.lines += cleared; + state.score += SCORE_TABLE[cleared] * (state.level + 1); + state.level = Math.floor(state.lines / LINES_PER_LEVEL); + } + updateHUD(); + spawnNext(); + } + function hardDrop() { + const gy = ghostY(state.board, state.current); + const dist = gy - state.current.y; + state.score += dist * 2; + state.current.y = gy; + lockAndClear(); + } + function softDrop() { + if (isValidPosition(state.board, state.current, 0, 1)) { + state.current.y++; + state.score += 1; + return true; + } + return false; + } + function moveLeft() { + if (isValidPosition(state.board, state.current, -1, 0)) { + state.current.x--; + state.lockTimer = 0; // reset lock delay on successful move + } + } + function moveRight() { + if (isValidPosition(state.board, state.current, 1, 0)) { + state.current.x++; + state.lockTimer = 0; + } + } + function rotateCW() { + if (tryRotate(state.board, state.current, 1)) { + state.lockTimer = 0; + } + } + function rotateCCW() { + if (tryRotate(state.board, state.current, -1)) { + state.lockTimer = 0; + } + } + // --- Keyboard handling --- + const keysDown = new Set(); + document.addEventListener("keydown", (e) => { + if (state.gameOver) + return; + if (!running) + return; + if (e.code === "KeyP" || e.code === "Escape") { + e.preventDefault(); + state.paused = !state.paused; + if (state.paused) { + overlayText.textContent = "PAUSA"; + startBtn.textContent = "Continuar"; + overlayEl.classList.remove("hidden"); + } + else { + overlayEl.classList.add("hidden"); + state.lastDrop = performance.now(); + } + return; + } + if (state.paused) + return; + if (keysDown.has(e.code)) + return; + keysDown.add(e.code); + switch (e.code) { + case "ArrowLeft": + case "KeyA": + e.preventDefault(); + moveLeft(); + break; + case "ArrowRight": + case "KeyD": + e.preventDefault(); + moveRight(); + break; + case "ArrowDown": + case "KeyS": + e.preventDefault(); + state.softDropping = true; + softDrop(); + break; + case "ArrowUp": + case "KeyW": + case "KeyX": + e.preventDefault(); + rotateCW(); + break; + case "KeyZ": + case "ControlLeft": + case "ControlRight": + e.preventDefault(); + rotateCCW(); + break; + case "Space": + e.preventDefault(); + hardDrop(); + break; + } + }); + document.addEventListener("keyup", (e) => { + keysDown.delete(e.code); + if (e.code === "ArrowDown" || e.code === "KeyS") { + state.softDropping = false; + } + }); + // --- DAS (Delayed Auto Shift) for held keys --- + const DAS_DELAY = 170; // ms before auto-repeat starts + const DAS_RATE = 50; // ms between auto-repeats + let dasKey = null; + let dasTimer = 0; + let dasRepeatTimer = 0; + function updateDAS(now) { + // Check which direction key is currently held + const leftHeld = keysDown.has("ArrowLeft") || keysDown.has("KeyA"); + const rightHeld = keysDown.has("ArrowRight") || keysDown.has("KeyD"); + const downHeld = keysDown.has("ArrowDown") || keysDown.has("KeyS"); + let activeKey = null; + if (leftHeld) + activeKey = "left"; + else if (rightHeld) + activeKey = "right"; + if (downHeld) + activeKey = "down"; + if (activeKey !== dasKey) { + dasKey = activeKey; + dasTimer = now; + dasRepeatTimer = 0; + } + if (dasKey && now - dasTimer >= DAS_DELAY) { + const elapsed = now - dasTimer - DAS_DELAY; + const repeats = Math.floor(elapsed / DAS_RATE); + if (repeats > dasRepeatTimer) { + const newRepeats = repeats - dasRepeatTimer; + dasRepeatTimer = repeats; + for (let i = 0; i < newRepeats; i++) { + if (dasKey === "left") + moveLeft(); + else if (dasKey === "right") + moveRight(); + else if (dasKey === "down") + softDrop(); + } + } + } + } + // --- Game loop --- + function gameLoop(now) { + if (!running) + return; + if (state.gameOver) + return; + if (!state.paused) { + updateDAS(now); + const interval = state.softDropping + ? Math.min(dropInterval(state.level), 50) + : dropInterval(state.level); + if (now - state.lastDrop >= interval) { + state.lastDrop = now; + if (isValidPosition(state.board, state.current, 0, 1)) { + state.current.y++; + state.lockTimer = 0; + } + else { + // Lock delay + state.lockTimer += interval; + if (state.lockTimer >= state.lockDelay) { + lockAndClear(); + } + } + } + // Render + drawBoard(ctx, state.board); + drawGhost(ctx, state.board, state.current); + drawPiece(ctx, state.current); + drawPreview(pctx, state.next); + updateHUD(); + } + animationId = requestAnimationFrame(gameLoop); + } + // --- Start / restart --- + function startGame() { + state = initGame(); + overlayEl.classList.add("hidden"); + running = true; + state.lastDrop = performance.now(); + updateHUD(); + drawPreview(pctx, state.next); + animationId = requestAnimationFrame(gameLoop); + } + startBtn.addEventListener("click", () => { + if (state.paused && running) { + // Un-pause + state.paused = false; + overlayEl.classList.add("hidden"); + state.lastDrop = performance.now(); + return; + } + if (animationId) + cancelAnimationFrame(animationId); + startGame(); + }); + // Initial render + drawBoard(ctx, state.board); + overlayText.textContent = "TETRIS"; + startBtn.textContent = "Jugar"; + overlayEl.classList.remove("hidden"); +} +// Boot +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", main); +} +else { + main(); +} +export { COLS, ROWS, BLOCK_SIZE, COLORS, TETROMINOES, createBoard, clearLines, isValidPosition, createPiece, buildRotations, lockPiece, ghostY, tryRotate, dropInterval, SCORE_TABLE, LINES_PER_LEVEL }; +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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C,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClD,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CA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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js b/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js @@ -0,0 +1,660 @@ +"use strict"; +(() => { + var __getOwnPropNames = Object.getOwnPropertyNames; + var __esm = (fn, res) => function __init() { + return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; + }; + var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; + + // src/board.ts + function createBoard() { + return Array.from( + { length: BOARD_ROWS }, + () => new Array(BOARD_COLS).fill(null) + ); + } + function isValidPosition(board, matrix, x, y) { + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (matrix[r][c] === 0) continue; + const boardR = y + r; + const boardC = x + c; + if (boardC < 0 || boardC >= BOARD_COLS || boardR >= BOARD_ROWS) return false; + if (boardR >= 0 && board[boardR][boardC] !== null) return false; + } + } + return true; + } + function stampPiece(board, matrix, x, y, color) { + const next = board.map((row) => [...row]); + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (matrix[r][c] !== 0) { + const boardR = y + r; + const boardC = x + c; + if (boardR >= 0 && boardR < BOARD_ROWS) { + next[boardR][boardC] = color; + } + } + } + } + return next; + } + function clearLines(board) { + const remaining = board.filter((row) => row.some((cell) => cell === null)); + const cleared = BOARD_ROWS - remaining.length; + const emptyRows = Array.from( + { length: cleared }, + () => new Array(BOARD_COLS).fill(null) + ); + return { board: [...emptyRows, ...remaining], cleared }; + } + var BOARD_COLS, BOARD_ROWS; + var init_board = __esm({ + "src/board.ts"() { + "use strict"; + BOARD_COLS = 10; + BOARD_ROWS = 20; + } + }); + + // src/pieces.ts + function rotateCW(matrix) { + const rows = matrix.length; + const cols = matrix[0].length; + const result = []; + for (let c = 0; c < cols; c++) { + result.push([]); + for (let r = rows - 1; r >= 0; r--) { + result[c].push(matrix[r][c]); + } + } + return result; + } + var TETROMINOES, PieceBag; + var init_pieces = __esm({ + "src/pieces.ts"() { + "use strict"; + TETROMINOES = [ + { + name: "I", + color: "#00f0f0", + matrix: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0] + ] + }, + { + name: "O", + color: "#f0f000", + matrix: [ + [1, 1], + [1, 1] + ] + }, + { + name: "T", + color: "#a000f0", + matrix: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0] + ] + }, + { + name: "S", + color: "#00f000", + matrix: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0] + ] + }, + { + name: "Z", + color: "#f00000", + matrix: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0] + ] + }, + { + name: "J", + color: "#0070f0", + matrix: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0] + ] + }, + { + name: "L", + color: "#f0a000", + matrix: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0] + ] + } + ]; + PieceBag = class { + constructor() { + this.bag = []; + } + next() { + if (this.bag.length === 0) { + this.bag = [...TETROMINOES]; + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop(); + } + }; + } + }); + + // src/game.ts + function dropInterval(level) { + return Math.max(50, 1e3 - (level - 1) * 100); + } + function topVisibleRow(matrix) { + for (let r = 0; r < matrix.length; r++) { + if (matrix[r].some((v) => v !== 0)) return r; + } + return 0; + } + function spawnPosition(matrix) { + const x = Math.floor((BOARD_COLS - matrix[0].length) / 2); + const y = -topVisibleRow(matrix); + return { x, y }; + } + function loadHighScore() { + return parseInt(localStorage.getItem(HS_KEY) ?? "0", 10) || 0; + } + function saveHighScore(score) { + localStorage.setItem(HS_KEY, String(score)); + } + var LINE_POINTS, HS_KEY, TetrisGame; + var init_game = __esm({ + "src/game.ts"() { + "use strict"; + init_board(); + init_pieces(); + LINE_POINTS = [0, 100, 300, 500, 800]; + HS_KEY = "tetris-highscore"; + TetrisGame = class { + constructor(onUpdate) { + this.bag = new PieceBag(); + this.rafId = null; + this.lastDrop = 0; + this.onUpdate = onUpdate; + this.state = this.buildInitialState(); + } + // ── Public API ───────────────────────────────────────────────────────────── + start() { + if (this.rafId !== null) cancelAnimationFrame(this.rafId); + this.bag = new PieceBag(); + this.state = this.buildInitialState(); + this.spawn(); + this.lastDrop = performance.now(); + this.rafId = requestAnimationFrame((ts) => this.loop(ts)); + } + moveLeft() { + this.shift(-1); + } + moveRight() { + this.shift(1); + } + rotate() { + if (!this.canAct()) return; + const { matrix, x, y } = this.state.current; + const rotated = rotateCW(matrix); + for (const kick of [0, -1, 1, -2, 2]) { + if (isValidPosition(this.state.board, rotated, x + kick, y)) { + this.state.current.matrix = rotated; + this.state.current.x += kick; + return; + } + } + } + softDrop() { + if (!this.canAct()) return; + const { matrix, x, y } = this.state.current; + if (isValidPosition(this.state.board, matrix, x, y + 1)) { + this.state.current.y++; + this.state.score += 1; + this.lastDrop = performance.now(); + } else { + this.lock(); + } + } + hardDrop() { + if (!this.canAct()) return; + let dropped = 0; + while (true) { + const { matrix, x, y } = this.state.current; + if (isValidPosition(this.state.board, matrix, x, y + 1)) { + this.state.current.y++; + dropped++; + } else { + break; + } + } + this.state.score += dropped * 2; + this.lock(); + } + hold() { + if (!this.canAct() || !this.state.canHold) return; + const { current, held } = this.state; + const tetromino = current.tetromino; + const next = held ?? this.bag.next(); + const { x, y } = spawnPosition(next.matrix); + this.state.current = { tetromino: next, matrix: next.matrix, x, y }; + this.state.held = tetromino; + this.state.canHold = false; + } + togglePause() { + if (this.state.gameOver) return; + this.state.paused = !this.state.paused; + if (!this.state.paused) this.lastDrop = performance.now(); + } + /** Y coordinate of where the current piece would land (ghost piece). */ + ghostY() { + if (!this.state.current) return -1; + const { matrix, x, y } = this.state.current; + let gy = y; + while (isValidPosition(this.state.board, matrix, x, gy + 1)) gy++; + return gy; + } + getState() { + return this.state; + } + // ── Private helpers ──────────────────────────────────────────────────────── + buildInitialState() { + return { + board: createBoard(), + current: null, + next: this.bag.next(), + held: null, + canHold: true, + score: 0, + highScore: loadHighScore(), + level: 1, + lines: 0, + gameOver: false, + paused: false + }; + } + spawn() { + const tetromino = this.state.next; + const { x, y } = spawnPosition(tetromino.matrix); + if (!isValidPosition(this.state.board, tetromino.matrix, x, y)) { + this.state.gameOver = true; + if (this.state.score > this.state.highScore) { + this.state.highScore = this.state.score; + saveHighScore(this.state.score); + } + return; + } + this.state.current = { tetromino, matrix: tetromino.matrix, x, y }; + this.state.next = this.bag.next(); + this.state.canHold = true; + } + loop(ts) { + if (this.state.gameOver) { + this.onUpdate(this.state); + return; + } + if (!this.state.paused) { + if (ts - this.lastDrop >= dropInterval(this.state.level)) { + this.gravity(); + this.lastDrop = ts; + } + } + this.onUpdate(this.state); + this.rafId = requestAnimationFrame((t) => this.loop(t)); + } + gravity() { + if (!this.state.current) { + this.spawn(); + return; + } + const { matrix, x, y } = this.state.current; + if (isValidPosition(this.state.board, matrix, x, y + 1)) { + this.state.current.y++; + } else { + this.lock(); + } + } + lock() { + const c = this.state.current; + if (!c) return; + const stamped = stampPiece(this.state.board, c.matrix, c.x, c.y, c.tetromino.color); + const { board, cleared } = clearLines(stamped); + this.state.board = board; + if (cleared > 0) { + const pts = (LINE_POINTS[cleared] ?? 0) * this.state.level; + this.state.score += pts; + this.state.lines += cleared; + this.state.level = Math.floor(this.state.lines / 10) + 1; + if (this.state.score > this.state.highScore) { + this.state.highScore = this.state.score; + saveHighScore(this.state.score); + } + } + this.state.current = null; + this.spawn(); + } + shift(dx) { + if (!this.canAct()) return; + const { matrix, x, y } = this.state.current; + if (isValidPosition(this.state.board, matrix, x + dx, y)) { + this.state.current.x += dx; + } + } + canAct() { + return !this.state.gameOver && !this.state.paused && this.state.current !== null; + } + }; + } + }); + + // src/renderer.ts + function hex2rgba(hex, alpha) { + const r = parseInt(hex.slice(1, 3), 16); + const g = parseInt(hex.slice(3, 5), 16); + const b = parseInt(hex.slice(5, 7), 16); + return `rgba(${r},${g},${b},${alpha})`; + } + var CELL, C, Renderer; + var init_renderer = __esm({ + "src/renderer.ts"() { + "use strict"; + init_board(); + CELL = 30; + C = { + bg: "#080818", + gridLine: "rgba(255,255,255,0.04)", + ghostFill: "rgba(255,255,255,0.07)", + ghostStroke: "rgba(255,255,255,0.30)", + overlay: "rgba(6,6,22,0.78)", + textMain: "#ffffff", + textSub: "rgba(255,255,255,0.55)", + gameOver: "#ff3355", + paused: "#ffe066", + shine: "rgba(255,255,255,0.22)", + shadow: "rgba(0,0,0,0.30)" + }; + Renderer = class { + constructor(gameId, nextId, holdId) { + this.gCanvas = document.getElementById(gameId); + this.nCanvas = document.getElementById(nextId); + this.hCanvas = document.getElementById(holdId); + this.gCtx = this.gCanvas.getContext("2d"); + this.nCtx = this.nCanvas.getContext("2d"); + this.hCtx = this.hCanvas.getContext("2d"); + } + render(state, ghostY) { + this.drawMainCanvas(state, ghostY); + this.drawMiniCanvas(this.nCtx, this.nCanvas, state.next); + this.drawMiniCanvas(this.hCtx, this.hCanvas, state.held ?? null); + } + // ── Main board ────────────────────────────────────────────────────────────── + drawMainCanvas(state, ghostY) { + const ctx = this.gCtx; + const W = BOARD_COLS * CELL; + const H = BOARD_ROWS * CELL; + ctx.fillStyle = C.bg; + ctx.fillRect(0, 0, W, H); + this.drawGridLines(ctx, W, H); + this.drawLockedCells(ctx, state.board); + if (state.current) { + if (!state.paused) { + this.drawGhost(ctx, state.current.matrix, state.current.x, ghostY); + } + this.drawPieceCells(ctx, state.current.matrix, state.current.x, state.current.y, state.current.tetromino.color); + } + if (state.gameOver) { + this.drawOverlay(ctx, W, H, "GAME OVER", C.gameOver, "Press R to restart"); + } else if (state.paused) { + this.drawOverlay(ctx, W, H, "PAUSED", C.paused, "Press P to continue"); + } + } + drawGridLines(ctx, W, H) { + ctx.save(); + ctx.strokeStyle = C.gridLine; + ctx.lineWidth = 1; + for (let r = 0; r <= BOARD_ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(W, r * CELL); + ctx.stroke(); + } + for (let c = 0; c <= BOARD_COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, H); + ctx.stroke(); + } + ctx.restore(); + } + drawLockedCells(ctx, board) { + for (let r = 0; r < BOARD_ROWS; r++) { + for (let c = 0; c < BOARD_COLS; c++) { + const color = board[r][c]; + if (color) this.drawCell(ctx, c, r, color, CELL); + } + } + } + drawPieceCells(ctx, matrix, x, y, color) { + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (matrix[r][c] !== 0) { + const br = y + r; + const bc = x + c; + if (br >= 0 && br < BOARD_ROWS) { + this.drawCell(ctx, bc, br, color, CELL); + } + } + } + } + } + drawGhost(ctx, matrix, x, gy) { + ctx.save(); + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (matrix[r][c] !== 0) { + const br = gy + r; + const bc = x + c; + if (br >= 0 && br < BOARD_ROWS) { + const px = bc * CELL + 1; + const py = br * CELL + 1; + const sz = CELL - 2; + ctx.fillStyle = C.ghostFill; + ctx.fillRect(px, py, sz, sz); + ctx.strokeStyle = C.ghostStroke; + ctx.lineWidth = 1.5; + ctx.strokeRect(px, py, sz, sz); + } + } + } + } + ctx.restore(); + } + /** + * Draw one cell with a bevel highlight effect. + * `cellPx` lets us reuse this for mini previews (different cell size). + */ + drawCell(ctx, col, row, color, cellPx) { + const x = col * cellPx; + const y = row * cellPx; + const pad = 1; + const sz = cellPx - pad * 2; + ctx.fillStyle = color; + ctx.fillRect(x + pad, y + pad, sz, sz); + ctx.fillStyle = C.shine; + ctx.fillRect(x + pad, y + pad, sz, 5); + ctx.fillRect(x + pad, y + pad, 5, sz); + ctx.fillStyle = C.shadow; + ctx.fillRect(x + pad, y + pad + sz - 5, sz, 5); + ctx.fillRect(x + pad + sz - 5, y + pad, 5, sz); + ctx.fillStyle = hex2rgba(color, 0.6); + ctx.fillRect(x + pad + 5, y + pad + 2, sz - 10, 2); + } + drawOverlay(ctx, W, H, title, titleColor, subtitle) { + ctx.save(); + ctx.fillStyle = C.overlay; + ctx.fillRect(0, 0, W, H); + ctx.textAlign = "center"; + ctx.font = 'bold 34px "Courier New", monospace'; + ctx.fillStyle = titleColor; + ctx.shadowColor = titleColor; + ctx.shadowBlur = 18; + ctx.fillText(title, W / 2, H / 2 - 18); + ctx.font = '15px "Courier New", monospace'; + ctx.fillStyle = C.textSub; + ctx.shadowBlur = 0; + ctx.fillText(subtitle, W / 2, H / 2 + 18); + ctx.restore(); + } + // ── Mini canvases (next / hold) ──────────────────────────────────────────── + drawMiniCanvas(ctx, canvas, piece) { + const W = canvas.width; + const H = canvas.height; + ctx.fillStyle = C.bg; + ctx.fillRect(0, 0, W, H); + if (!piece) return; + const { matrix, color } = piece; + const cols = matrix[0].length; + const rows = matrix.length; + const cellPx = Math.min(Math.floor(W / 4), Math.floor(H / 4)); + const startX = Math.floor((W - cols * cellPx) / 2); + const startY = Math.floor((H - rows * cellPx) / 2); + ctx.save(); + ctx.translate(startX, startY); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (matrix[r][c] !== 0) { + this.drawCell(ctx, c, r, color, cellPx); + } + } + } + ctx.restore(); + } + }; + } + }); + + // src/main.ts + var require_main = __commonJS({ + "src/main.ts"() { + init_game(); + init_renderer(); + var DAS = class { + /** + * @param action What to do each repeat tick + * @param delay ms before first repeat (default 167 ms) + * @param interval ms between subsequent repeats (default 33 ms ≈ 2 frames) + */ + constructor(action, delay = 167, interval = 33) { + this.action = action; + this.delay = delay; + this.interval = interval; + this.timerId = null; + this.intervalId = null; + } + press() { + this.action(); + this.cancel(); + this.timerId = setTimeout(() => { + this.intervalId = setInterval(this.action, this.interval); + }, this.delay); + } + cancel() { + if (this.timerId !== null) { + clearTimeout(this.timerId); + this.timerId = null; + } + if (this.intervalId !== null) { + clearInterval(this.intervalId); + this.intervalId = null; + } + } + }; + var renderer = new Renderer("gameCanvas", "nextCanvas", "holdCanvas"); + var game; + var dasLeft = new DAS(() => game.moveLeft()); + var dasRight = new DAS(() => game.moveRight()); + var dasDown = new DAS(() => game.softDrop(), 0, 50); + function updateUI(state) { + document.getElementById("score").textContent = state.score.toString(); + document.getElementById("highscore").textContent = state.highScore.toString(); + document.getElementById("level").textContent = state.level.toString(); + document.getElementById("lines").textContent = state.lines.toString(); + renderer.render(state, game.ghostY()); + } + function startGame() { + dasLeft.cancel(); + dasRight.cancel(); + dasDown.cancel(); + game = new TetrisGame(updateUI); + game.start(); + } + document.addEventListener("keydown", (e) => { + if (e.repeat) return; + switch (e.key) { + case "ArrowLeft": + e.preventDefault(); + dasLeft.press(); + break; + case "ArrowRight": + e.preventDefault(); + dasRight.press(); + break; + case "ArrowDown": + e.preventDefault(); + dasDown.press(); + break; + case "ArrowUp": + case "x": + case "X": + e.preventDefault(); + game.rotate(); + break; + case " ": + e.preventDefault(); + game.hardDrop(); + break; + case "c": + case "C": + case "Shift": + game.hold(); + break; + case "p": + case "P": + game.togglePause(); + break; + case "r": + case "R": + startGame(); + break; + } + }); + document.addEventListener("keyup", (e) => { + if (e.key === "ArrowLeft") dasLeft.cancel(); + if (e.key === "ArrowRight") dasRight.cancel(); + if (e.key === "ArrowDown") dasDown.cancel(); + }); + startGame(); + } + }); + require_main(); +})(); +//# sourceMappingURL=main.js.map diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js.map b/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../src/board.ts", "../src/pieces.ts", "../src/game.ts", "../src/renderer.ts", "../src/main.ts"], + "sourcesContent": ["// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Board state & collision / line-clear logic\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport type { Matrix } from \"./pieces\";\n\nexport const BOARD_COLS = 10;\nexport const BOARD_ROWS = 20;\n\nexport type Cell = string | null; // null = empty, string = colour\nexport type Board = Cell[][];\n\n/** Create a fresh empty board. */\nexport function createBoard(): Board {\n return Array.from({ length: BOARD_ROWS }, () =>\n new Array<Cell>(BOARD_COLS).fill(null)\n );\n}\n\n/**\n * Returns true if placing `matrix` at board position (x, y) is valid:\n * - No out-of-bounds (left, right, bottom)\n * - No overlap with already-locked cells\n * Cells above the top (y < 0) are allowed (spawn area).\n */\nexport function isValidPosition(\n board: Board,\n matrix: Matrix,\n x: number,\n y: number\n): boolean {\n for (let r = 0; r < matrix.length; r++) {\n for (let c = 0; c < matrix[r].length; c++) {\n if (matrix[r][c] === 0) continue;\n const boardR = y + r;\n const boardC = x + c;\n if (boardC < 0 || boardC >= BOARD_COLS || boardR >= BOARD_ROWS) return false;\n if (boardR >= 0 && board[boardR][boardC] !== null) return false;\n }\n }\n return true;\n}\n\n/** Stamp a piece onto the board and return the updated board copy. */\nexport function stampPiece(\n board: Board,\n matrix: Matrix,\n x: number,\n y: number,\n color: string\n): Board {\n const next = board.map((row) => [...row]);\n for (let r = 0; r < matrix.length; r++) {\n for (let c = 0; c < matrix[r].length; c++) {\n if (matrix[r][c] !== 0) {\n const boardR = y + r;\n const boardC = x + c;\n if (boardR >= 0 && boardR < BOARD_ROWS) {\n next[boardR][boardC] = color;\n }\n }\n }\n }\n return next;\n}\n\n/** Remove all full rows and return the new board + how many were cleared. */\nexport function clearLines(board: Board): { board: Board; cleared: number } {\n const remaining = board.filter((row) => row.some((cell) => cell === null));\n const cleared = BOARD_ROWS - remaining.length;\n const emptyRows = Array.from({ length: cleared }, () =>\n new Array<Cell>(BOARD_COLS).fill(null)\n );\n return { board: [...emptyRows, ...remaining], cleared };\n}\n", "// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Tetromino definitions & helpers\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type Matrix = number[][];\n\nexport interface Tetromino {\n readonly name: string;\n readonly color: string;\n readonly matrix: Matrix;\n}\n\n/** All seven standard tetrominoes (Tetris Guideline colours). */\nexport const TETROMINOES: readonly Tetromino[] = [\n {\n name: \"I\",\n color: \"#00f0f0\",\n matrix: [\n [0, 0, 0, 0],\n [1, 1, 1, 1],\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n ],\n },\n {\n name: \"O\",\n color: \"#f0f000\",\n matrix: [\n [1, 1],\n [1, 1],\n ],\n },\n {\n name: \"T\",\n color: \"#a000f0\",\n matrix: [\n [0, 1, 0],\n [1, 1, 1],\n [0, 0, 0],\n ],\n },\n {\n name: \"S\",\n color: \"#00f000\",\n matrix: [\n [0, 1, 1],\n [1, 1, 0],\n [0, 0, 0],\n ],\n },\n {\n name: \"Z\",\n color: \"#f00000\",\n matrix: [\n [1, 1, 0],\n [0, 1, 1],\n [0, 0, 0],\n ],\n },\n {\n name: \"J\",\n color: \"#0070f0\",\n matrix: [\n [1, 0, 0],\n [1, 1, 1],\n [0, 0, 0],\n ],\n },\n {\n name: \"L\",\n color: \"#f0a000\",\n matrix: [\n [0, 0, 1],\n [1, 1, 1],\n [0, 0, 0],\n ],\n },\n] as const;\n\n/** Rotate a matrix 90 degrees clockwise. */\nexport function rotateCW(matrix: Matrix): Matrix {\n const rows = matrix.length;\n const cols = matrix[0].length;\n const result: Matrix = [];\n for (let c = 0; c < cols; c++) {\n result.push([]);\n for (let r = rows - 1; r >= 0; r--) {\n result[c].push(matrix[r][c]);\n }\n }\n return result;\n}\n\n/** 7-bag randomiser: guarantees each piece appears once per cycle. */\nexport class PieceBag {\n private bag: Tetromino[] = [];\n\n next(): Tetromino {\n if (this.bag.length === 0) {\n this.bag = [...TETROMINOES];\n // Fisher-Yates shuffle\n for (let i = this.bag.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [this.bag[i], this.bag[j]] = [this.bag[j]!, this.bag[i]!];\n }\n }\n return this.bag.pop()!;\n }\n}\n", "// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Game state machine & main loop\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport {\n Board,\n BOARD_COLS,\n BOARD_ROWS,\n createBoard,\n isValidPosition,\n stampPiece,\n clearLines,\n} from \"./board\";\nimport { Matrix, Tetromino, PieceBag, rotateCW } from \"./pieces\";\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ActivePiece {\n tetromino: Tetromino;\n matrix: Matrix;\n x: number;\n y: number;\n}\n\nexport interface GameState {\n board: Board;\n current: ActivePiece | null;\n next: Tetromino;\n held: Tetromino | null;\n canHold: boolean;\n score: number;\n highScore: number;\n level: number;\n lines: number;\n gameOver: boolean;\n paused: boolean;\n}\n\n// \u2500\u2500 Scoring (classic guideline) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst LINE_POINTS = [0, 100, 300, 500, 800] as const;\n\n/** Gravity interval in ms per level (minimum 50 ms \u2248 level 10+). */\nfunction dropInterval(level: number): number {\n return Math.max(50, 1000 - (level - 1) * 100);\n}\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction topVisibleRow(matrix: Matrix): number {\n for (let r = 0; r < matrix.length; r++) {\n if (matrix[r].some((v) => v !== 0)) return r;\n }\n return 0;\n}\n\nfunction spawnPosition(matrix: Matrix): { x: number; y: number } {\n const x = Math.floor((BOARD_COLS - matrix[0].length) / 2);\n const y = -topVisibleRow(matrix); // shift up so top visible row sits at row 0\n return { x, y };\n}\n\nconst HS_KEY = \"tetris-highscore\";\n\nfunction loadHighScore(): number {\n return parseInt(localStorage.getItem(HS_KEY) ?? \"0\", 10) || 0;\n}\n\nfunction saveHighScore(score: number): void {\n localStorage.setItem(HS_KEY, String(score));\n}\n\n// \u2500\u2500 Game class \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class TetrisGame {\n private state: GameState;\n private bag = new PieceBag();\n private rafId: number | null = null;\n private lastDrop = 0;\n private readonly onUpdate: (state: Readonly<GameState>) => void;\n\n constructor(onUpdate: (state: Readonly<GameState>) => void) {\n this.onUpdate = onUpdate;\n this.state = this.buildInitialState();\n }\n\n // \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n start(): void {\n if (this.rafId !== null) cancelAnimationFrame(this.rafId);\n this.bag = new PieceBag();\n this.state = this.buildInitialState();\n this.spawn();\n this.lastDrop = performance.now();\n this.rafId = requestAnimationFrame((ts) => this.loop(ts));\n }\n\n moveLeft(): void {\n this.shift(-1);\n }\n moveRight(): void {\n this.shift(1);\n }\n\n rotate(): void {\n if (!this.canAct()) return;\n const { matrix, x, y } = this.state.current!;\n const rotated = rotateCW(matrix);\n // Wall-kick offsets: try 0, -1, +1, -2, +2\n for (const kick of [0, -1, 1, -2, 2]) {\n if (isValidPosition(this.state.board, rotated, x + kick, y)) {\n this.state.current!.matrix = rotated;\n this.state.current!.x += kick;\n return;\n }\n }\n }\n\n softDrop(): void {\n if (!this.canAct()) return;\n const { matrix, x, y } = this.state.current!;\n if (isValidPosition(this.state.board, matrix, x, y + 1)) {\n this.state.current!.y++;\n this.state.score += 1;\n this.lastDrop = performance.now(); // reset gravity timer\n } else {\n this.lock();\n }\n }\n\n hardDrop(): void {\n if (!this.canAct()) return;\n let dropped = 0;\n while (true) {\n const { matrix, x, y } = this.state.current!;\n if (isValidPosition(this.state.board, matrix, x, y + 1)) {\n this.state.current!.y++;\n dropped++;\n } else {\n break;\n }\n }\n this.state.score += dropped * 2;\n this.lock();\n }\n\n hold(): void {\n if (!this.canAct() || !this.state.canHold) return;\n const { current, held } = this.state;\n const tetromino = current!.tetromino;\n const next = held ?? this.bag.next();\n const { x, y } = spawnPosition(next.matrix);\n this.state.current = { tetromino: next, matrix: next.matrix, x, y };\n this.state.held = tetromino;\n this.state.canHold = false;\n }\n\n togglePause(): void {\n if (this.state.gameOver) return;\n this.state.paused = !this.state.paused;\n if (!this.state.paused) this.lastDrop = performance.now();\n }\n\n /** Y coordinate of where the current piece would land (ghost piece). */\n ghostY(): number {\n if (!this.state.current) return -1;\n const { matrix, x, y } = this.state.current;\n let gy = y;\n while (isValidPosition(this.state.board, matrix, x, gy + 1)) gy++;\n return gy;\n }\n\n getState(): Readonly<GameState> {\n return this.state;\n }\n\n // \u2500\u2500 Private helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private buildInitialState(): GameState {\n return {\n board: createBoard(),\n current: null,\n next: this.bag.next(),\n held: null,\n canHold: true,\n score: 0,\n highScore: loadHighScore(),\n level: 1,\n lines: 0,\n gameOver: false,\n paused: false,\n };\n }\n\n private spawn(): void {\n const tetromino = this.state.next;\n const { x, y } = spawnPosition(tetromino.matrix);\n if (!isValidPosition(this.state.board, tetromino.matrix, x, y)) {\n this.state.gameOver = true;\n if (this.state.score > this.state.highScore) {\n this.state.highScore = this.state.score;\n saveHighScore(this.state.score);\n }\n return;\n }\n this.state.current = { tetromino, matrix: tetromino.matrix, x, y };\n this.state.next = this.bag.next();\n this.state.canHold = true;\n }\n\n private loop(ts: number): void {\n if (this.state.gameOver) {\n this.onUpdate(this.state);\n return;\n }\n if (!this.state.paused) {\n if (ts - this.lastDrop >= dropInterval(this.state.level)) {\n this.gravity();\n this.lastDrop = ts;\n }\n }\n this.onUpdate(this.state);\n this.rafId = requestAnimationFrame((t) => this.loop(t));\n }\n\n private gravity(): void {\n if (!this.state.current) {\n this.spawn();\n return;\n }\n const { matrix, x, y } = this.state.current;\n if (isValidPosition(this.state.board, matrix, x, y + 1)) {\n this.state.current.y++;\n } else {\n this.lock();\n }\n }\n\n private lock(): void {\n const c = this.state.current;\n if (!c) return;\n const stamped = stampPiece(this.state.board, c.matrix, c.x, c.y, c.tetromino.color);\n const { board, cleared } = clearLines(stamped);\n this.state.board = board;\n if (cleared > 0) {\n const pts = (LINE_POINTS[cleared] ?? 0) * this.state.level;\n this.state.score += pts;\n this.state.lines += cleared;\n this.state.level = Math.floor(this.state.lines / 10) + 1;\n if (this.state.score > this.state.highScore) {\n this.state.highScore = this.state.score;\n saveHighScore(this.state.score);\n }\n }\n this.state.current = null;\n this.spawn();\n }\n\n private shift(dx: number): void {\n if (!this.canAct()) return;\n const { matrix, x, y } = this.state.current!;\n if (isValidPosition(this.state.board, matrix, x + dx, y)) {\n this.state.current!.x += dx;\n }\n }\n\n private canAct(): boolean {\n return !this.state.gameOver && !this.state.paused && this.state.current !== null;\n }\n}\n", "// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Canvas renderer\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport { BOARD_COLS, BOARD_ROWS, Board } from \"./board\";\nimport { Matrix, Tetromino } from \"./pieces\";\nimport { GameState } from \"./game\";\n\nconst CELL = 30; // px per cell on the main board\n\n// \u2500\u2500 Palette \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst C = {\n bg: \"#080818\",\n gridLine: \"rgba(255,255,255,0.04)\",\n ghostFill: \"rgba(255,255,255,0.07)\",\n ghostStroke: \"rgba(255,255,255,0.30)\",\n overlay: \"rgba(6,6,22,0.78)\",\n textMain: \"#ffffff\",\n textSub: \"rgba(255,255,255,0.55)\",\n gameOver: \"#ff3355\",\n paused: \"#ffe066\",\n shine: \"rgba(255,255,255,0.22)\",\n shadow: \"rgba(0,0,0,0.30)\",\n};\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction hex2rgba(hex: string, alpha: number): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r},${g},${b},${alpha})`;\n}\n\n// \u2500\u2500 Renderer class \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class Renderer {\n private readonly gCtx: CanvasRenderingContext2D;\n private readonly nCtx: CanvasRenderingContext2D;\n private readonly hCtx: CanvasRenderingContext2D;\n private readonly gCanvas: HTMLCanvasElement;\n private readonly nCanvas: HTMLCanvasElement;\n private readonly hCanvas: HTMLCanvasElement;\n\n constructor(gameId: string, nextId: string, holdId: string) {\n this.gCanvas = document.getElementById(gameId) as HTMLCanvasElement;\n this.nCanvas = document.getElementById(nextId) as HTMLCanvasElement;\n this.hCanvas = document.getElementById(holdId) as HTMLCanvasElement;\n this.gCtx = this.gCanvas.getContext(\"2d\")!;\n this.nCtx = this.nCanvas.getContext(\"2d\")!;\n this.hCtx = this.hCanvas.getContext(\"2d\")!;\n }\n\n render(state: Readonly<GameState>, ghostY: number): void {\n this.drawMainCanvas(state, ghostY);\n this.drawMiniCanvas(this.nCtx, this.nCanvas, state.next);\n this.drawMiniCanvas(this.hCtx, this.hCanvas, state.held ?? null);\n }\n\n // \u2500\u2500 Main board \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private drawMainCanvas(state: Readonly<GameState>, ghostY: number): void {\n const ctx = this.gCtx;\n const W = BOARD_COLS * CELL;\n const H = BOARD_ROWS * CELL;\n\n // Background\n ctx.fillStyle = C.bg;\n ctx.fillRect(0, 0, W, H);\n\n this.drawGridLines(ctx, W, H);\n this.drawLockedCells(ctx, state.board);\n\n if (state.current) {\n // Ghost piece\n if (!state.paused) {\n this.drawGhost(ctx, state.current.matrix, state.current.x, ghostY);\n }\n // Active piece\n this.drawPieceCells(ctx, state.current.matrix, state.current.x, state.current.y, state.current.tetromino.color);\n }\n\n // Overlays\n if (state.gameOver) {\n this.drawOverlay(ctx, W, H, \"GAME OVER\", C.gameOver, \"Press R to restart\");\n } else if (state.paused) {\n this.drawOverlay(ctx, W, H, \"PAUSED\", C.paused, \"Press P to continue\");\n }\n }\n\n private drawGridLines(ctx: CanvasRenderingContext2D, W: number, H: number): void {\n ctx.save();\n ctx.strokeStyle = C.gridLine;\n ctx.lineWidth = 1;\n for (let r = 0; r <= BOARD_ROWS; r++) {\n ctx.beginPath();\n ctx.moveTo(0, r * CELL);\n ctx.lineTo(W, r * CELL);\n ctx.stroke();\n }\n for (let c = 0; c <= BOARD_COLS; c++) {\n ctx.beginPath();\n ctx.moveTo(c * CELL, 0);\n ctx.lineTo(c * CELL, H);\n ctx.stroke();\n }\n ctx.restore();\n }\n\n private drawLockedCells(ctx: CanvasRenderingContext2D, board: Board): void {\n for (let r = 0; r < BOARD_ROWS; r++) {\n for (let c = 0; c < BOARD_COLS; c++) {\n const color = board[r][c];\n if (color) this.drawCell(ctx, c, r, color, CELL);\n }\n }\n }\n\n private drawPieceCells(\n ctx: CanvasRenderingContext2D,\n matrix: Matrix,\n x: number,\n y: number,\n color: string\n ): void {\n for (let r = 0; r < matrix.length; r++) {\n for (let c = 0; c < matrix[r].length; c++) {\n if (matrix[r][c] !== 0) {\n const br = y + r;\n const bc = x + c;\n if (br >= 0 && br < BOARD_ROWS) {\n this.drawCell(ctx, bc, br, color, CELL);\n }\n }\n }\n }\n }\n\n private drawGhost(\n ctx: CanvasRenderingContext2D,\n matrix: Matrix,\n x: number,\n gy: number\n ): void {\n ctx.save();\n for (let r = 0; r < matrix.length; r++) {\n for (let c = 0; c < matrix[r].length; c++) {\n if (matrix[r][c] !== 0) {\n const br = gy + r;\n const bc = x + c;\n if (br >= 0 && br < BOARD_ROWS) {\n const px = bc * CELL + 1;\n const py = br * CELL + 1;\n const sz = CELL - 2;\n ctx.fillStyle = C.ghostFill;\n ctx.fillRect(px, py, sz, sz);\n ctx.strokeStyle = C.ghostStroke;\n ctx.lineWidth = 1.5;\n ctx.strokeRect(px, py, sz, sz);\n }\n }\n }\n }\n ctx.restore();\n }\n\n /**\n * Draw one cell with a bevel highlight effect.\n * `cellPx` lets us reuse this for mini previews (different cell size).\n */\n private drawCell(\n ctx: CanvasRenderingContext2D,\n col: number,\n row: number,\n color: string,\n cellPx: number\n ): void {\n const x = col * cellPx;\n const y = row * cellPx;\n const pad = 1;\n const sz = cellPx - pad * 2;\n\n // Base fill\n ctx.fillStyle = color;\n ctx.fillRect(x + pad, y + pad, sz, sz);\n\n // Inner top-left shine\n ctx.fillStyle = C.shine;\n ctx.fillRect(x + pad, y + pad, sz, 5);\n ctx.fillRect(x + pad, y + pad, 5, sz);\n\n // Inner bottom-right shadow\n ctx.fillStyle = C.shadow;\n ctx.fillRect(x + pad, y + pad + sz - 5, sz, 5);\n ctx.fillRect(x + pad + sz - 5, y + pad, 5, sz);\n\n // Subtle inner highlight line (top edge)\n ctx.fillStyle = hex2rgba(color, 0.6);\n ctx.fillRect(x + pad + 5, y + pad + 2, sz - 10, 2);\n }\n\n private drawOverlay(\n ctx: CanvasRenderingContext2D,\n W: number,\n H: number,\n title: string,\n titleColor: string,\n subtitle: string\n ): void {\n ctx.save();\n ctx.fillStyle = C.overlay;\n ctx.fillRect(0, 0, W, H);\n\n ctx.textAlign = \"center\";\n ctx.font = 'bold 34px \"Courier New\", monospace';\n ctx.fillStyle = titleColor;\n ctx.shadowColor = titleColor;\n ctx.shadowBlur = 18;\n ctx.fillText(title, W / 2, H / 2 - 18);\n\n ctx.font = '15px \"Courier New\", monospace';\n ctx.fillStyle = C.textSub;\n ctx.shadowBlur = 0;\n ctx.fillText(subtitle, W / 2, H / 2 + 18);\n ctx.restore();\n }\n\n // \u2500\u2500 Mini canvases (next / hold) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private drawMiniCanvas(\n ctx: CanvasRenderingContext2D,\n canvas: HTMLCanvasElement,\n piece: Tetromino | null\n ): void {\n const W = canvas.width;\n const H = canvas.height;\n ctx.fillStyle = C.bg;\n ctx.fillRect(0, 0, W, H);\n\n if (!piece) return;\n\n const { matrix, color } = piece;\n const cols = matrix[0].length;\n const rows = matrix.length;\n const cellPx = Math.min(Math.floor(W / 4), Math.floor(H / 4));\n const startX = Math.floor((W - cols * cellPx) / 2);\n const startY = Math.floor((H - rows * cellPx) / 2);\n\n ctx.save();\n ctx.translate(startX, startY);\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < cols; c++) {\n if (matrix[r][c] !== 0) {\n this.drawCell(ctx, c, r, color, cellPx);\n }\n }\n }\n ctx.restore();\n }\n}\n", "// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Entry point \u2013 input handling, DAS, UI updates\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport { TetrisGame, GameState } from \"./game\";\nimport { Renderer } from \"./renderer\";\n\n// \u2500\u2500 DAS (Delayed Auto Shift) helper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nclass DAS {\n private timerId: ReturnType<typeof setTimeout> | null = null;\n private intervalId: ReturnType<typeof setInterval> | null = null;\n\n /**\n * @param action What to do each repeat tick\n * @param delay ms before first repeat (default 167 ms)\n * @param interval ms between subsequent repeats (default 33 ms \u2248 2 frames)\n */\n constructor(\n private readonly action: () => void,\n private readonly delay = 167,\n private readonly interval = 33\n ) {}\n\n press(): void {\n this.action(); // immediate response\n this.cancel();\n this.timerId = setTimeout(() => {\n this.intervalId = setInterval(this.action, this.interval);\n }, this.delay);\n }\n\n cancel(): void {\n if (this.timerId !== null) { clearTimeout(this.timerId); this.timerId = null; }\n if (this.intervalId !== null) { clearInterval(this.intervalId); this.intervalId = null; }\n }\n}\n\n// \u2500\u2500 Setup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst renderer = new Renderer(\"gameCanvas\", \"nextCanvas\", \"holdCanvas\");\n\nlet game!: TetrisGame;\n\n// DAS instances \u2014 arrow functions keep a live reference to `game`\nconst dasLeft = new DAS(() => game.moveLeft());\nconst dasRight = new DAS(() => game.moveRight());\nconst dasDown = new DAS(() => game.softDrop(), 0, 50);\n\nfunction updateUI(state: Readonly<GameState>): void {\n (document.getElementById(\"score\") as HTMLElement).textContent = state.score.toString();\n (document.getElementById(\"highscore\") as HTMLElement).textContent = state.highScore.toString();\n (document.getElementById(\"level\") as HTMLElement).textContent = state.level.toString();\n (document.getElementById(\"lines\") as HTMLElement).textContent = state.lines.toString();\n renderer.render(state, game.ghostY());\n}\n\nfunction startGame(): void {\n // Cancel any lingering DAS so keys held through restart don't repeat\n dasLeft.cancel();\n dasRight.cancel();\n dasDown.cancel();\n game = new TetrisGame(updateUI);\n game.start();\n}\n\n// \u2500\u2500 Keyboard input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ndocument.addEventListener(\"keydown\", (e: KeyboardEvent) => {\n if (e.repeat) return; // native key-repeat is handled by our DAS\n\n switch (e.key) {\n case \"ArrowLeft\":\n e.preventDefault();\n dasLeft.press();\n break;\n case \"ArrowRight\":\n e.preventDefault();\n dasRight.press();\n break;\n case \"ArrowDown\":\n e.preventDefault();\n dasDown.press();\n break;\n case \"ArrowUp\":\n case \"x\":\n case \"X\":\n e.preventDefault();\n game.rotate();\n break;\n case \" \":\n e.preventDefault();\n game.hardDrop();\n break;\n case \"c\":\n case \"C\":\n case \"Shift\":\n game.hold();\n break;\n case \"p\":\n case \"P\":\n game.togglePause();\n break;\n case \"r\":\n case \"R\":\n startGame();\n break;\n }\n});\n\ndocument.addEventListener(\"keyup\", (e: KeyboardEvent) => {\n if (e.key === \"ArrowLeft\") dasLeft.cancel();\n if (e.key === \"ArrowRight\") dasRight.cancel();\n if (e.key === \"ArrowDown\") dasDown.cancel();\n});\n\n// \u2500\u2500 Start \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nstartGame();\n"], + "mappings": ";;;;;;;;;;;AAaO,WAAS,cAAqB;AACnC,WAAO,MAAM;AAAA,MAAK,EAAE,QAAQ,WAAW;AAAA,MAAG,MACxC,IAAI,MAAY,UAAU,EAAE,KAAK,IAAI;AAAA,IACvC;AAAA,EACF;AAQO,WAAS,gBACd,OACA,QACA,GACA,GACS;AACT,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,eAAS,IAAI,GAAG,IAAI,OAAO,CAAC,EAAE,QAAQ,KAAK;AACzC,YAAI,OAAO,CAAC,EAAE,CAAC,MAAM,EAAG;AACxB,cAAM,SAAS,IAAI;AACnB,cAAM,SAAS,IAAI;AACnB,YAAI,SAAS,KAAK,UAAU,cAAc,UAAU,WAAY,QAAO;AACvE,YAAI,UAAU,KAAK,MAAM,MAAM,EAAE,MAAM,MAAM,KAAM,QAAO;AAAA,MAC5D;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAGO,WAAS,WACd,OACA,QACA,GACA,GACA,OACO;AACP,UAAM,OAAO,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC;AACxC,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,eAAS,IAAI,GAAG,IAAI,OAAO,CAAC,EAAE,QAAQ,KAAK;AACzC,YAAI,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG;AACtB,gBAAM,SAAS,IAAI;AACnB,gBAAM,SAAS,IAAI;AACnB,cAAI,UAAU,KAAK,SAAS,YAAY;AACtC,iBAAK,MAAM,EAAE,MAAM,IAAI;AAAA,UACzB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAGO,WAAS,WAAW,OAAiD;AAC1E,UAAM,YAAY,MAAM,OAAO,CAAC,QAAQ,IAAI,KAAK,CAAC,SAAS,SAAS,IAAI,CAAC;AACzE,UAAM,UAAU,aAAa,UAAU;AACvC,UAAM,YAAY,MAAM;AAAA,MAAK,EAAE,QAAQ,QAAQ;AAAA,MAAG,MAChD,IAAI,MAAY,UAAU,EAAE,KAAK,IAAI;AAAA,IACvC;AACA,WAAO,EAAE,OAAO,CAAC,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ;AAAA,EACxD;AA1EA,MAMa,YACA;AAPb;AAAA;AAAA;AAMO,MAAM,aAAa;AACnB,MAAM,aAAa;AAAA;AAAA;;;ACyEnB,WAAS,SAAS,QAAwB;AAC/C,UAAM,OAAO,OAAO;AACpB,UAAM,OAAO,OAAO,CAAC,EAAE;AACvB,UAAM,SAAiB,CAAC;AACxB,aAAS,IAAI,GAAG,IAAI,MAAM,KAAK;AAC7B,aAAO,KAAK,CAAC,CAAC;AACd,eAAS,IAAI,OAAO,GAAG,KAAK,GAAG,KAAK;AAClC,eAAO,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,CAAC,CAAC;AAAA,MAC7B;AAAA,IACF;AACA,WAAO;AAAA,EACT;AA3FA,MAaa,aAiFA;AA9Fb;AAAA;AAAA;AAaO,MAAM,cAAoC;AAAA,QAC/C;AAAA,UACE,MAAM;AAAA,UACN,OAAO;AAAA,UACP,QAAQ;AAAA,YACN,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA,YACX,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA,YACX,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA,YACX,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA,UACb;AAAA,QACF;AAAA,QACA;AAAA,UACE,MAAM;AAAA,UACN,OAAO;AAAA,UACP,QAAQ;AAAA,YACN,CAAC,GAAG,CAAC;AAAA,YACL,CAAC,GAAG,CAAC;AAAA,UACP;AAAA,QACF;AAAA,QACA;AAAA,UACE,MAAM;AAAA,UACN,OAAO;AAAA,UACP,QAAQ;AAAA,YACN,CAAC,GAAG,GAAG,CAAC;AAAA,YACR,CAAC,GAAG,GAAG,CAAC;AAAA,YACR,CAAC,GAAG,GAAG,CAAC;AAAA,UACV;AAAA,QACF;AAAA,QACA;AAAA,UACE,MAAM;AAAA,UACN,OAAO;AAAA,UACP,QAAQ;AAAA,YACN,CAAC,GAAG,GAAG,CAAC;AAAA,YACR,CAAC,GAAG,GAAG,CAAC;AAAA,YACR,CAAC,GAAG,GAAG,CAAC;AAAA,UACV;AAAA,QACF;AAAA,QACA;AAAA,UACE,MAAM;AAAA,UACN,OAAO;AAAA,UACP,QAAQ;AAAA,YACN,CAAC,GAAG,GAAG,CAAC;AAAA,YACR,CAAC,GAAG,GAAG,CAAC;AAAA,YACR,CAAC,GAAG,GAAG,CAAC;AAAA,UACV;AAAA,QACF;AAAA,QACA;AAAA,UACE,MAAM;AAAA,UACN,OAAO;AAAA,UACP,QAAQ;AAAA,YACN,CAAC,GAAG,GAAG,CAAC;AAAA,YACR,CAAC,GAAG,GAAG,CAAC;AAAA,YACR,CAAC,GAAG,GAAG,CAAC;AAAA,UACV;AAAA,QACF;AAAA,QACA;AAAA,UACE,MAAM;AAAA,UACN,OAAO;AAAA,UACP,QAAQ;AAAA,YACN,CAAC,GAAG,GAAG,CAAC;AAAA,YACR,CAAC,GAAG,GAAG,CAAC;AAAA,YACR,CAAC,GAAG,GAAG,CAAC;AAAA,UACV;AAAA,QACF;AAAA,MACF;AAiBO,MAAM,WAAN,MAAe;AAAA,QAAf;AACL,eAAQ,MAAmB,CAAC;AAAA;AAAA,QAE5B,OAAkB;AAChB,cAAI,KAAK,IAAI,WAAW,GAAG;AACzB,iBAAK,MAAM,CAAC,GAAG,WAAW;AAE1B,qBAAS,IAAI,KAAK,IAAI,SAAS,GAAG,IAAI,GAAG,KAAK;AAC5C,oBAAM,IAAI,KAAK,MAAM,KAAK,OAAO,KAAK,IAAI,EAAE;AAC5C,eAAC,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,GAAI,KAAK,IAAI,CAAC,CAAE;AAAA,YAC1D;AAAA,UACF;AACA,iBAAO,KAAK,IAAI,IAAI;AAAA,QACtB;AAAA,MACF;AAAA;AAAA;;;ACjEA,WAAS,aAAa,OAAuB;AAC3C,WAAO,KAAK,IAAI,IAAI,OAAQ,QAAQ,KAAK,GAAG;AAAA,EAC9C;AAIA,WAAS,cAAc,QAAwB;AAC7C,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAI,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,MAAM,CAAC,EAAG,QAAO;AAAA,IAC7C;AACA,WAAO;AAAA,EACT;AAEA,WAAS,cAAc,QAA0C;AAC/D,UAAM,IAAI,KAAK,OAAO,aAAa,OAAO,CAAC,EAAE,UAAU,CAAC;AACxD,UAAM,IAAI,CAAC,cAAc,MAAM;AAC/B,WAAO,EAAE,GAAG,EAAE;AAAA,EAChB;AAIA,WAAS,gBAAwB;AAC/B,WAAO,SAAS,aAAa,QAAQ,MAAM,KAAK,KAAK,EAAE,KAAK;AAAA,EAC9D;AAEA,WAAS,cAAc,OAAqB;AAC1C,iBAAa,QAAQ,QAAQ,OAAO,KAAK,CAAC;AAAA,EAC5C;AAtEA,MAwCM,aAsBA,QAYO;AA1Eb;AAAA;AAAA;AAIA;AASA;AA2BA,MAAM,cAAc,CAAC,GAAG,KAAK,KAAK,KAAK,GAAG;AAsB1C,MAAM,SAAS;AAYR,MAAM,aAAN,MAAiB;AAAA,QAOtB,YAAY,UAAgD;AAL5D,eAAQ,MAAM,IAAI,SAAS;AAC3B,eAAQ,QAAuB;AAC/B,eAAQ,WAAW;AAIjB,eAAK,WAAW;AAChB,eAAK,QAAQ,KAAK,kBAAkB;AAAA,QACtC;AAAA;AAAA,QAIA,QAAc;AACZ,cAAI,KAAK,UAAU,KAAM,sBAAqB,KAAK,KAAK;AACxD,eAAK,MAAM,IAAI,SAAS;AACxB,eAAK,QAAQ,KAAK,kBAAkB;AACpC,eAAK,MAAM;AACX,eAAK,WAAW,YAAY,IAAI;AAChC,eAAK,QAAQ,sBAAsB,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;AAAA,QAC1D;AAAA,QAEA,WAAiB;AACf,eAAK,MAAM,EAAE;AAAA,QACf;AAAA,QACA,YAAkB;AAChB,eAAK,MAAM,CAAC;AAAA,QACd;AAAA,QAEA,SAAe;AACb,cAAI,CAAC,KAAK,OAAO,EAAG;AACpB,gBAAM,EAAE,QAAQ,GAAG,EAAE,IAAI,KAAK,MAAM;AACpC,gBAAM,UAAU,SAAS,MAAM;AAE/B,qBAAW,QAAQ,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG;AACpC,gBAAI,gBAAgB,KAAK,MAAM,OAAO,SAAS,IAAI,MAAM,CAAC,GAAG;AAC3D,mBAAK,MAAM,QAAS,SAAS;AAC7B,mBAAK,MAAM,QAAS,KAAK;AACzB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QAEA,WAAiB;AACf,cAAI,CAAC,KAAK,OAAO,EAAG;AACpB,gBAAM,EAAE,QAAQ,GAAG,EAAE,IAAI,KAAK,MAAM;AACpC,cAAI,gBAAgB,KAAK,MAAM,OAAO,QAAQ,GAAG,IAAI,CAAC,GAAG;AACvD,iBAAK,MAAM,QAAS;AACpB,iBAAK,MAAM,SAAS;AACpB,iBAAK,WAAW,YAAY,IAAI;AAAA,UAClC,OAAO;AACL,iBAAK,KAAK;AAAA,UACZ;AAAA,QACF;AAAA,QAEA,WAAiB;AACf,cAAI,CAAC,KAAK,OAAO,EAAG;AACpB,cAAI,UAAU;AACd,iBAAO,MAAM;AACX,kBAAM,EAAE,QAAQ,GAAG,EAAE,IAAI,KAAK,MAAM;AACpC,gBAAI,gBAAgB,KAAK,MAAM,OAAO,QAAQ,GAAG,IAAI,CAAC,GAAG;AACvD,mBAAK,MAAM,QAAS;AACpB;AAAA,YACF,OAAO;AACL;AAAA,YACF;AAAA,UACF;AACA,eAAK,MAAM,SAAS,UAAU;AAC9B,eAAK,KAAK;AAAA,QACZ;AAAA,QAEA,OAAa;AACX,cAAI,CAAC,KAAK,OAAO,KAAK,CAAC,KAAK,MAAM,QAAS;AAC3C,gBAAM,EAAE,SAAS,KAAK,IAAI,KAAK;AAC/B,gBAAM,YAAY,QAAS;AAC3B,gBAAM,OAAO,QAAQ,KAAK,IAAI,KAAK;AACnC,gBAAM,EAAE,GAAG,EAAE,IAAI,cAAc,KAAK,MAAM;AAC1C,eAAK,MAAM,UAAU,EAAE,WAAW,MAAM,QAAQ,KAAK,QAAQ,GAAG,EAAE;AAClE,eAAK,MAAM,OAAO;AAClB,eAAK,MAAM,UAAU;AAAA,QACvB;AAAA,QAEA,cAAoB;AAClB,cAAI,KAAK,MAAM,SAAU;AACzB,eAAK,MAAM,SAAS,CAAC,KAAK,MAAM;AAChC,cAAI,CAAC,KAAK,MAAM,OAAQ,MAAK,WAAW,YAAY,IAAI;AAAA,QAC1D;AAAA;AAAA,QAGA,SAAiB;AACf,cAAI,CAAC,KAAK,MAAM,QAAS,QAAO;AAChC,gBAAM,EAAE,QAAQ,GAAG,EAAE,IAAI,KAAK,MAAM;AACpC,cAAI,KAAK;AACT,iBAAO,gBAAgB,KAAK,MAAM,OAAO,QAAQ,GAAG,KAAK,CAAC,EAAG;AAC7D,iBAAO;AAAA,QACT;AAAA,QAEA,WAAgC;AAC9B,iBAAO,KAAK;AAAA,QACd;AAAA;AAAA,QAIQ,oBAA+B;AACrC,iBAAO;AAAA,YACL,OAAO,YAAY;AAAA,YACnB,SAAS;AAAA,YACT,MAAM,KAAK,IAAI,KAAK;AAAA,YACpB,MAAM;AAAA,YACN,SAAS;AAAA,YACT,OAAO;AAAA,YACP,WAAW,cAAc;AAAA,YACzB,OAAO;AAAA,YACP,OAAO;AAAA,YACP,UAAU;AAAA,YACV,QAAQ;AAAA,UACV;AAAA,QACF;AAAA,QAEQ,QAAc;AACpB,gBAAM,YAAY,KAAK,MAAM;AAC7B,gBAAM,EAAE,GAAG,EAAE,IAAI,cAAc,UAAU,MAAM;AAC/C,cAAI,CAAC,gBAAgB,KAAK,MAAM,OAAO,UAAU,QAAQ,GAAG,CAAC,GAAG;AAC9D,iBAAK,MAAM,WAAW;AACtB,gBAAI,KAAK,MAAM,QAAQ,KAAK,MAAM,WAAW;AAC3C,mBAAK,MAAM,YAAY,KAAK,MAAM;AAClC,4BAAc,KAAK,MAAM,KAAK;AAAA,YAChC;AACA;AAAA,UACF;AACA,eAAK,MAAM,UAAU,EAAE,WAAW,QAAQ,UAAU,QAAQ,GAAG,EAAE;AACjE,eAAK,MAAM,OAAO,KAAK,IAAI,KAAK;AAChC,eAAK,MAAM,UAAU;AAAA,QACvB;AAAA,QAEQ,KAAK,IAAkB;AAC7B,cAAI,KAAK,MAAM,UAAU;AACvB,iBAAK,SAAS,KAAK,KAAK;AACxB;AAAA,UACF;AACA,cAAI,CAAC,KAAK,MAAM,QAAQ;AACtB,gBAAI,KAAK,KAAK,YAAY,aAAa,KAAK,MAAM,KAAK,GAAG;AACxD,mBAAK,QAAQ;AACb,mBAAK,WAAW;AAAA,YAClB;AAAA,UACF;AACA,eAAK,SAAS,KAAK,KAAK;AACxB,eAAK,QAAQ,sBAAsB,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC;AAAA,QACxD;AAAA,QAEQ,UAAgB;AACtB,cAAI,CAAC,KAAK,MAAM,SAAS;AACvB,iBAAK,MAAM;AACX;AAAA,UACF;AACA,gBAAM,EAAE,QAAQ,GAAG,EAAE,IAAI,KAAK,MAAM;AACpC,cAAI,gBAAgB,KAAK,MAAM,OAAO,QAAQ,GAAG,IAAI,CAAC,GAAG;AACvD,iBAAK,MAAM,QAAQ;AAAA,UACrB,OAAO;AACL,iBAAK,KAAK;AAAA,UACZ;AAAA,QACF;AAAA,QAEQ,OAAa;AACnB,gBAAM,IAAI,KAAK,MAAM;AACrB,cAAI,CAAC,EAAG;AACR,gBAAM,UAAU,WAAW,KAAK,MAAM,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,KAAK;AAClF,gBAAM,EAAE,OAAO,QAAQ,IAAI,WAAW,OAAO;AAC7C,eAAK,MAAM,QAAQ;AACnB,cAAI,UAAU,GAAG;AACf,kBAAM,OAAO,YAAY,OAAO,KAAK,KAAK,KAAK,MAAM;AACrD,iBAAK,MAAM,SAAS;AACpB,iBAAK,MAAM,SAAS;AACpB,iBAAK,MAAM,QAAQ,KAAK,MAAM,KAAK,MAAM,QAAQ,EAAE,IAAI;AACvD,gBAAI,KAAK,MAAM,QAAQ,KAAK,MAAM,WAAW;AAC3C,mBAAK,MAAM,YAAY,KAAK,MAAM;AAClC,4BAAc,KAAK,MAAM,KAAK;AAAA,YAChC;AAAA,UACF;AACA,eAAK,MAAM,UAAU;AACrB,eAAK,MAAM;AAAA,QACb;AAAA,QAEQ,MAAM,IAAkB;AAC9B,cAAI,CAAC,KAAK,OAAO,EAAG;AACpB,gBAAM,EAAE,QAAQ,GAAG,EAAE,IAAI,KAAK,MAAM;AACpC,cAAI,gBAAgB,KAAK,MAAM,OAAO,QAAQ,IAAI,IAAI,CAAC,GAAG;AACxD,iBAAK,MAAM,QAAS,KAAK;AAAA,UAC3B;AAAA,QACF;AAAA,QAEQ,SAAkB;AACxB,iBAAO,CAAC,KAAK,MAAM,YAAY,CAAC,KAAK,MAAM,UAAU,KAAK,MAAM,YAAY;AAAA,QAC9E;AAAA,MACF;AAAA;AAAA;;;AClPA,WAAS,SAAS,KAAa,OAAuB;AACpD,UAAM,IAAI,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;AACtC,UAAM,IAAI,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;AACtC,UAAM,IAAI,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;AACtC,WAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK;AAAA,EACrC;AAhCA,MAQM,MAGA,GAyBO;AApCb;AAAA;AAAA;AAIA;AAIA,MAAM,OAAO;AAGb,MAAM,IAAI;AAAA,QACR,IAAa;AAAA,QACb,UAAa;AAAA,QACb,WAAa;AAAA,QACb,aAAa;AAAA,QACb,SAAa;AAAA,QACb,UAAa;AAAA,QACb,SAAa;AAAA,QACb,UAAa;AAAA,QACb,QAAa;AAAA,QACb,OAAa;AAAA,QACb,QAAa;AAAA,MACf;AAaO,MAAM,WAAN,MAAe;AAAA,QAQpB,YAAY,QAAgB,QAAgB,QAAgB;AAC1D,eAAK,UAAU,SAAS,eAAe,MAAM;AAC7C,eAAK,UAAU,SAAS,eAAe,MAAM;AAC7C,eAAK,UAAU,SAAS,eAAe,MAAM;AAC7C,eAAK,OAAO,KAAK,QAAQ,WAAW,IAAI;AACxC,eAAK,OAAO,KAAK,QAAQ,WAAW,IAAI;AACxC,eAAK,OAAO,KAAK,QAAQ,WAAW,IAAI;AAAA,QAC1C;AAAA,QAEA,OAAO,OAA4B,QAAsB;AACvD,eAAK,eAAe,OAAO,MAAM;AACjC,eAAK,eAAe,KAAK,MAAM,KAAK,SAAS,MAAM,IAAI;AACvD,eAAK,eAAe,KAAK,MAAM,KAAK,SAAS,MAAM,QAAQ,IAAI;AAAA,QACjE;AAAA;AAAA,QAIQ,eAAe,OAA4B,QAAsB;AACvE,gBAAM,MAAM,KAAK;AACjB,gBAAM,IAAI,aAAa;AACvB,gBAAM,IAAI,aAAa;AAGvB,cAAI,YAAY,EAAE;AAClB,cAAI,SAAS,GAAG,GAAG,GAAG,CAAC;AAEvB,eAAK,cAAc,KAAK,GAAG,CAAC;AAC5B,eAAK,gBAAgB,KAAK,MAAM,KAAK;AAErC,cAAI,MAAM,SAAS;AAEjB,gBAAI,CAAC,MAAM,QAAQ;AACjB,mBAAK,UAAU,KAAK,MAAM,QAAQ,QAAQ,MAAM,QAAQ,GAAG,MAAM;AAAA,YACnE;AAEA,iBAAK,eAAe,KAAK,MAAM,QAAQ,QAAQ,MAAM,QAAQ,GAAG,MAAM,QAAQ,GAAG,MAAM,QAAQ,UAAU,KAAK;AAAA,UAChH;AAGA,cAAI,MAAM,UAAU;AAClB,iBAAK,YAAY,KAAK,GAAG,GAAG,aAAa,EAAE,UAAU,oBAAoB;AAAA,UAC3E,WAAW,MAAM,QAAQ;AACvB,iBAAK,YAAY,KAAK,GAAG,GAAG,UAAU,EAAE,QAAQ,qBAAqB;AAAA,UACvE;AAAA,QACF;AAAA,QAEQ,cAAc,KAA+B,GAAW,GAAiB;AAC/E,cAAI,KAAK;AACT,cAAI,cAAc,EAAE;AACpB,cAAI,YAAY;AAChB,mBAAS,IAAI,GAAG,KAAK,YAAY,KAAK;AACpC,gBAAI,UAAU;AACd,gBAAI,OAAO,GAAG,IAAI,IAAI;AACtB,gBAAI,OAAO,GAAG,IAAI,IAAI;AACtB,gBAAI,OAAO;AAAA,UACb;AACA,mBAAS,IAAI,GAAG,KAAK,YAAY,KAAK;AACpC,gBAAI,UAAU;AACd,gBAAI,OAAO,IAAI,MAAM,CAAC;AACtB,gBAAI,OAAO,IAAI,MAAM,CAAC;AACtB,gBAAI,OAAO;AAAA,UACb;AACA,cAAI,QAAQ;AAAA,QACd;AAAA,QAEQ,gBAAgB,KAA+B,OAAoB;AACzE,mBAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACnC,qBAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACnC,oBAAM,QAAQ,MAAM,CAAC,EAAE,CAAC;AACxB,kBAAI,MAAO,MAAK,SAAS,KAAK,GAAG,GAAG,OAAO,IAAI;AAAA,YACjD;AAAA,UACF;AAAA,QACF;AAAA,QAEQ,eACN,KACA,QACA,GACA,GACA,OACM;AACN,mBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,qBAAS,IAAI,GAAG,IAAI,OAAO,CAAC,EAAE,QAAQ,KAAK;AACzC,kBAAI,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG;AACtB,sBAAM,KAAK,IAAI;AACf,sBAAM,KAAK,IAAI;AACf,oBAAI,MAAM,KAAK,KAAK,YAAY;AAC9B,uBAAK,SAAS,KAAK,IAAI,IAAI,OAAO,IAAI;AAAA,gBACxC;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QAEQ,UACN,KACA,QACA,GACA,IACM;AACN,cAAI,KAAK;AACT,mBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,qBAAS,IAAI,GAAG,IAAI,OAAO,CAAC,EAAE,QAAQ,KAAK;AACzC,kBAAI,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG;AACtB,sBAAM,KAAK,KAAK;AAChB,sBAAM,KAAK,IAAI;AACf,oBAAI,MAAM,KAAK,KAAK,YAAY;AAC9B,wBAAM,KAAK,KAAK,OAAO;AACvB,wBAAM,KAAK,KAAK,OAAO;AACvB,wBAAM,KAAK,OAAO;AAClB,sBAAI,YAAY,EAAE;AAClB,sBAAI,SAAS,IAAI,IAAI,IAAI,EAAE;AAC3B,sBAAI,cAAc,EAAE;AACpB,sBAAI,YAAY;AAChB,sBAAI,WAAW,IAAI,IAAI,IAAI,EAAE;AAAA,gBAC/B;AAAA,cACF;AAAA,YACF;AAAA,UACF;AACA,cAAI,QAAQ;AAAA,QACd;AAAA;AAAA;AAAA;AAAA;AAAA,QAMQ,SACN,KACA,KACA,KACA,OACA,QACM;AACN,gBAAM,IAAI,MAAM;AAChB,gBAAM,IAAI,MAAM;AAChB,gBAAM,MAAM;AACZ,gBAAM,KAAK,SAAS,MAAM;AAG1B,cAAI,YAAY;AAChB,cAAI,SAAS,IAAI,KAAK,IAAI,KAAK,IAAI,EAAE;AAGrC,cAAI,YAAY,EAAE;AAClB,cAAI,SAAS,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC;AACpC,cAAI,SAAS,IAAI,KAAK,IAAI,KAAK,GAAG,EAAE;AAGpC,cAAI,YAAY,EAAE;AAClB,cAAI,SAAS,IAAI,KAAK,IAAI,MAAM,KAAK,GAAG,IAAI,CAAC;AAC7C,cAAI,SAAS,IAAI,MAAM,KAAK,GAAG,IAAI,KAAK,GAAG,EAAE;AAG7C,cAAI,YAAY,SAAS,OAAO,GAAG;AACnC,cAAI,SAAS,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,KAAK,IAAI,CAAC;AAAA,QACnD;AAAA,QAEQ,YACN,KACA,GACA,GACA,OACA,YACA,UACM;AACN,cAAI,KAAK;AACT,cAAI,YAAY,EAAE;AAClB,cAAI,SAAS,GAAG,GAAG,GAAG,CAAC;AAEvB,cAAI,YAAY;AAChB,cAAI,OAAO;AACX,cAAI,YAAY;AAChB,cAAI,cAAc;AAClB,cAAI,aAAa;AACjB,cAAI,SAAS,OAAO,IAAI,GAAG,IAAI,IAAI,EAAE;AAErC,cAAI,OAAO;AACX,cAAI,YAAY,EAAE;AAClB,cAAI,aAAa;AACjB,cAAI,SAAS,UAAU,IAAI,GAAG,IAAI,IAAI,EAAE;AACxC,cAAI,QAAQ;AAAA,QACd;AAAA;AAAA,QAIQ,eACN,KACA,QACA,OACM;AACN,gBAAM,IAAI,OAAO;AACjB,gBAAM,IAAI,OAAO;AACjB,cAAI,YAAY,EAAE;AAClB,cAAI,SAAS,GAAG,GAAG,GAAG,CAAC;AAEvB,cAAI,CAAC,MAAO;AAEZ,gBAAM,EAAE,QAAQ,MAAM,IAAI;AAC1B,gBAAM,OAAO,OAAO,CAAC,EAAE;AACvB,gBAAM,OAAO,OAAO;AACpB,gBAAM,SAAS,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC,GAAG,KAAK,MAAM,IAAI,CAAC,CAAC;AAC5D,gBAAM,SAAS,KAAK,OAAO,IAAI,OAAO,UAAU,CAAC;AACjD,gBAAM,SAAS,KAAK,OAAO,IAAI,OAAO,UAAU,CAAC;AAEjD,cAAI,KAAK;AACT,cAAI,UAAU,QAAQ,MAAM;AAC5B,mBAAS,IAAI,GAAG,IAAI,MAAM,KAAK;AAC7B,qBAAS,IAAI,GAAG,IAAI,MAAM,KAAK;AAC7B,kBAAI,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG;AACtB,qBAAK,SAAS,KAAK,GAAG,GAAG,OAAO,MAAM;AAAA,cACxC;AAAA,YACF;AAAA,UACF;AACA,cAAI,QAAQ;AAAA,QACd;AAAA,MACF;AAAA;AAAA;;;ACnQA;AAAA;AAIA;AACA;AAIA,UAAM,MAAN,MAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QASR,YACmB,QACA,QAAQ,KACR,WAAW,IAC5B;AAHiB;AACA;AACA;AAXnB,eAAQ,UAAgD;AACxD,eAAQ,aAAoD;AAAA,QAWzD;AAAA,QAEH,QAAc;AACZ,eAAK,OAAO;AACZ,eAAK,OAAO;AACZ,eAAK,UAAU,WAAW,MAAM;AAC9B,iBAAK,aAAa,YAAY,KAAK,QAAQ,KAAK,QAAQ;AAAA,UAC1D,GAAG,KAAK,KAAK;AAAA,QACf;AAAA,QAEA,SAAe;AACb,cAAI,KAAK,YAAY,MAAM;AAAE,yBAAa,KAAK,OAAO;AAAI,iBAAK,UAAW;AAAA,UAAM;AAChF,cAAI,KAAK,eAAe,MAAM;AAAE,0BAAc,KAAK,UAAU;AAAG,iBAAK,aAAa;AAAA,UAAM;AAAA,QAC1F;AAAA,MACF;AAIA,UAAM,WAAW,IAAI,SAAS,cAAc,cAAc,YAAY;AAEtE,UAAI;AAGJ,UAAM,UAAW,IAAI,IAAI,MAAM,KAAK,SAAS,CAAC;AAC9C,UAAM,WAAW,IAAI,IAAI,MAAM,KAAK,UAAU,CAAC;AAC/C,UAAM,UAAW,IAAI,IAAI,MAAM,KAAK,SAAS,GAAG,GAAG,EAAE;AAErD,eAAS,SAAS,OAAkC;AAClD,QAAC,SAAS,eAAe,OAAO,EAAqB,cAAc,MAAM,MAAM,SAAS;AACxF,QAAC,SAAS,eAAe,WAAW,EAAkB,cAAc,MAAM,UAAU,SAAS;AAC7F,QAAC,SAAS,eAAe,OAAO,EAAqB,cAAc,MAAM,MAAM,SAAS;AACxF,QAAC,SAAS,eAAe,OAAO,EAAqB,cAAc,MAAM,MAAM,SAAS;AACxF,iBAAS,OAAO,OAAO,KAAK,OAAO,CAAC;AAAA,MACtC;AAEA,eAAS,YAAkB;AAEzB,gBAAQ,OAAO;AACf,iBAAS,OAAO;AAChB,gBAAQ,OAAO;AACf,eAAO,IAAI,WAAW,QAAQ;AAC9B,aAAK,MAAM;AAAA,MACb;AAIA,eAAS,iBAAiB,WAAW,CAAC,MAAqB;AACzD,YAAI,EAAE,OAAQ;AAEd,gBAAQ,EAAE,KAAK;AAAA,UACb,KAAK;AACH,cAAE,eAAe;AACjB,oBAAQ,MAAM;AACd;AAAA,UACF,KAAK;AACH,cAAE,eAAe;AACjB,qBAAS,MAAM;AACf;AAAA,UACF,KAAK;AACH,cAAE,eAAe;AACjB,oBAAQ,MAAM;AACd;AAAA,UACF,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AACH,cAAE,eAAe;AACjB,iBAAK,OAAO;AACZ;AAAA,UACF,KAAK;AACH,cAAE,eAAe;AACjB,iBAAK,SAAS;AACd;AAAA,UACF,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AACH,iBAAK,KAAK;AACV;AAAA,UACF,KAAK;AAAA,UACL,KAAK;AACH,iBAAK,YAAY;AACjB;AAAA,UACF,KAAK;AAAA,UACL,KAAK;AACH,sBAAU;AACV;AAAA,QACJ;AAAA,MACF,CAAC;AAED,eAAS,iBAAiB,SAAS,CAAC,MAAqB;AACvD,YAAI,EAAE,QAAQ,YAAc,SAAQ,OAAO;AAC3C,YAAI,EAAE,QAAQ,aAAc,UAAS,OAAO;AAC5C,YAAI,EAAE,QAAQ,YAAc,SAAQ,OAAO;AAAA,MAC7C,CAAC;AAID,gBAAU;AAAA;AAAA;", + "names": [] +} diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,608 @@ +"use strict"; +// ─── Types ──────────────────────────────────────────────────────────────────── +// ─── Constants ──────────────────────────────────────────────────────────────── +const BOARD_COLS = 10; +const BOARD_ROWS = 20; +const BLOCK_SIZE = 30; +const NEXT_BLOCK_SIZE = 25; +/** How many lines to clear per level-up */ +const LINES_PER_LEVEL = 10; +/** Score awarded for clearing 1/2/3/4 lines at once (multiplied by level) */ +const LINE_SCORES = [0, 100, 300, 500, 800]; +/** Drop interval in ms at each level (index 0 = level 1) */ +function dropInterval(level) { + return Math.max(80, 1000 - (level - 1) * 90); +} +// ─── Tetromino shapes & colours ─────────────────────────────────────────────── +const TETROMINOES = { + I: { shape: [[1, 1, 1, 1]], color: '#00F0F0' }, + O: { shape: [[1, 1], [1, 1]], color: '#F0F000' }, + T: { shape: [[0, 1, 0], [1, 1, 1]], color: '#A000F0' }, + S: { shape: [[0, 1, 1], [1, 1, 0]], color: '#00F000' }, + Z: { shape: [[1, 1, 0], [0, 1, 1]], color: '#F00000' }, + J: { shape: [[1, 0, 0], [1, 1, 1]], color: '#0000F0' }, + L: { shape: [[0, 0, 1], [1, 1, 1]], color: '#F0A000' }, +}; +const PIECE_TYPES = Object.keys(TETROMINOES); +// ─── Helpers ────────────────────────────────────────────────────────────────── +/** Rotate a 2-D matrix 90 degrees clockwise */ +function rotateMatrix(shape) { + const rows = shape.length; + const cols = shape[0].length; + const result = Array.from({ length: cols }, () => Array(rows).fill(0)); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + result[c][rows - 1 - r] = shape[r][c]; + } + } + return result; +} +function cloneShape(shape) { + return shape.map(row => [...row]); +} +function emptyBoard() { + return Array.from({ length: BOARD_ROWS }, () => Array(BOARD_COLS).fill(null)); +} +function randomPieceType() { + return PIECE_TYPES[Math.floor(Math.random() * PIECE_TYPES.length)]; +} +// ─── Bag randomiser (7-bag) ─────────────────────────────────────────────────── +class Bag { + constructor() { + this.queue = []; + } + refill() { + const bag = [...PIECE_TYPES]; + for (let i = bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [bag[i], bag[j]] = [bag[j], bag[i]]; + } + this.queue.push(...bag); + } + next() { + if (this.queue.length < 2) + this.refill(); + return this.queue.shift(); + } + peek() { + if (this.queue.length === 0) + this.refill(); + return this.queue[0]; + } +} +// ─── Main game class ────────────────────────────────────────────────────────── +class Tetris { + constructor() { + // Game state + this.board = emptyBoard(); + this.current = null; + this.held = null; + this.canHold = true; + this.bag = new Bag(); + this.score = 0; + this.highScore = 0; + this.level = 1; + this.lines = 0; + this.isGameOver = false; + this.isPaused = false; + // Animation + this.rafId = 0; + this.lastTime = 0; + this.dropAccum = 0; + // Line-clear flash animation + this.flashRows = []; + this.flashTimer = 0; + this.FLASH_DURATION = 180; // ms + // Lock-delay + this.lockTimer = 0; + this.LOCK_DELAY = 500; // ms — standard guideline + // ─── Rotation (SRS wall-kicks) ──────────────────────────────────────────── + this.WALL_KICKS = [0, -1, 1, -2, 2, 3, -3]; + // ─── Game loop ─────────────────────────────────────────────────────────────── + this.loop = (timestamp) => { + const delta = timestamp - this.lastTime; + this.lastTime = timestamp; + if (!this.isPaused && !this.isGameOver) { + // Flash animation for cleared rows + if (this.flashTimer > 0) { + this.flashTimer -= delta; + if (this.flashTimer <= 0) { + this.flashTimer = 0; + this.clearFullRows(); + } + } + else if (this.current) { + // Gravity + this.dropAccum += delta; + const interval = dropInterval(this.level); + if (this.dropAccum >= interval) { + this.dropAccum -= interval; + if (this.validPosition(this.current, 0, 1)) { + this.current.y++; + this.lockTimer = 0; + } + else { + // Lock delay + this.lockTimer += delta; + if (this.lockTimer >= this.LOCK_DELAY) { + this.lock(); + } + } + } + else if (!this.validPosition(this.current, 0, 1)) { + // Already grounded — accumulate lock delay + this.lockTimer += delta; + if (this.lockTimer >= this.LOCK_DELAY) { + this.lock(); + } + } + else { + this.lockTimer = 0; + } + } + } + this.drawBoard(); + this.drawOverlays(); + this.rafId = requestAnimationFrame(this.loop); + }; + this.canvas = document.getElementById('game-canvas'); + this.ctx = this.canvas.getContext('2d'); + this.nextCanvas = document.getElementById('next-canvas'); + this.nextCtx = this.nextCanvas.getContext('2d'); + this.elScore = document.getElementById('score'); + this.elHighScore = document.getElementById('high-score'); + this.elLevel = document.getElementById('level'); + this.elLines = document.getElementById('lines'); + this.elStatus = document.getElementById('status-msg'); + this.canvas.width = BOARD_COLS * BLOCK_SIZE; + this.canvas.height = BOARD_ROWS * BLOCK_SIZE; + this.nextCanvas.width = 4 * NEXT_BLOCK_SIZE + 10; + this.nextCanvas.height = 4 * NEXT_BLOCK_SIZE + 10; + document.addEventListener('keydown', this.handleKey.bind(this)); + document.getElementById('btn-start').addEventListener('click', () => this.restart()); + document.getElementById('btn-pause').addEventListener('click', () => this.togglePause()); + this.drawIdleScreen(); + } + // ─── Piece creation ───────────────────────────────────────────────────────── + makePiece(type) { + const def = TETROMINOES[type]; + const shape = cloneShape(def.shape); + const x = Math.floor((BOARD_COLS - shape[0].length) / 2); + return { type, shape, x, y: 0, color: def.color }; + } + spawn() { + const type = this.bag.next(); + this.current = this.makePiece(type); + // Peek next for preview + this.drawNextPreview(this.bag.peek()); + if (!this.validPosition(this.current)) { + this.current = null; + this.triggerGameOver(); + } + } + // ─── Collision / validity ──────────────────────────────────────────────────── + validPosition(piece, dx = 0, dy = 0, shape = piece.shape) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = piece.x + c + dx; + const ny = piece.y + r + dy; + if (nx < 0 || nx >= BOARD_COLS || ny >= BOARD_ROWS) + return false; + if (ny < 0) + continue; + if (this.board[ny][nx]) + return false; + } + } + return true; + } + rotate(cw) { + if (!this.current) + return; + let rotated = cloneShape(this.current.shape); + if (cw) { + rotated = rotateMatrix(rotated); + } + else { + rotated = rotateMatrix(rotateMatrix(rotateMatrix(rotated))); + } + for (const kick of this.WALL_KICKS) { + if (this.validPosition(this.current, kick, 0, rotated)) { + this.current.shape = rotated; + this.current.x += kick; + this.lockTimer = 0; // reset lock on successful rotate + return; + } + } + } + // ─── Movement ──────────────────────────────────────────────────────────────── + moveH(dx) { + if (!this.current || !this.validPosition(this.current, dx, 0)) + return; + this.current.x += dx; + if (!this.validPosition(this.current, 0, 1)) + this.lockTimer = 0; + } + softDrop() { + if (!this.current) + return; + if (this.validPosition(this.current, 0, 1)) { + this.current.y++; + this.score += 1; + this.dropAccum = 0; + this.updateHUD(); + } + } + hardDrop() { + if (!this.current) + return; + let dropped = 0; + while (this.validPosition(this.current, 0, 1)) { + this.current.y++; + dropped++; + } + this.score += dropped * 2; + this.lock(); + this.updateHUD(); + } + // ─── Hold ──────────────────────────────────────────────────────────────────── + hold() { + if (!this.current || !this.canHold) + return; + if (this.held) { + const prev = this.held; + this.held = this.makePiece(this.current.type); + this.current = this.makePiece(prev.type); + } + else { + this.held = this.makePiece(this.current.type); + this.current = null; + this.spawn(); + } + this.canHold = false; + this.drawHeld(); + } + // ─── Locking & line clearing ───────────────────────────────────────────────── + lock() { + if (!this.current) + return; + // Place blocks on board + for (let r = 0; r < this.current.shape.length; r++) { + for (let c = 0; c < this.current.shape[r].length; c++) { + if (!this.current.shape[r][c]) + continue; + const bx = this.current.x + c; + const by = this.current.y + r; + if (by < 0) { + this.triggerGameOver(); + return; + } + this.board[by][bx] = this.current.color; + } + } + this.current = null; + this.lockTimer = 0; + this.dropAccum = 0; + // Find full rows + const full = []; + for (let r = 0; r < BOARD_ROWS; r++) { + if (this.board[r].every(c => c !== null)) + full.push(r); + } + if (full.length > 0) { + this.flashRows = full; + this.flashTimer = this.FLASH_DURATION; + } + else { + this.canHold = true; + this.spawn(); + } + } + clearFullRows() { + var _a; + const rows = this.flashRows.slice(); + this.flashRows = []; + for (const r of rows) { + this.board.splice(r, 1); + this.board.unshift(Array(BOARD_COLS).fill(null)); + } + const cleared = rows.length; + this.lines += cleared; + const newLevel = Math.floor(this.lines / LINES_PER_LEVEL) + 1; + if (newLevel > this.level) + this.level = newLevel; + this.score += ((_a = LINE_SCORES[cleared]) !== null && _a !== void 0 ? _a : 1200) * this.level; + if (this.score > this.highScore) + this.highScore = this.score; + this.updateHUD(); + this.canHold = true; + this.spawn(); + } + // ─── Ghost piece ───────────────────────────────────────────────────────────── + ghostY() { + if (!this.current) + return 0; + let gy = this.current.y; + while (this.validPosition(this.current, 0, gy - this.current.y + 1)) + gy++; + return gy; + } + // ─── Rendering ─────────────────────────────────────────────────────────────── + drawBlock(ctx, x, y, color, size, alpha = 1) { + ctx.globalAlpha = alpha; + const px = x * size; + const py = y * size; + // Main fill + ctx.fillStyle = color; + ctx.fillRect(px + 1, py + 1, size - 2, size - 2); + // Top/left highlight + ctx.fillStyle = 'rgba(255,255,255,0.35)'; + ctx.fillRect(px + 1, py + 1, size - 2, 5); + ctx.fillRect(px + 1, py + 1, 5, size - 2); + // Bottom/right shadow + ctx.fillStyle = 'rgba(0,0,0,0.30)'; + ctx.fillRect(px + 1, py + size - 6, size - 2, 5); + ctx.fillRect(px + size - 6, py + 1, 5, size - 2); + ctx.globalAlpha = 1; + } + drawGhostBlock(ctx, x, y, color, size) { + const px = x * size; + const py = y * size; + ctx.globalAlpha = 0.28; + ctx.strokeStyle = color; + ctx.lineWidth = 2; + ctx.strokeRect(px + 2, py + 2, size - 4, size - 4); + ctx.globalAlpha = 1; + } + drawBoard() { + const { ctx, canvas } = this; + // Background + ctx.fillStyle = '#111827'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + // Subtle grid + ctx.strokeStyle = 'rgba(255,255,255,0.04)'; + ctx.lineWidth = 0.5; + for (let c = 0; c <= BOARD_COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK_SIZE, 0); + ctx.lineTo(c * BLOCK_SIZE, canvas.height); + ctx.stroke(); + } + for (let r = 0; r <= BOARD_ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK_SIZE); + ctx.lineTo(canvas.width, r * BLOCK_SIZE); + ctx.stroke(); + } + // Placed blocks + for (let r = 0; r < BOARD_ROWS; r++) { + for (let c = 0; c < BOARD_COLS; c++) { + if (this.board[r][c]) { + // Flash animation for full rows + if (this.flashRows.includes(r)) { + const alpha = 0.5 + 0.5 * Math.sin((this.flashTimer / this.FLASH_DURATION) * Math.PI * 4); + this.drawBlock(ctx, c, r, '#FFFFFF', BLOCK_SIZE, alpha); + } + else { + this.drawBlock(ctx, c, r, this.board[r][c], BLOCK_SIZE); + } + } + } + } + // Ghost piece + if (this.current && this.flashRows.length === 0) { + const gy = this.ghostY(); + for (let r = 0; r < this.current.shape.length; r++) { + for (let c = 0; c < this.current.shape[r].length; c++) { + if (!this.current.shape[r][c]) + continue; + const gRow = gy + r; + if (gRow >= 0 && gRow !== this.current.y + r) { + this.drawGhostBlock(ctx, this.current.x + c, gRow, this.current.color, BLOCK_SIZE); + } + } + } + } + // Active piece + if (this.current) { + for (let r = 0; r < this.current.shape.length; r++) { + for (let c = 0; c < this.current.shape[r].length; c++) { + if (!this.current.shape[r][c]) + continue; + const by = this.current.y + r; + if (by >= 0) { + this.drawBlock(ctx, this.current.x + c, by, this.current.color, BLOCK_SIZE); + } + } + } + } + } + drawNextPreview(type) { + const ctx = this.nextCtx; + const size = NEXT_BLOCK_SIZE; + const w = this.nextCanvas.width; + const h = this.nextCanvas.height; + ctx.fillStyle = '#111827'; + ctx.fillRect(0, 0, w, h); + const def = TETROMINOES[type]; + const shape = def.shape; + const cols = shape[0].length; + const rows = shape.length; + const offsetX = Math.floor((w / size - cols) / 2); + const offsetY = Math.floor((h / size - rows) / 2); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (shape[r][c]) { + this.drawBlock(ctx, offsetX + c, offsetY + r, def.color, size); + } + } + } + } + drawHeld() { + const canvas = document.getElementById('hold-canvas'); + const ctx = canvas.getContext('2d'); + const size = NEXT_BLOCK_SIZE; + ctx.fillStyle = '#111827'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + if (!this.held) + return; + const shape = this.held.shape; + const cols = shape[0].length; + const rows = shape.length; + const offsetX = Math.floor((canvas.width / size - cols) / 2); + const offsetY = Math.floor((canvas.height / size - rows) / 2); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (shape[r][c]) { + this.drawBlock(ctx, offsetX + c, offsetY + r, this.held.color, size, this.canHold ? 1 : 0.4); + } + } + } + } + drawIdleScreen() { + const { ctx, canvas } = this; + ctx.fillStyle = '#111827'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.textAlign = 'center'; + ctx.fillStyle = '#A78BFA'; + ctx.font = `bold ${BLOCK_SIZE * 1.2}px "Courier New", monospace`; + ctx.fillText('TETRIS', canvas.width / 2, canvas.height / 2 - 30); + ctx.fillStyle = '#9CA3AF'; + ctx.font = `${BLOCK_SIZE * 0.55}px "Courier New", monospace`; + ctx.fillText('Press Start', canvas.width / 2, canvas.height / 2 + 15); + } + drawOverlays() { + const { ctx, canvas } = this; + if (this.isGameOver) { + ctx.fillStyle = 'rgba(0,0,0,0.72)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.textAlign = 'center'; + ctx.fillStyle = '#F87171'; + ctx.font = `bold ${BLOCK_SIZE * 1.1}px "Courier New", monospace`; + ctx.fillText('GAME OVER', canvas.width / 2, canvas.height / 2 - 28); + ctx.fillStyle = '#FCD34D'; + ctx.font = `${BLOCK_SIZE * 0.55}px "Courier New", monospace`; + ctx.fillText(`Score: ${this.score}`, canvas.width / 2, canvas.height / 2 + 12); + ctx.fillStyle = '#9CA3AF'; + ctx.font = `${BLOCK_SIZE * 0.5}px "Courier New", monospace`; + ctx.fillText('Press R or Start', canvas.width / 2, canvas.height / 2 + 44); + return; + } + if (this.isPaused) { + ctx.fillStyle = 'rgba(0,0,0,0.65)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.textAlign = 'center'; + ctx.fillStyle = '#FCD34D'; + ctx.font = `bold ${BLOCK_SIZE * 1.1}px "Courier New", monospace`; + ctx.fillText('PAUSED', canvas.width / 2, canvas.height / 2); + } + } + // ─── HUD ───────────────────────────────────────────────────────────────────── + updateHUD() { + this.elScore.textContent = this.score.toLocaleString(); + this.elHighScore.textContent = this.highScore.toLocaleString(); + this.elLevel.textContent = this.level.toString(); + this.elLines.textContent = this.lines.toString(); + } + // ─── Input ─────────────────────────────────────────────────────────────────── + handleKey(e) { + if (this.isGameOver) { + if (e.key === 'r' || e.key === 'R' || e.key === 'Enter') + this.restart(); + return; + } + if (e.key === 'p' || e.key === 'P' || e.key === 'Escape') { + this.togglePause(); + return; + } + if (this.isPaused) + return; + switch (e.key) { + case 'ArrowLeft': + e.preventDefault(); + this.moveH(-1); + break; + case 'ArrowRight': + e.preventDefault(); + this.moveH(1); + break; + case 'ArrowDown': + e.preventDefault(); + this.softDrop(); + break; + case 'ArrowUp': + case 'x': + case 'X': + e.preventDefault(); + this.rotate(true); + break; + case 'z': + case 'Z': + e.preventDefault(); + this.rotate(false); + break; + case ' ': + e.preventDefault(); + this.hardDrop(); + break; + case 'c': + case 'C': + case 'Shift': + e.preventDefault(); + this.hold(); + break; + case 'r': + case 'R': + this.restart(); + break; + } + } + // ─── Lifecycle ─────────────────────────────────────────────────────────────── + triggerGameOver() { + this.isGameOver = true; + this.elStatus.textContent = 'GAME OVER'; + if (this.score > this.highScore) + this.highScore = this.score; + this.updateHUD(); + } + togglePause() { + if (this.isGameOver) + return; + this.isPaused = !this.isPaused; + this.elStatus.textContent = this.isPaused ? 'PAUSED' : 'PLAYING'; + if (!this.isPaused) + this.lastTime = performance.now(); + } + restart() { + cancelAnimationFrame(this.rafId); + this.board = emptyBoard(); + this.current = null; + this.held = null; + this.canHold = true; + this.bag = new Bag(); + this.score = 0; + this.level = 1; + this.lines = 0; + this.isGameOver = false; + this.isPaused = false; + this.dropAccum = 0; + this.lockTimer = 0; + this.flashRows = []; + this.flashTimer = 0; + this.lastTime = performance.now(); + this.elStatus.textContent = 'PLAYING'; + this.updateHUD(); + // Draw empty hold canvas + const holdCanvas = document.getElementById('hold-canvas'); + holdCanvas.getContext('2d').fillStyle = '#111827'; + holdCanvas.getContext('2d').fillRect(0, 0, holdCanvas.width, holdCanvas.height); + this.spawn(); + this.rafId = requestAnimationFrame(this.loop); + } +} +// ─── Entry point ────────────────────────────────────────────────────────────── +window.addEventListener('DOMContentLoaded', () => { + new Tetris(); +}); diff --git a/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=high_human_language=es_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,564 @@ +"use strict"; +// ============================================================ +// TETRIS — TypeScript / Canvas implementation +// ============================================================ +// ── Constants ────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const CELL = 30; // board cell size (px) +const PREVIEW_CS = 25; // preview cell size (px) +const LOCK_DELAY = 500; // ms before a grounded piece locks +// Points awarded per simultaneous line clear × current level +const LINE_SCORE = [0, 100, 300, 500, 800]; +const PIECES = { + I: { shape: [[1, 1, 1, 1]], color: '#00d8d8' }, + O: { shape: [[1, 1], [1, 1]], color: '#d8d800' }, + T: { shape: [[0, 1, 0], [1, 1, 1]], color: '#a000d0' }, + S: { shape: [[0, 1, 1], [1, 1, 0]], color: '#00c800' }, + Z: { shape: [[1, 1, 0], [0, 1, 1]], color: '#d80000' }, + J: { shape: [[1, 0, 0], [1, 1, 1]], color: '#0040d8' }, + L: { shape: [[0, 0, 1], [1, 1, 1]], color: '#d87800' }, +}; +// ── Pure rotation helpers ────────────────────────────────── +function rotCW(s) { + const R = s.length, C = s[0].length; + return Array.from({ length: C }, (_, c) => Array.from({ length: R }, (_, r) => s[R - 1 - r][c])); +} +function rotCCW(s) { + const R = s.length, C = s[0].length; + return Array.from({ length: C }, (_, c) => Array.from({ length: R }, (_, r) => s[r][C - 1 - c])); +} +// ── Game class ───────────────────────────────────────────── +class Tetris { + // ── Bootstrap ──────────────────────────────────────────── + constructor() { + var _a; + this.held = null; + this.canHold = true; + // stats + this.score = 0; + this.level = 1; + this.lines = 0; + this.best = 0; + // flags + this.over = false; + this.paused = false; + // timers + this.dropT = 0; + this.lockT = 0; + this.onGnd = false; + this.lastTs = 0; + this.rafId = 0; + // 7-bag randomiser + this.bag = []; + // DAS / ARR (Delayed Auto Shift / Auto Repeat Rate) — ms + this.DAS = 160; + this.ARR = 40; + this.dasMap = new Map(); + this.arrMap = new Map(); + // line-clear flash state + this.flashRows = []; + this.flashTimer = 0; + this.FLASH_DURATION = 120; // ms + this.bCanvas = document.getElementById('board'); + this.bCtx = this.bCanvas.getContext('2d'); + this.nCanvas = document.getElementById('next-canvas'); + this.nCtx = this.nCanvas.getContext('2d'); + this.hCanvas = document.getElementById('hold-canvas'); + this.hCtx = this.hCanvas.getContext('2d'); + this.bCanvas.width = COLS * CELL; + this.bCanvas.height = ROWS * CELL; + this.nCanvas.width = this.hCanvas.width = 4 * PREVIEW_CS; + this.nCanvas.height = this.hCanvas.height = 4 * PREVIEW_CS; + this.best = +((_a = localStorage.getItem('tet-best')) !== null && _a !== void 0 ? _a : 0); + this.el('best').textContent = this.best.toLocaleString(); + this.bindInput(); + this.newGame(); + } + // ── Utility ────────────────────────────────────────────── + el(id) { + return document.getElementById(id); + } + // ── Game lifecycle ──────────────────────────────────────── + newGame() { + cancelAnimationFrame(this.rafId); + this.grid = Array.from({ length: ROWS }, () => new Array(COLS).fill(null)); + this.held = null; + this.canHold = true; + this.score = 0; + this.lines = 0; + this.level = 1; + this.dropT = 0; + this.lockT = 0; + this.onGnd = false; + this.over = false; + this.paused = false; + this.lastTs = 0; + this.bag = []; + this.flashRows = []; + this.flashTimer = 0; + this.nxt = this.makePiece(); + this.spawn(); + this.refreshStats(); + this.rafId = requestAnimationFrame(ts => this.tick(ts)); + } + // ── 7-bag piece factory ─────────────────────────────────── + bagPop() { + if (!this.bag.length) { + this.bag = Object.keys(PIECES); + for (let i = this.bag.length - 1; i > 0; i--) { + const j = (Math.random() * (i + 1)) | 0; + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop(); + } + makePiece() { + const type = this.bagPop(); + const def = PIECES[type]; + const shape = def.shape.map(r => [...r]); + return { + type, shape, color: def.color, + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + }; + } + spawn() { + this.cur = this.nxt; + this.nxt = this.makePiece(); + // reset to spawn position + this.cur.x = Math.floor((COLS - this.cur.shape[0].length) / 2); + this.cur.y = 0; + this.dropT = 0; + this.lockT = 0; + this.onGnd = false; + this.canHold = true; + if (!this.fits(this.cur, 0, 0)) { + this.over = true; + this.saveBest(); + } + } + saveBest() { + if (this.score > this.best) { + this.best = this.score; + localStorage.setItem('tet-best', String(this.best)); + this.el('best').textContent = this.best.toLocaleString(); + } + } + // ── Collision detection ─────────────────────────────────── + fits(p, dx, dy, sh = p.shape) { + for (let r = 0; r < sh.length; r++) { + for (let c = 0; c < sh[r].length; c++) { + if (!sh[r][c]) + continue; + const nx = p.x + c + dx; + const ny = p.y + r + dy; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return false; + if (ny >= 0 && this.grid[ny][nx]) + return false; + } + } + return true; + } + // ── Piece actions ───────────────────────────────────────── + moveL() { + if (this.fits(this.cur, -1, 0)) { + this.cur.x--; + this.onMove(); + } + } + moveR() { + if (this.fits(this.cur, 1, 0)) { + this.cur.x++; + this.onMove(); + } + } + softD() { + if (this.fits(this.cur, 0, 1)) { + this.cur.y++; + this.score++; + this.dropT = 0; + this.lockT = 0; + this.onGnd = false; + this.refreshStats(); + } + } + hardD() { + let n = 0; + while (this.fits(this.cur, 0, 1)) { + this.cur.y++; + n++; + } + this.score += n * 2; + this.refreshStats(); + this.lockImmediate(); + } + rotate(dir) { + const ns = dir === 1 ? rotCW(this.cur.shape) : rotCCW(this.cur.shape); + // Wall-kick candidates: horizontal offsets [0, ±1, ±2] + for (const kick of [0, 1, -1, 2, -2]) { + if (this.fits(this.cur, kick, 0, ns)) { + this.cur.shape = ns; + this.cur.x += kick; + this.onMove(); + return; + } + } + } + holdF() { + if (!this.canHold) + return; + this.canHold = false; + const prev = this.held; + // Store current piece (reset rotation) + this.held = { + type: this.cur.type, + shape: PIECES[this.cur.type].shape.map(r => [...r]), + color: this.cur.color, + x: 0, y: 0, + }; + if (prev) { + // Swap in the previously held piece + this.cur = Object.assign(Object.assign({}, prev), { x: Math.floor((COLS - prev.shape[0].length) / 2), y: 0 }); + this.dropT = this.lockT = 0; + this.onGnd = false; + if (!this.fits(this.cur, 0, 0)) { + this.over = true; + this.saveBest(); + } + } + else { + this.spawn(); + } + } + /** Called on any movement/rotation to reset the lock-delay. */ + onMove() { + if (this.onGnd) + this.lockT = 0; + } + // ── Locking ─────────────────────────────────────────────── + lockImmediate() { + this.lockT = LOCK_DELAY; // force lock on next tick + } + lock() { + // Write piece cells into the grid + for (let r = 0; r < this.cur.shape.length; r++) { + for (let c = 0; c < this.cur.shape[r].length; c++) { + if (!this.cur.shape[r][c]) + continue; + const y = this.cur.y + r; + const x = this.cur.x + c; + if (y < 0) { + this.over = true; + this.saveBest(); + return; + } + this.grid[y][x] = this.cur.color; + } + } + this.sweep(); + if (!this.over) + this.spawn(); + } + // ── Line clearing with flash ────────────────────────────── + sweep() { + const full = []; + for (let r = 0; r < ROWS; r++) { + if (this.grid[r].every(c => c !== null)) + full.push(r); + } + if (!full.length) + return; + this.flashRows = full; + this.flashTimer = 0; + // Immediately update score / level so the UI reflects it + this.lines += full.length; + this.score += LINE_SCORE[full.length] * this.level; + this.level = Math.floor(this.lines / 10) + 1; + this.refreshStats(); + } + /** Remove the flashed rows from the grid. */ + commitSweep() { + for (let r = ROWS - 1; r >= 0; r--) { + if (this.flashRows.includes(r)) { + this.grid.splice(r, 1); + this.grid.unshift(new Array(COLS).fill(null)); + } + } + this.flashRows = []; + this.flashTimer = 0; + this.spawn(); + } + // ── Ghost piece ─────────────────────────────────────────── + ghostY() { + let dy = 0; + while (this.fits(this.cur, 0, dy + 1)) + dy++; + return this.cur.y + dy; + } + // ── Drop-interval (speed) ───────────────────────────────── + dropInterval() { + return Math.max(50, Math.floor(1000 * Math.pow(0.85, this.level - 1))); + } + // ── Main game loop ──────────────────────────────────────── + tick(ts) { + // Cap dt to 200 ms to avoid huge jumps after tab switches + const dt = Math.min(this.lastTs > 0 ? ts - this.lastTs : 0, 200); + this.lastTs = ts; + if (!this.paused && !this.over) { + // Flash animation while clearing lines + if (this.flashRows.length > 0) { + this.flashTimer += dt; + if (this.flashTimer >= this.FLASH_DURATION) { + this.commitSweep(); + } + } + else { + // Normal drop + this.dropT += dt; + const iv = this.dropInterval(); + while (this.dropT >= iv) { + this.dropT -= iv; + if (this.fits(this.cur, 0, 1)) { + this.cur.y++; + this.onGnd = false; + this.lockT = 0; + } + else { + this.onGnd = true; + } + } + // Lock delay + if (this.onGnd) { + this.lockT += dt; + if (this.lockT >= LOCK_DELAY) { + this.lockT = 0; + this.lock(); + } + } + } + } + this.draw(ts); + this.rafId = requestAnimationFrame(ts2 => this.tick(ts2)); + } + // ── Rendering ───────────────────────────────────────────── + /** Draw a single cell at grid position (col, row) with bevel shading. */ + drawCell(ctx, col, row, color, cs = CELL, alpha = 1.0) { + const x = col * cs, y = row * cs; + const p = 1; + const bevel = Math.max(3, (cs * 0.13) | 0); + ctx.save(); + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x + p, y + p, cs - p * 2, cs - p * 2); + // top-left highlight + ctx.fillStyle = 'rgba(255,255,255,0.30)'; + ctx.fillRect(x + p, y + p, cs - p * 2, bevel); + ctx.fillRect(x + p, y + p, bevel, cs - p * 2); + // bottom-right shadow + ctx.fillStyle = 'rgba(0,0,0,0.35)'; + ctx.fillRect(x + p, y + cs - p - bevel, cs - p * 2, bevel); + ctx.fillRect(x + cs - p - bevel, y + p, bevel, cs - p * 2); + ctx.restore(); + } + /** Draw every cell in a shape at grid origin (ox, oy). */ + drawShape(ctx, shape, color, ox, oy, cs = CELL, alpha = 1.0) { + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c]) + this.drawCell(ctx, ox + c, oy + r, color, cs, alpha); + } + draw(ts) { + const ctx = this.bCtx; + const W = this.bCanvas.width; + const H = this.bCanvas.height; + // ── board background ── + ctx.fillStyle = '#0c0c20'; + ctx.fillRect(0, 0, W, H); + // ── subtle grid lines ── + ctx.strokeStyle = '#1a1a40'; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(W, r * CELL); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, H); + ctx.stroke(); + } + // ── locked cells ── + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const cell = this.grid[r][c]; + if (!cell) + continue; + // flash effect on clearing rows + if (this.flashRows.includes(r)) { + const t = this.flashTimer / this.FLASH_DURATION; // 0..1 + const wb = Math.sin(t * Math.PI); // 0→1→0 + // blend towards white + ctx.save(); + this.drawCell(ctx, c, r, cell); + ctx.globalAlpha = wb * 0.75; + ctx.fillStyle = '#ffffff'; + ctx.fillRect(c * CELL + 1, r * CELL + 1, CELL - 2, CELL - 2); + ctx.restore(); + } + else { + this.drawCell(ctx, c, r, cell); + } + } + } + // ── ghost piece ── + if (!this.over && !this.flashRows.length) { + const gy = this.ghostY(); + if (gy > this.cur.y) { + this.drawShape(ctx, this.cur.shape, this.cur.color, this.cur.x, gy, CELL, 0.18); + } + } + // ── current piece ── + if (!this.over && !this.flashRows.length) { + this.drawShape(ctx, this.cur.shape, this.cur.color, this.cur.x, this.cur.y); + } + // ── overlays ── + if (this.over) { + ctx.fillStyle = 'rgba(0,0,0,0.82)'; + ctx.fillRect(0, 0, W, H); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = '#ff3355'; + ctx.font = 'bold 38px Arial, sans-serif'; + ctx.fillText('GAME OVER', W / 2, H / 2 - 52); + ctx.fillStyle = '#ccccee'; + ctx.font = '18px Arial, sans-serif'; + ctx.fillText(`Score: ${this.score.toLocaleString()}`, W / 2, H / 2 - 8); + ctx.fillStyle = '#777799'; + ctx.font = '14px Arial, sans-serif'; + ctx.fillText('Enter / Space → restart', W / 2, H / 2 + 26); + } + else if (this.paused) { + ctx.fillStyle = 'rgba(0,0,0,0.68)'; + ctx.fillRect(0, 0, W, H); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = '#eeeeff'; + ctx.font = 'bold 32px Arial, sans-serif'; + ctx.fillText('PAUSED', W / 2, H / 2 - 16); + ctx.fillStyle = '#777799'; + ctx.font = '14px Arial, sans-serif'; + ctx.fillText('P → resume', W / 2, H / 2 + 20); + } + // ── preview panels ── + this.drawPreview(this.nCtx, this.nCanvas, this.nxt, false); + this.drawPreview(this.hCtx, this.hCanvas, this.held, !this.canHold); + } + drawPreview(ctx, canvas, piece, dim) { + ctx.fillStyle = '#0c0c20'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + if (!piece) + return; + const rows = piece.shape.length; + const cols = piece.shape[0].length; + const ox = (4 - cols) >> 1; + const oy = (4 - rows) >> 1; + this.drawShape(ctx, piece.shape, piece.color, ox, oy, PREVIEW_CS, dim ? 0.32 : 1.0); + } + // ── Stats UI ────────────────────────────────────────────── + refreshStats() { + this.el('score').textContent = this.score.toLocaleString(); + this.el('level').textContent = String(this.level); + this.el('lines').textContent = String(this.lines); + this.saveBest(); + } + // ── Input handling ──────────────────────────────────────── + stopRepeat(key) { + const d = this.dasMap.get(key); + const a = this.arrMap.get(key); + if (d != null) { + window.clearTimeout(d); + this.dasMap.delete(key); + } + if (a != null) { + window.clearInterval(a); + this.arrMap.delete(key); + } + } + startRepeat(key, fn) { + if (this.dasMap.has(key)) + return; // already active + fn(); // fire immediately + const d = window.setTimeout(() => { + const a = window.setInterval(() => { + if (!this.paused && !this.over) + fn(); + }, this.ARR); + this.arrMap.set(key, a); + }, this.DAS); + this.dasMap.set(key, d); + } + bindInput() { + const PREVENT = new Set(['ArrowLeft', 'ArrowRight', 'ArrowDown', 'ArrowUp', 'Space']); + document.addEventListener('keydown', (e) => { + if (PREVENT.has(e.code)) + e.preventDefault(); + // Restart on game over + if (this.over) { + if (e.code === 'Enter' || e.code === 'Space') + this.newGame(); + return; + } + // Pause toggle (works even mid-game) + if (e.code === 'KeyP') { + this.paused = !this.paused; + if (!this.paused) + this.lastTs = 0; // prevent dt spike after unpause + return; + } + if (this.paused) + return; + switch (e.code) { + case 'ArrowLeft': + this.startRepeat('L', () => this.moveL()); + break; + case 'ArrowRight': + this.startRepeat('R', () => this.moveR()); + break; + case 'ArrowDown': + this.startRepeat('D', () => this.softD()); + break; + case 'ArrowUp': + case 'KeyX': + this.rotate(1); + break; + case 'KeyZ': + case 'ControlLeft': + case 'ControlRight': + this.rotate(-1); + break; + case 'Space': + this.hardD(); + break; + case 'KeyC': + case 'ShiftLeft': + case 'ShiftRight': + this.holdF(); + break; + } + }); + document.addEventListener('keyup', (e) => { + const map = { + ArrowLeft: 'L', ArrowRight: 'R', ArrowDown: 'D', + }; + const key = map[e.code]; + if (key) + this.stopRepeat(key); + }); + } +} +// ── Entry point ─────────────────────────────────────────────────────────────── +window.addEventListener('DOMContentLoaded', () => { new Tetris(); }); diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts @@ -0,0 +1,82 @@ +interface Point { + x: number; + y: number; +} +interface Piece { + shape: number[][]; + color: string; + position: Point; + rotationIndex: number; +} +interface GameState { + board: (string | null)[][]; + currentPiece: Piece | null; + nextPiece: Piece | null; + score: number; + level: number; + linesCleared: number; + gameOver: boolean; + paused: boolean; +} +declare const BOARD_WIDTH = 10; +declare const BOARD_HEIGHT = 20; +declare const BLOCK_SIZE = 30; +declare const INITIAL_DROP_SPEED = 800; +declare const TETROMINOS: { + I: { + rotations: number[][][]; + color: string; + }; + O: { + rotations: number[][][]; + color: string; + }; + T: { + rotations: number[][][]; + color: string; + }; + S: { + rotations: number[][][]; + color: string; + }; + Z: { + rotations: number[][][]; + color: string; + }; + J: { + rotations: number[][][]; + color: string; + }; + L: { + rotations: number[][][]; + color: string; + }; +}; +type TetrominoKey = keyof typeof TETROMINOS; +declare class TetrisGame { + private canvas; + private ctx; + private gameState; + private dropInterval; + private moveInterval; + private keys; + constructor(canvasId: string); + private initializeGameState; + private generateNewPiece; + private setupEventListeners; + private togglePause; + private restartGame; + startGameLoop(): void; + private handleInput; + private movePiece; + private rotatePiece; + private canMovePiece; + private lockPiece; + private clearLines; + private update; + private render; + private drawBlock; + private drawPiece; + private renderUI; +} +//# sourceMappingURL=game.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts.map b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"game.d.ts","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"AAEA,UAAU,KAAK;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,UAAU,KAAK;IACb,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,SAAS;IACjB,KAAK,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;IAC3B,YAAY,EAAE,KAAK,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,KAAK,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,QAAA,MAAM,WAAW,KAAK,CAAC;AACvB,QAAA,MAAM,YAAY,KAAK,CAAC;AACxB,QAAA,MAAM,UAAU,KAAK,CAAC;AACtB,QAAA,MAAM,kBAAkB,MAAM,CAAC;AAG/B,QAAA,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDf,CAAC;AAEF,KAAK,YAAY,GAAG,MAAM,OAAO,UAAU,CAAC;AAE5C,cAAM,UAAU;IACd,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,GAAG,CAA2B;IACtC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,IAAI,CAA0B;gBAE1B,QAAQ,EAAE,MAAM;IAmB5B,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,mBAAmB;IAuB3B,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,WAAW;IAMZ,aAAa,IAAI,IAAI;IAkB5B,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,SAAS;IAejB,OAAO,CAAC,WAAW;IAgCnB,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,SAAS;IAkCjB,OAAO,CAAC,UAAU;IAiClB,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,MAAM;IAuCd,OAAO,CAAC,SAAS;IAmBjB,OAAO,CAAC,SAAS;IAejB,OAAO,CAAC,QAAQ;CA4GjB"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js @@ -0,0 +1,404 @@ +"use strict"; +// Tetris Game in TypeScript +const BOARD_WIDTH = 10; +const BOARD_HEIGHT = 20; +const BLOCK_SIZE = 30; +const INITIAL_DROP_SPEED = 800; // milliseconds +// Tetromino shapes (all rotations) +const TETROMINOS = { + I: { + rotations: [ + [[1, 1, 1, 1]], + [[1], [1], [1], [1]], + ], + color: '#00F0F0', // Cyan + }, + O: { + rotations: [[[1, 1], [1, 1]]], + color: '#F0F000', // Yellow + }, + T: { + rotations: [ + [[0, 1, 0], [1, 1, 1]], + [[1, 0], [1, 1], [1, 0]], + [[1, 1, 1], [0, 1, 0]], + [[0, 1], [1, 1], [0, 1]], + ], + color: '#A000F0', // Purple + }, + S: { + rotations: [ + [[0, 1, 1], [1, 1, 0]], + [[1, 0], [1, 1], [0, 1]], + ], + color: '#00F000', // Green + }, + Z: { + rotations: [ + [[1, 1, 0], [0, 1, 1]], + [[0, 1], [1, 1], [1, 0]], + ], + color: '#F00000', // Red + }, + J: { + rotations: [ + [[1, 0, 0], [1, 1, 1]], + [[1, 1], [1, 0], [1, 0]], + [[1, 1, 1], [0, 0, 1]], + [[0, 1], [0, 1], [1, 1]], + ], + color: '#0000F0', // Blue + }, + L: { + rotations: [ + [[0, 0, 1], [1, 1, 1]], + [[1, 0], [1, 0], [1, 1]], + [[1, 1, 1], [1, 0, 0]], + [[1, 1], [0, 1], [0, 1]], + ], + color: '#F0A000', // Orange + }, +}; +class TetrisGame { + constructor(canvasId) { + this.dropInterval = null; + this.moveInterval = null; + this.keys = new Set(); + const canvas = document.getElementById(canvasId); + if (!canvas) { + throw new Error(`Canvas with id "${canvasId}" not found`); + } + this.canvas = canvas; + const ctx = canvas.getContext('2d'); + if (!ctx) { + throw new Error('Could not get 2D context from canvas'); + } + this.ctx = ctx; + this.gameState = this.initializeGameState(); + this.setupEventListeners(); + this.render(); + } + initializeGameState() { + const board = Array(BOARD_HEIGHT) + .fill(null) + .map(() => Array(BOARD_WIDTH).fill(null)); + return { + board, + currentPiece: this.generateNewPiece(), + nextPiece: this.generateNewPiece(), + score: 0, + level: 1, + linesCleared: 0, + gameOver: false, + paused: false, + }; + } + generateNewPiece() { + const keys = Object.keys(TETROMINOS); + const randomKey = keys[Math.floor(Math.random() * keys.length)]; + const tetromino = TETROMINOS[randomKey]; + const rotation = tetromino.rotations[0]; + return { + shape: rotation.map(row => [...row]), + color: tetromino.color, + position: { x: BOARD_WIDTH / 2 - Math.ceil(rotation[0].length / 2), y: 0 }, + rotationIndex: 0, + }; + } + setupEventListeners() { + window.addEventListener('keydown', (e) => { + this.keys.add(e.key.toLowerCase()); + if (e.key === ' ') { + e.preventDefault(); + this.rotatePiece(); + } + if (e.key === 'Enter') { + e.preventDefault(); + this.togglePause(); + } + if (e.key === 'Escape') { + e.preventDefault(); + this.restartGame(); + } + }); + window.addEventListener('keyup', (e) => { + this.keys.delete(e.key.toLowerCase()); + }); + } + togglePause() { + if (this.gameState.gameOver) + return; + this.gameState.paused = !this.gameState.paused; + } + restartGame() { + this.gameState = this.initializeGameState(); + if (this.dropInterval) + clearInterval(this.dropInterval); + this.startGameLoop(); + } + startGameLoop() { + const dropSpeed = INITIAL_DROP_SPEED - (this.gameState.level - 1) * 50; + const finalSpeed = Math.max(100, dropSpeed); + this.dropInterval = window.setInterval(() => { + if (!this.gameState.paused && !this.gameState.gameOver) { + this.update(); + this.render(); + } + }, finalSpeed); + this.moveInterval = window.setInterval(() => { + if (!this.gameState.paused && !this.gameState.gameOver) { + this.handleInput(); + } + }, 50); + } + handleInput() { + if (this.keys.has('arrowleft')) { + this.movePiece(-1, 0); + } + if (this.keys.has('arrowright')) { + this.movePiece(1, 0); + } + if (this.keys.has('arrowdown')) { + this.movePiece(0, 1); + } + } + movePiece(dx, dy) { + if (!this.gameState.currentPiece) + return; + const newPosition = { + x: this.gameState.currentPiece.position.x + dx, + y: this.gameState.currentPiece.position.y + dy, + }; + if (this.canMovePiece(this.gameState.currentPiece.shape, newPosition)) { + this.gameState.currentPiece.position = newPosition; + } + else if (dy > 0) { + this.lockPiece(); + } + } + rotatePiece() { + if (!this.gameState.currentPiece) + return; + const keys = Object.keys(TETROMINOS); + let tetrominoKey = null; + for (const key of keys) { + if (TETROMINOS[key].color === this.gameState.currentPiece.color) { + tetrominoKey = key; + break; + } + } + if (!tetrominoKey) + return; + const tetromino = TETROMINOS[tetrominoKey]; + const rotations = tetromino.rotations; + const currentRotationIndex = this.gameState.currentPiece.rotationIndex; + const nextRotationIndex = (currentRotationIndex + 1) % rotations.length; + const newShape = rotations[nextRotationIndex]; + if (this.canMovePiece(newShape, this.gameState.currentPiece.position)) { + this.gameState.currentPiece.shape = newShape.map(row => [...row]); + this.gameState.currentPiece.rotationIndex = nextRotationIndex; + } + } + canMovePiece(shape, position) { + for (let y = 0; y < shape.length; y++) { + for (let x = 0; x < shape[y].length; x++) { + if (!shape[y][x]) + continue; + const boardX = position.x + x; + const boardY = position.y + y; + if (boardX < 0 || + boardX >= BOARD_WIDTH || + boardY >= BOARD_HEIGHT) { + return false; + } + if (boardY >= 0 && this.gameState.board[boardY][boardX] !== null) { + return false; + } + } + } + return true; + } + lockPiece() { + const piece = this.gameState.currentPiece; + if (!piece) + return; + for (let y = 0; y < piece.shape.length; y++) { + for (let x = 0; x < piece.shape[y].length; x++) { + if (!piece.shape[y][x]) + continue; + const boardX = piece.position.x + x; + const boardY = piece.position.y + y; + if (boardY < 0) { + this.gameState.gameOver = true; + return; + } + if (boardY >= 0 && boardY < BOARD_HEIGHT) { + this.gameState.board[boardY][boardX] = piece.color; + } + } + } + this.clearLines(); + this.gameState.currentPiece = this.gameState.nextPiece; + this.gameState.nextPiece = this.generateNewPiece(); + if (this.gameState.currentPiece && !this.canMovePiece(this.gameState.currentPiece.shape, this.gameState.currentPiece.position)) { + this.gameState.gameOver = true; + } + } + clearLines() { + const linesToClear = []; + for (let y = BOARD_HEIGHT - 1; y >= 0; y--) { + if (this.gameState.board[y].every(cell => cell !== null)) { + linesToClear.push(y); + } + } + if (linesToClear.length === 0) + return; + linesToClear.forEach((lineIndex) => { + this.gameState.board.splice(lineIndex, 1); + this.gameState.board.unshift(Array(BOARD_WIDTH).fill(null)); + }); + this.gameState.linesCleared += linesToClear.length; + // Update score based on lines cleared at once + const lineScores = { + 1: 100, + 2: 300, + 3: 500, + 4: 800, // Tetris bonus + }; + const points = lineScores[linesToClear.length] || 0; + this.gameState.score += points * this.gameState.level; + // Increase level every 10 lines + this.gameState.level = Math.floor(this.gameState.linesCleared / 10) + 1; + } + update() { + if (!this.gameState.currentPiece) { + this.gameState.currentPiece = this.generateNewPiece(); + } + this.movePiece(0, 1); + } + render() { + // Clear canvas + this.ctx.fillStyle = '#000000'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw game board background + this.ctx.strokeStyle = '#333333'; + this.ctx.lineWidth = 0.5; + for (let y = 0; y <= BOARD_HEIGHT; y++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, y * BLOCK_SIZE); + this.ctx.lineTo(BOARD_WIDTH * BLOCK_SIZE, y * BLOCK_SIZE); + this.ctx.stroke(); + } + for (let x = 0; x <= BOARD_WIDTH; x++) { + this.ctx.beginPath(); + this.ctx.moveTo(x * BLOCK_SIZE, 0); + this.ctx.lineTo(x * BLOCK_SIZE, BOARD_HEIGHT * BLOCK_SIZE); + this.ctx.stroke(); + } + // Draw locked blocks + for (let y = 0; y < BOARD_HEIGHT; y++) { + for (let x = 0; x < BOARD_WIDTH; x++) { + const color = this.gameState.board[y][x]; + if (color) { + this.drawBlock(x, y, color); + } + } + } + // Draw current piece + if (this.gameState.currentPiece) { + this.drawPiece(this.gameState.currentPiece); + } + this.renderUI(); + } + drawBlock(x, y, color) { + this.ctx.fillStyle = color; + this.ctx.fillRect(x * BLOCK_SIZE + 1, y * BLOCK_SIZE + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + this.ctx.strokeStyle = '#ffffff'; + this.ctx.lineWidth = 0.5; + this.ctx.strokeRect(x * BLOCK_SIZE + 1, y * BLOCK_SIZE + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + } + drawPiece(piece) { + for (let y = 0; y < piece.shape.length; y++) { + for (let x = 0; x < piece.shape[y].length; x++) { + if (piece.shape[y][x]) { + const boardX = piece.position.x + x; + const boardY = piece.position.y + y; + if (boardY >= 0) { + this.drawBlock(boardX, boardY, piece.color); + } + } + } + } + } + renderUI() { + const gameWidth = BOARD_WIDTH * BLOCK_SIZE; + const uiX = gameWidth + 20; + // Score + this.ctx.fillStyle = '#FFFFFF'; + this.ctx.font = 'bold 20px Arial'; + this.ctx.fillText('TETRIS', uiX, 30); + this.ctx.font = '14px Arial'; + this.ctx.fillText(`Score: ${this.gameState.score}`, uiX, 70); + this.ctx.fillText(`Level: ${this.gameState.level}`, uiX, 100); + this.ctx.fillText(`Lines: ${this.gameState.linesCleared}`, uiX, 130); + // Next piece + this.ctx.font = 'bold 14px Arial'; + this.ctx.fillText('Next:', uiX, 170); + if (this.gameState.nextPiece) { + const nextStartY = 190; + const previewX = uiX; + for (let y = 0; y < this.gameState.nextPiece.shape.length; y++) { + for (let x = 0; x < this.gameState.nextPiece.shape[y].length; x++) { + if (this.gameState.nextPiece.shape[y][x]) { + this.ctx.fillStyle = this.gameState.nextPiece.color; + this.ctx.fillRect(previewX + x * 20, nextStartY + y * 20, 18, 18); + this.ctx.strokeStyle = '#FFFFFF'; + this.ctx.lineWidth = 0.5; + this.ctx.strokeRect(previewX + x * 20, nextStartY + y * 20, 18, 18); + } + } + } + } + // Controls + this.ctx.font = '11px Arial'; + this.ctx.fillStyle = '#AAAAAA'; + const controlsY = 350; + this.ctx.fillText('← → Move', uiX, controlsY); + this.ctx.fillText('↓ Drop faster', uiX, controlsY + 20); + this.ctx.fillText('SPACE Rotate', uiX, controlsY + 40); + this.ctx.fillText('ENTER Pause', uiX, controlsY + 60); + this.ctx.fillText('ESC Restart', uiX, controlsY + 80); + // Game over/Paused message + if (this.gameState.gameOver) { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; + this.ctx.fillRect(0, 0, BOARD_WIDTH * BLOCK_SIZE, BOARD_HEIGHT * BLOCK_SIZE); + this.ctx.fillStyle = '#FF0000'; + this.ctx.font = 'bold 48px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('GAME OVER', (BOARD_WIDTH * BLOCK_SIZE) / 2, (BOARD_HEIGHT * BLOCK_SIZE) / 2 - 30); + this.ctx.font = '20px Arial'; + this.ctx.fillStyle = '#FFFFFF'; + this.ctx.fillText(`Final Score: ${this.gameState.score}`, (BOARD_WIDTH * BLOCK_SIZE) / 2, (BOARD_HEIGHT * BLOCK_SIZE) / 2 + 20); + this.ctx.fillText('Press ESC to restart', (BOARD_WIDTH * BLOCK_SIZE) / 2, (BOARD_HEIGHT * BLOCK_SIZE) / 2 + 50); + this.ctx.textAlign = 'left'; + } + else if (this.gameState.paused) { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; + this.ctx.fillRect(0, 0, BOARD_WIDTH * BLOCK_SIZE, BOARD_HEIGHT * BLOCK_SIZE); + this.ctx.fillStyle = '#FFFF00'; + this.ctx.font = 'bold 48px Arial'; + this.ctx.textAlign = 'center'; + this.ctx.fillText('PAUSED', (BOARD_WIDTH * BLOCK_SIZE) / 2, (BOARD_HEIGHT * BLOCK_SIZE) / 2); + this.ctx.font = '20px Arial'; + this.ctx.fillStyle = '#FFFFFF'; + this.ctx.fillText('Press ENTER to continue', (BOARD_WIDTH * BLOCK_SIZE) / 2, (BOARD_HEIGHT * BLOCK_SIZE) / 2 + 40); + this.ctx.textAlign = 'left'; + } + } +} +// Initialize game when page loads +window.addEventListener('DOMContentLoaded', () => { + const game = new TetrisGame('gameCanvas'); + game.startGameLoop(); +}); +//# sourceMappingURL=game.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js.map b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js.map @@ -0,0 +1 @@ +{"version":3,"file":"game.js","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,706 @@ +"use strict"; +// ── Types ────────────────────────────────────────────────────────────────── +// ── Constants ────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const HIDDEN_ROWS = 2; // rows above the visible board for spawning +const TOTAL_ROWS = ROWS + HIDDEN_ROWS; +const CELL = 32; // pixels per cell +const PREVIEW_CELL = 20; +const LOCK_DELAY = 500; // ms before a landed piece locks +const MAX_LOCK_RESETS = 15; +const LEVEL_SPEEDS = []; // ms per gravity tick at each level +for (let lvl = 0; lvl <= 29; lvl++) { + // NES-inspired curve, but in milliseconds + const framesPerDrop = [ + 48, 43, 38, 33, 28, 23, 18, 13, 8, 6, + 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, + ][lvl]; + LEVEL_SPEEDS.push(framesPerDrop * (1000 / 60)); +} +// Scoring (original BPS) +const LINE_SCORES = [0, 100, 300, 500, 800]; +// SRS wall-kick data (non-I pieces) +const WALL_KICKS_JLSTZ = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// SRS wall-kick data (I piece) +const WALL_KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// ── Tetromino Definitions (SRS) ──────────────────────────────────────────── +function buildRotations(base) { + const rots = [base]; + for (let r = 1; r < 4; r++) { + const prev = rots[r - 1]; + const size = prev.length; + const next = Array.from({ length: size }, () => Array(size).fill(0)); + for (let row = 0; row < size; row++) { + for (let col = 0; col < size; col++) { + next[col][size - 1 - row] = prev[row][col]; + } + } + rots.push(next); + } + return rots; +} +const TETROMINOES = [ + { + color: "#00f0f0", + rotations: buildRotations([ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ]), + }, + { + color: "#f0f000", + rotations: buildRotations([ + [1, 1], + [1, 1], + ]), + }, + { + color: "#a000f0", + rotations: buildRotations([ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ]), + }, + { + color: "#00f000", + rotations: buildRotations([ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ]), + }, + { + color: "#f00000", + rotations: buildRotations([ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ]), + }, + { + color: "#0000f0", + rotations: buildRotations([ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ]), + }, + { + color: "#f0a000", + rotations: buildRotations([ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ]), + }, +]; +// ── Game State ───────────────────────────────────────────────────────────── +class Piece { + constructor(defIdx) { + this.defIdx = defIdx; + this.rot = 0; + const shape = this.shape(); + // centre horizontally + this.pos = { + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, // spawn in hidden area + }; + } + get def() { + return TETROMINOES[this.defIdx]; + } + shape() { + return this.def.rotations[this.rot]; + } + /** Iterate over filled cells yielding board coordinates. */ + *cells() { + const s = this.shape(); + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (s[r][c]) { + yield { x: this.pos.x + c, y: this.pos.y + r }; + } + } + } + } +} +class TetrisGame { + constructor() { + this.nextQueue = []; + this.bag = []; + this.holdIdx = null; + this.holdUsed = false; + this.score = 0; + this.lines = 0; + this.level = 0; + this.startLevel = 0; + this.combo = -1; + this.gameOver = false; + this.paused = false; + // Timing + this.lastDrop = 0; + this.lockTimer = null; + this.lockResets = 0; + // DAS / ARR (Delayed Auto Shift) + this.dasDir = 0; + this.dasTimer = 0; + this.dasDelay = 167; // ms before auto-repeat starts + this.arrDelay = 50; // ms between auto-repeat moves + // Soft drop + this.softDropping = false; + // Ghost piece + this.ghostY = 0; + // Line clear animation + this.clearingRows = []; + this.clearAnimStart = 0; + this.clearAnimDuration = 300; // ms + this.canvas = document.getElementById("board"); + this.ctx = this.canvas.getContext("2d"); + this.canvas.width = COLS * CELL; + this.canvas.height = ROWS * CELL; + this.previewCanvas = document.getElementById("preview"); + this.previewCtx = this.previewCanvas.getContext("2d"); + this.previewCanvas.width = PREVIEW_CELL * 6; + this.previewCanvas.height = PREVIEW_CELL * 3 * 5; // 5 previews + this.holdCanvas = document.getElementById("hold"); + this.holdCtx = this.holdCanvas.getContext("2d"); + this.holdCanvas.width = PREVIEW_CELL * 6; + this.holdCanvas.height = PREVIEW_CELL * 4; + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.board = []; + this.reset(); + } + // ── Bag Randomiser ────────────────────────────────────────────────────── + refillBag() { + const indices = [0, 1, 2, 3, 4, 5, 6]; + // Fisher-Yates + for (let i = indices.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [indices[i], indices[j]] = [indices[j], indices[i]]; + } + this.bag = indices; + } + nextPiece() { + if (this.bag.length === 0) + this.refillBag(); + return this.bag.pop(); + } + ensureQueue() { + while (this.nextQueue.length < 5) { + this.nextQueue.push(this.nextPiece()); + } + } + // ── Reset / Spawn ─────────────────────────────────────────────────────── + reset() { + this.board = Array.from({ length: TOTAL_ROWS }, () => Array(COLS).fill(null)); + this.score = 0; + this.lines = 0; + this.level = this.startLevel; + this.combo = -1; + this.gameOver = false; + this.paused = false; + this.holdIdx = null; + this.holdUsed = false; + this.clearingRows = []; + this.bag = []; + this.nextQueue = []; + this.ensureQueue(); + this.spawn(); + this.lastDrop = performance.now(); + this.updateStats(); + } + spawn() { + this.ensureQueue(); + const idx = this.nextQueue.shift(); + this.current = new Piece(idx); + this.lockTimer = null; + this.lockResets = 0; + this.holdUsed = false; + this.updateGhost(); + // If the new piece overlaps immediately → game over + if (!this.isValid(this.current)) { + this.gameOver = true; + } + } + // ── Collision ─────────────────────────────────────────────────────────── + isValid(piece) { + for (const { x, y } of piece.cells()) { + if (x < 0 || x >= COLS || y < 0 || y >= TOTAL_ROWS) + return false; + if (this.board[y][x] !== null) + return false; + } + return true; + } + isOnGround(piece) { + piece.pos.y++; + const valid = this.isValid(piece); + piece.pos.y--; + return !valid; + } + // ── Ghost ─────────────────────────────────────────────────────────────── + updateGhost() { + let gy = this.current.pos.y; + const saved = this.current.pos.y; + while (true) { + this.current.pos.y = gy + 1; + if (!this.isValid(this.current)) + break; + gy++; + } + this.current.pos.y = saved; + this.ghostY = gy; + } + // ── Movement ──────────────────────────────────────────────────────────── + tryMove(dx, dy) { + this.current.pos.x += dx; + this.current.pos.y += dy; + if (this.isValid(this.current)) { + this.updateGhost(); + this.resetLock(); + return true; + } + this.current.pos.x -= dx; + this.current.pos.y -= dy; + return false; + } + tryRotate(dir) { + const oldRot = this.current.rot; + const newRot = (oldRot + dir + 4) % 4; + const kicks = this.current.defIdx === 0 + ? WALL_KICKS_I[`${oldRot}>${newRot}`] + : WALL_KICKS_JLSTZ[`${oldRot}>${newRot}`]; + // O piece — no rotation needed (but harmless) + if (this.current.defIdx === 1) + return false; + const savedX = this.current.pos.x; + const savedY = this.current.pos.y; + this.current.rot = newRot; + for (const [kx, ky] of kicks) { + this.current.pos.x = savedX + kx; + this.current.pos.y = savedY - ky; // SRS kick tables use y-up + if (this.isValid(this.current)) { + this.updateGhost(); + this.resetLock(); + return true; + } + } + // Revert + this.current.rot = oldRot; + this.current.pos.x = savedX; + this.current.pos.y = savedY; + return false; + } + hardDrop() { + let rows = 0; + while (!this.isOnGround(this.current)) { + this.current.pos.y++; + rows++; + } + this.score += rows * 2; + this.lockPiece(); + } + // ── Hold ──────────────────────────────────────────────────────────────── + hold() { + if (this.holdUsed) + return; + this.holdUsed = true; + const prev = this.holdIdx; + this.holdIdx = this.current.defIdx; + if (prev !== null) { + this.current = new Piece(prev); + this.lockTimer = null; + this.lockResets = 0; + this.updateGhost(); + if (!this.isValid(this.current)) { + this.gameOver = true; + } + } + else { + this.spawn(); + } + } + // ── Lock ──────────────────────────────────────────────────────────────── + resetLock() { + if (this.lockTimer !== null && this.lockResets < MAX_LOCK_RESETS) { + this.lockTimer = performance.now(); + this.lockResets++; + } + } + lockPiece() { + for (const { x, y } of this.current.cells()) { + this.board[y][x] = this.current.def.color; + } + this.lockTimer = null; + this.checkLines(); + } + // ── Line Clearing ────────────────────────────────────────────────────── + checkLines() { + const full = []; + for (let r = 0; r < TOTAL_ROWS; r++) { + if (this.board[r].every((c) => c !== null)) { + full.push(r); + } + } + if (full.length > 0) { + this.clearingRows = full; + this.clearAnimStart = performance.now(); + } + else { + this.combo = -1; + this.spawn(); + } + } + finishClear() { + const count = this.clearingRows.length; + // Remove rows top-down and add empty rows at top + for (const r of [...this.clearingRows].sort((a, b) => a - b)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(null)); + } + this.combo++; + const base = LINE_SCORES[count] ?? 0; + this.score += base * (this.level + 1); + // Combo bonus + if (this.combo > 0) { + this.score += 50 * this.combo * (this.level + 1); + } + this.lines += count; + this.level = this.startLevel + Math.floor(this.lines / 10); + this.clearingRows = []; + this.updateStats(); + this.spawn(); + } + // ── Input ─────────────────────────────────────────────────────────────── + handleKeyDown(e) { + if (this.gameOver) { + if (e.key === "r" || e.key === "R") + this.reset(); + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.paused = !this.paused; + if (!this.paused) + this.lastDrop = performance.now(); + return; + } + if (this.paused) + return; + if (this.clearingRows.length > 0) + return; + switch (e.key) { + case "ArrowLeft": + e.preventDefault(); + this.tryMove(-1, 0); + this.dasDir = -1; + this.dasTimer = performance.now(); + break; + case "ArrowRight": + e.preventDefault(); + this.tryMove(1, 0); + this.dasDir = 1; + this.dasTimer = performance.now(); + break; + case "ArrowDown": + e.preventDefault(); + this.softDropping = true; + break; + case "ArrowUp": + e.preventDefault(); + this.tryRotate(1); + break; + case "z": + case "Z": + this.tryRotate(-1); + break; + case "x": + case "X": + this.tryRotate(1); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + case "c": + case "C": + case "Shift": + this.hold(); + break; + case "r": + case "R": + this.reset(); + break; + } + } + handleKeyUp(e) { + if (e.key === "ArrowLeft" && this.dasDir === -1) + this.dasDir = 0; + if (e.key === "ArrowRight" && this.dasDir === 1) + this.dasDir = 0; + if (e.key === "ArrowDown") + this.softDropping = false; + } + // ── Update ────────────────────────────────────────────────────────────── + update(now) { + if (this.gameOver || this.paused) + return; + // Handle line clear animation + if (this.clearingRows.length > 0) { + if (now - this.clearAnimStart >= this.clearAnimDuration) { + this.finishClear(); + this.lastDrop = now; + } + return; + } + // DAS + if (this.dasDir !== 0) { + const elapsed = now - this.dasTimer; + if (elapsed >= this.dasDelay) { + const arrElapsed = elapsed - this.dasDelay; + const moves = Math.floor(arrElapsed / this.arrDelay); + // move up to `moves` times (we just do a single step per frame for simplicity) + this.tryMove(this.dasDir, 0); + } + } + // Soft drop + if (this.softDropping) { + if (this.tryMove(0, 1)) { + this.score += 1; + this.lastDrop = now; + } + } + // Gravity + const speed = LEVEL_SPEEDS[Math.min(this.level, LEVEL_SPEEDS.length - 1)]; + if (now - this.lastDrop >= speed) { + if (!this.tryMove(0, 1)) { + // On ground — start lock timer if not started + if (this.lockTimer === null) { + this.lockTimer = now; + } + } + else { + this.lockTimer = null; + } + this.lastDrop = now; + } + // Lock delay + if (this.lockTimer !== null && this.isOnGround(this.current)) { + if (now - this.lockTimer >= LOCK_DELAY) { + this.lockPiece(); + } + } + else if (this.lockTimer !== null && !this.isOnGround(this.current)) { + this.lockTimer = null; // piece moved off ground + } + } + // ── Stats ─────────────────────────────────────────────────────────────── + updateStats() { + this.scoreEl.textContent = this.score.toLocaleString(); + this.linesEl.textContent = this.lines.toString(); + this.levelEl.textContent = this.level.toString(); + } + // ── Rendering ─────────────────────────────────────────────────────────── + draw(now) { + this.drawBoard(now); + this.drawPreview(); + this.drawHold(); + this.updateStats(); + } + drawBoard(now) { + const ctx = this.ctx; + const w = this.canvas.width; + const h = this.canvas.height; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, w, h); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, h); + ctx.stroke(); + } + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(w, r * CELL); + ctx.stroke(); + } + // Locked cells + for (let r = HIDDEN_ROWS; r < TOTAL_ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const color = this.board[r][c]; + if (color) { + // Check if this row is being cleared + if (this.clearingRows.includes(r)) { + const progress = Math.min(1, (now - this.clearAnimStart) / this.clearAnimDuration); + ctx.globalAlpha = 1 - progress; + this.drawCell(ctx, c, r - HIDDEN_ROWS, color, CELL); + ctx.globalAlpha = 1; + } + else { + this.drawCell(ctx, c, r - HIDDEN_ROWS, color, CELL); + } + } + } + } + if (this.gameOver) { + ctx.fillStyle = "rgba(0,0,0,0.7)"; + ctx.fillRect(0, 0, w, h); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px 'Segoe UI', Arial, sans-serif"; + ctx.textAlign = "center"; + ctx.fillText("GAME OVER", w / 2, h / 2 - 16); + ctx.font = "16px 'Segoe UI', Arial, sans-serif"; + ctx.fillText("Press R to restart", w / 2, h / 2 + 16); + return; + } + if (this.paused) { + ctx.fillStyle = "rgba(0,0,0,0.7)"; + ctx.fillRect(0, 0, w, h); + ctx.fillStyle = "#fff"; + ctx.font = "bold 28px 'Segoe UI', Arial, sans-serif"; + ctx.textAlign = "center"; + ctx.fillText("PAUSED", w / 2, h / 2 - 16); + ctx.font = "16px 'Segoe UI', Arial, sans-serif"; + ctx.fillText("Press P or Esc to resume", w / 2, h / 2 + 16); + return; + } + if (this.clearingRows.length > 0) + return; + // Ghost piece + const savedY = this.current.pos.y; + this.current.pos.y = this.ghostY; + for (const { x, y } of this.current.cells()) { + if (y >= HIDDEN_ROWS) { + const drawY = y - HIDDEN_ROWS; + ctx.fillStyle = "rgba(255,255,255,0.12)"; + ctx.fillRect(x * CELL + 1, drawY * CELL + 1, CELL - 2, CELL - 2); + ctx.strokeStyle = "rgba(255,255,255,0.3)"; + ctx.lineWidth = 1; + ctx.strokeRect(x * CELL + 1, drawY * CELL + 1, CELL - 2, CELL - 2); + } + } + this.current.pos.y = savedY; + // Current piece + for (const { x, y } of this.current.cells()) { + if (y >= HIDDEN_ROWS) { + this.drawCell(ctx, x, y - HIDDEN_ROWS, this.current.def.color, CELL); + } + } + } + drawCell(ctx, col, row, color, size) { + const x = col * size; + const y = row * size; + const inset = 1; + // Main fill + ctx.fillStyle = color; + ctx.fillRect(x + inset, y + inset, size - inset * 2, size - inset * 2); + // Highlight (top-left bevel) + ctx.fillStyle = "rgba(255,255,255,0.3)"; + ctx.fillRect(x + inset, y + inset, size - inset * 2, 2); + ctx.fillRect(x + inset, y + inset, 2, size - inset * 2); + // Shadow (bottom-right bevel) + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(x + inset, y + size - inset - 2, size - inset * 2, 2); + ctx.fillRect(x + size - inset - 2, y + inset, 2, size - inset * 2); + } + drawPreview() { + const ctx = this.previewCtx; + const cw = this.previewCanvas.width; + const ch = this.previewCanvas.height; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, cw, ch); + this.ensureQueue(); + const count = Math.min(5, this.nextQueue.length); + for (let i = 0; i < count; i++) { + const def = TETROMINOES[this.nextQueue[i]]; + const shape = def.rotations[0]; + const offsetY = i * PREVIEW_CELL * 3 + PREVIEW_CELL * 0.5; + const offsetX = (cw - shape[0].length * PREVIEW_CELL) / 2; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const px = offsetX + c * PREVIEW_CELL; + const py = offsetY + r * PREVIEW_CELL; + ctx.fillStyle = def.color; + ctx.fillRect(px + 1, py + 1, PREVIEW_CELL - 2, PREVIEW_CELL - 2); + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(px + 1, py + 1, PREVIEW_CELL - 2, 2); + ctx.fillRect(px + 1, py + 1, 2, PREVIEW_CELL - 2); + } + } + } + } + } + drawHold() { + const ctx = this.holdCtx; + const cw = this.holdCanvas.width; + const ch = this.holdCanvas.height; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, cw, ch); + if (this.holdIdx === null) + return; + const def = TETROMINOES[this.holdIdx]; + const shape = def.rotations[0]; + const offsetX = (cw - shape[0].length * PREVIEW_CELL) / 2; + const offsetY = (ch - shape.length * PREVIEW_CELL) / 2; + const alpha = this.holdUsed ? 0.35 : 1; + ctx.globalAlpha = alpha; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const px = offsetX + c * PREVIEW_CELL; + const py = offsetY + r * PREVIEW_CELL; + ctx.fillStyle = def.color; + ctx.fillRect(px + 1, py + 1, PREVIEW_CELL - 2, PREVIEW_CELL - 2); + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(px + 1, py + 1, PREVIEW_CELL - 2, 2); + ctx.fillRect(px + 1, py + 1, 2, PREVIEW_CELL - 2); + } + } + } + ctx.globalAlpha = 1; + } +} +// ── Bootstrap ───────────────────────────────────────────────────────────── +function main() { + const game = new TetrisGame(); + document.addEventListener("keydown", (e) => game.handleKeyDown(e)); + document.addEventListener("keyup", (e) => game.handleKeyUp(e)); + function loop(now) { + game.update(now); + game.draw(now); + requestAnimationFrame(loop); + } + requestAnimationFrame(loop); +} +document.addEventListener("DOMContentLoaded", main); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":";AAAA,8EAA8E;AAe9E,8EAA8E;AAE9E,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,4CAA4C;AACnE,MAAM,UAAU,GAAG,IAAI,GAAG,WAAW,CAAC;AACtC,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC,kBAAkB;AACnC,MAAM,YAAY,GAAG,EAAE,CAAC;AAExB,MAAM,UAAU,GAAG,GAAG,CAAC,CAAC,iCAAiC;AACzD,MAAM,eAAe,GAAG,EAAE,CAAC;AAE3B,MAAM,YAAY,GAAa,EAAE,CAAC,CAAC,oCAAoC;AACvE,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC;IACnC,0CAA0C;IAC1C,MAAM,aAAa,GAAG;QACpB,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;QACpC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAC5B,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KAC7B,CAAC,GAAG,CAAE,CAAC;IACR,YAAY,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,yBAAyB;AACzB,MAAM,WAAW,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAE5C,oCAAoC;AACpC,MAAM,gBAAgB,GAAuC;IAC3D,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACvC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IACvC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IACxC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IAC1C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC;IAC1C,KAAK,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/board.js b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/board.js @@ -0,0 +1,124 @@ +// ── Game Board Logic ──────────────────────────────────────────────── +import { TETROMINOES, getWallKicks } from "./pieces.js"; +export const COLS = 10; +export const ROWS = 20; +const BUFFER_ROWS = 4; // hidden rows above visible area +const TOTAL_ROWS = ROWS + BUFFER_ROWS; +export class Board { + constructor() { + this.bag = []; + this.grid = this.createEmptyGrid(); + } + createEmptyGrid() { + return Array.from({ length: TOTAL_ROWS }, () => Array(COLS).fill(null)); + } + reset() { + this.grid = this.createEmptyGrid(); + this.bag = []; + } + /** 7-bag randomizer: each bag has one of each piece, shuffled */ + nextPiece() { + if (this.bag.length === 0) { + this.bag = [...TETROMINOES]; + // Fisher-Yates shuffle + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop(); + } + /** Spawn position: centered, at top of visible area */ + spawnPosition(type) { + const shape = type.shapes[0]; + const width = shape[0].length; + return { + x: Math.floor((COLS - width) / 2), + y: BUFFER_ROWS - 1, // just above the visible area so piece enters from top + }; + } + /** Check if placing piece at pos/rotation collides */ + collides(type, rotation, pos) { + const shape = type.shapes[rotation]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const newX = pos.x + c; + const newY = pos.y + r; + if (newX < 0 || newX >= COLS || newY >= TOTAL_ROWS) + return true; + if (newY < 0) + continue; // above board is OK + if (this.grid[newY][newX] !== null) + return true; + } + } + return false; + } + /** Lock a piece into the grid */ + lock(piece) { + const shape = piece.type.shapes[piece.rotation]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const x = piece.pos.x + c; + const y = piece.pos.y + r; + if (y >= 0 && y < TOTAL_ROWS && x >= 0 && x < COLS) { + this.grid[y][x] = piece.type.color; + } + } + } + } + /** Clear completed lines, return how many were cleared */ + clearLines() { + let cleared = 0; + for (let r = TOTAL_ROWS - 1; r >= 0; r--) { + if (this.grid[r].every((cell) => cell !== null)) { + this.grid.splice(r, 1); + this.grid.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check same row index since rows shifted down + } + } + return cleared; + } + /** Check if any block is locked above the visible area → game over */ + isTopOut() { + for (let r = 0; r < BUFFER_ROWS; r++) { + if (this.grid[r].some((cell) => cell !== null)) + return true; + } + return false; + } + /** Try to rotate a piece with SRS wall kicks. Returns new rotation + position, or null */ + tryRotate(piece, direction) { + const fromRot = piece.rotation; + const toRot = (piece.rotation + direction + 4) % 4; + const kicks = getWallKicks(piece.type.name, fromRot, toRot); + for (const [dx, dy] of kicks) { + const newPos = { x: piece.pos.x + dx, y: piece.pos.y - dy }; + if (!this.collides(piece.type, toRot, newPos)) { + return { rotation: toRot, pos: newPos }; + } + } + return null; // no valid kick found + } + /** Compute the ghost piece Y (hard drop destination) */ + ghostY(piece) { + let y = piece.pos.y; + while (!this.collides(piece.type, piece.rotation, { x: piece.pos.x, y: y + 1 })) { + y++; + } + return y; + } + /** Return only the visible portion of the grid (below the buffer) */ + visibleGrid() { + return this.grid.slice(BUFFER_ROWS); + } + get bufferRows() { + return BUFFER_ROWS; + } +} +//# sourceMappingURL=board.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/board.js.map b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/board.js.map @@ -0,0 +1 @@ +{"version":3,"file":"board.js","sourceRoot":"","sources":["../src/board.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js @@ -0,0 +1,289 @@ +// ── Game Controller ───────────────────────────────────────────────── +/** Gravity interval (ms) per level. Starts slow, gets faster. */ +function dropInterval(level) { + // NES-style curve capped at a reasonable minimum + const intervals = [800, 720, 630, 550, 470, 380, 300, 220, 150, 100, 80, 70, 60, 50, 40]; + return intervals[Math.min(level - 1, intervals.length - 1)]; +} +/** Scoring table: index = lines cleared (1-4) */ +const LINE_SCORES = [0, 100, 300, 500, 800]; +/** Lock delay: how long (ms) the piece can sit on a surface before locking */ +const LOCK_DELAY = 500; +const MAX_LOCK_RESETS = 15; +/** DAS / ARR for key repeat */ +const DAS = 170; // ms before auto-repeat starts +const ARR = 50; // ms between auto-repeats +export class Game { + constructor(board, renderer) { + this.state = "idle" /* GameState.Idle */; + this.current = null; + this.nextType = null; + this.holdType = null; + this.holdLocked = false; + this.score = { score: 0, level: 1, lines: 0 }; + // Timing + this.lastDrop = 0; + this.lockTimer = 0; + this.lockResets = 0; + this.isLocking = false; + // Key repeat state + this.heldKeys = new Map(); + // Animation frame handle + this.rafId = 0; + // ── Core Loop ─────────────────────────────────────────────────── + this.loop = (now) => { + if (this.state !== "playing" /* GameState.Playing */) { + this.render(); + return; + } + this.processAutoRepeat(now); + // Gravity + const interval = dropInterval(this.score.level); + if (now - this.lastDrop >= interval) { + this.applyGravity(now); + this.lastDrop = now; + } + // Lock delay + if (this.isLocking && now - this.lockTimer >= LOCK_DELAY) { + this.lockPiece(); + } + this.render(); + this.rafId = requestAnimationFrame(this.loop); + }; + this.board = board; + this.renderer = renderer; + } + // ── Public API ────────────────────────────────────────────────── + start() { + this.board.reset(); + this.score = { score: 0, level: 1, lines: 0 }; + this.holdType = null; + this.holdLocked = false; + this.nextType = this.board.nextPiece(); + this.spawnPiece(); + this.state = "playing" /* GameState.Playing */; + this.renderer.showMessage(""); + this.lastDrop = performance.now(); + this.loop(performance.now()); + } + handleKeyDown(e) { + if (this.state === "idle" /* GameState.Idle */ || this.state === "over" /* GameState.Over */) { + if (e.key === "Enter" || e.key === " ") { + this.start(); + e.preventDefault(); + } + return; + } + if (e.key === "p" || e.key === "Escape") { + this.togglePause(); + e.preventDefault(); + return; + } + if (this.state !== "playing" /* GameState.Playing */) + return; + // Track held keys for DAS/ARR + if (!this.heldKeys.has(e.key)) { + this.heldKeys.set(e.key, { since: performance.now(), lastFire: 0 }); + } + switch (e.key) { + case "ArrowLeft": + this.move(-1, 0); + e.preventDefault(); + break; + case "ArrowRight": + this.move(1, 0); + e.preventDefault(); + break; + case "ArrowDown": + this.softDrop(); + e.preventDefault(); + break; + case "ArrowUp": + this.rotate(1); + e.preventDefault(); + break; + case "z": + case "Control": + this.rotate(-1); + e.preventDefault(); + break; + case " ": + this.hardDrop(); + e.preventDefault(); + break; + case "c": + case "Shift": + this.hold(); + e.preventDefault(); + break; + } + } + handleKeyUp(e) { + this.heldKeys.delete(e.key); + } + processAutoRepeat(now) { + for (const [key, info] of this.heldKeys) { + const held = now - info.since; + if (held < DAS) + continue; + const timeSinceLast = now - info.lastFire; + if (timeSinceLast >= ARR) { + info.lastFire = now; + if (key === "ArrowLeft") + this.move(-1, 0); + else if (key === "ArrowRight") + this.move(1, 0); + else if (key === "ArrowDown") + this.softDrop(); + } + } + } + // ── Piece Actions ─────────────────────────────────────────────── + spawnPiece() { + const type = this.nextType; + this.nextType = this.board.nextPiece(); + const pos = this.board.spawnPosition(type); + this.current = { type, rotation: 0, pos }; + this.isLocking = false; + this.lockResets = 0; + // If spawn position collides, game over + if (this.board.collides(type, 0, pos)) { + this.gameOver(); + } + } + move(dx, dy) { + if (!this.current) + return false; + const newPos = { x: this.current.pos.x + dx, y: this.current.pos.y + dy }; + if (!this.board.collides(this.current.type, this.current.rotation, newPos)) { + this.current.pos = newPos; + this.resetLockDelay(); + return true; + } + return false; + } + rotate(dir) { + if (!this.current) + return; + const result = this.board.tryRotate(this.current, dir); + if (result) { + this.current.rotation = result.rotation; + this.current.pos = result.pos; + this.resetLockDelay(); + } + } + softDrop() { + if (!this.current) + return; + if (this.move(0, 1)) { + this.score.score += 1; + this.lastDrop = performance.now(); + } + } + hardDrop() { + if (!this.current) + return; + let rows = 0; + while (!this.board.collides(this.current.type, this.current.rotation, { + x: this.current.pos.x, + y: this.current.pos.y + 1, + })) { + this.current.pos.y++; + rows++; + } + this.score.score += rows * 2; + this.lockPiece(); + } + hold() { + if (!this.current || this.holdLocked) + return; + const currentType = this.current.type; + if (this.holdType) { + // Swap + const pos = this.board.spawnPosition(this.holdType); + this.current = { type: this.holdType, rotation: 0, pos }; + this.holdType = currentType; + } + else { + this.holdType = currentType; + this.spawnPiece(); + } + this.holdLocked = true; + this.isLocking = false; + this.lockResets = 0; + } + applyGravity(now) { + if (!this.current) + return; + const below = { + x: this.current.pos.x, + y: this.current.pos.y + 1, + }; + if (!this.board.collides(this.current.type, this.current.rotation, below)) { + this.current.pos.y++; + this.isLocking = false; + } + else if (!this.isLocking) { + // Start lock delay + this.isLocking = true; + this.lockTimer = now; + } + } + resetLockDelay() { + if (this.isLocking && this.lockResets < MAX_LOCK_RESETS) { + this.lockTimer = performance.now(); + this.lockResets++; + } + // If piece is no longer on a surface, cancel lock + if (this.current && + !this.board.collides(this.current.type, this.current.rotation, { + x: this.current.pos.x, + y: this.current.pos.y + 1, + })) { + this.isLocking = false; + } + } + lockPiece() { + if (!this.current) + return; + this.board.lock(this.current); + const cleared = this.board.clearLines(); + if (cleared > 0) { + this.score.lines += cleared; + this.score.score += LINE_SCORES[cleared] * this.score.level; + this.score.level = Math.floor(this.score.lines / 10) + 1; + } + this.holdLocked = false; + this.isLocking = false; + if (this.board.isTopOut()) { + this.gameOver(); + return; + } + this.spawnPiece(); + } + // ── State ─────────────────────────────────────────────────────── + togglePause() { + if (this.state === "playing" /* GameState.Playing */) { + this.state = "paused" /* GameState.Paused */; + cancelAnimationFrame(this.rafId); + this.renderer.showMessage("PAUSED — press P to resume"); + } + else if (this.state === "paused" /* GameState.Paused */) { + this.state = "playing" /* GameState.Playing */; + this.lastDrop = performance.now(); + this.renderer.showMessage(""); + this.rafId = requestAnimationFrame(this.loop); + } + } + gameOver() { + this.state = "over" /* GameState.Over */; + cancelAnimationFrame(this.rafId); + this.render(); + this.renderer.showMessage(`GAME OVER — Score: ${this.score.score.toLocaleString()}\nPress Enter to restart`); + } + render() { + const ghostY = this.current ? this.board.ghostY(this.current) : null; + this.renderer.draw(this.board.visibleGrid(), this.current, ghostY, this.nextType, this.holdType, this.score, this.holdLocked); + } +} +//# sourceMappingURL=game.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js.map b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js.map @@ -0,0 +1 @@ +{"version":3,"file":"game.js","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/main.js b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/main.js @@ -0,0 +1,19 @@ +// ── Entry Point ───────────────────────────────────────────────────── +import { Board } from "./board.js"; +import { Renderer } from "./renderer.js"; +import { Game } from "./game.js"; +function $(id) { + const el = document.getElementById(id); + if (!el) + throw new Error(`Missing element #${id}`); + return el; +} +document.addEventListener("DOMContentLoaded", () => { + const board = new Board(); + const renderer = new Renderer($("game-canvas"), $("next-canvas"), $("hold-canvas"), $("score-value"), $("level-value"), $("lines-value"), $("message-overlay")); + const game = new Game(board, renderer); + document.addEventListener("keydown", (e) => game.handleKeyDown(e)); + document.addEventListener("keyup", (e) => game.handleKeyUp(e)); + renderer.showMessage("Press Enter or Space to start"); +}); +//# sourceMappingURL=main.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/main.js.map b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/main.js.map @@ -0,0 +1 @@ +{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAEvE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,SAAS,CAAC,CAAC,EAAU;IACnB,MAAM,EAAE,GAAG,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC;IACnD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;IACjD,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAC3B,CAAC,CAAC,aAAa,CAAsB,EACrC,CAAC,CAAC,aAAa,CAAsB,EACrC,CAAC,CAAC,aAAa,CAAsB,EACrC,CAAC,CAAC,aAAa,CAAC,EAChB,CAAC,CAAC,aAAa,CAAC,EAChB,CAAC,CAAC,aAAa,CAAC,EAChB,CAAC,CAAC,iBAAiB,CAAC,CACrB,CAAC;IAEF,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAEvC,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/D,QAAQ,CAAC,WAAW,CAAC,+BAA+B,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/pieces.js b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/pieces.js @@ -0,0 +1,221 @@ +// ── Tetromino Definitions with SRS Rotation States ────────────────── +/** + * Each piece has 4 rotation states (0 = spawn, 1 = R, 2 = 2, 3 = L). + * Shapes are stored as row-major 2D arrays where 1 = filled. + */ +export const TETROMINOES = [ + { + name: "I", + color: "#00f0f0", + shapes: [ + [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + [ + [0, 0, 1, 0], + [0, 0, 1, 0], + [0, 0, 1, 0], + [0, 0, 1, 0], + ], + [ + [0, 0, 0, 0], + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + ], + [ + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0], + ], + ], + }, + { + name: "O", + color: "#f0f000", + shapes: [ + [ + [1, 1], + [1, 1], + ], + [ + [1, 1], + [1, 1], + ], + [ + [1, 1], + [1, 1], + ], + [ + [1, 1], + [1, 1], + ], + ], + }, + { + name: "T", + color: "#a000f0", + shapes: [ + [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + [ + [0, 1, 0], + [0, 1, 1], + [0, 1, 0], + ], + [ + [0, 0, 0], + [1, 1, 1], + [0, 1, 0], + ], + [ + [0, 1, 0], + [1, 1, 0], + [0, 1, 0], + ], + ], + }, + { + name: "S", + color: "#00f000", + shapes: [ + [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + [ + [0, 1, 0], + [0, 1, 1], + [0, 0, 1], + ], + [ + [0, 0, 0], + [0, 1, 1], + [1, 1, 0], + ], + [ + [1, 0, 0], + [1, 1, 0], + [0, 1, 0], + ], + ], + }, + { + name: "Z", + color: "#f00000", + shapes: [ + [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + [ + [0, 0, 1], + [0, 1, 1], + [0, 1, 0], + ], + [ + [0, 0, 0], + [1, 1, 0], + [0, 1, 1], + ], + [ + [0, 1, 0], + [1, 1, 0], + [1, 0, 0], + ], + ], + }, + { + name: "J", + color: "#0000f0", + shapes: [ + [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + [ + [0, 1, 1], + [0, 1, 0], + [0, 1, 0], + ], + [ + [0, 0, 0], + [1, 1, 1], + [0, 0, 1], + ], + [ + [0, 1, 0], + [0, 1, 0], + [1, 1, 0], + ], + ], + }, + { + name: "L", + color: "#f0a000", + shapes: [ + [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], + [ + [0, 1, 0], + [0, 1, 0], + [0, 1, 1], + ], + [ + [0, 0, 0], + [1, 1, 1], + [1, 0, 0], + ], + [ + [1, 1, 0], + [0, 1, 0], + [0, 1, 0], + ], + ], + }, +]; +// ── SRS Wall Kick Data ────────────────────────────────────────────── +/** Wall kick offsets for J, L, S, T, Z pieces. Key: "from->to" rotation */ +const JLSTZ_KICKS = { + "0->1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1->0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1->2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2->1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2->3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3->2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3->0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0->3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +/** Wall kick offsets for I piece */ +const I_KICKS = { + "0->1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1->0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1->2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2->1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2->3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3->2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3->0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0->3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +export function getWallKicks(pieceName, fromRot, toRot) { + const key = `${fromRot}->${toRot}`; + if (pieceName === "I") + return I_KICKS[key] ?? [[0, 0]]; + if (pieceName === "O") + return [[0, 0]]; + return JLSTZ_KICKS[key] ?? [[0, 0]]; +} +//# sourceMappingURL=pieces.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/pieces.js.map b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/pieces.js.map @@ -0,0 +1 @@ +{"version":3,"file":"pieces.js","sourceRoot":"","sources":["../src/pieces.ts"],"names":[],"mappings":"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AAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;CACpD,CAAC;AAEF,MAAM,UAAU,YAAY,CAC1B,SAAiB,EACjB,OAAe,EACf,KAAa;IAEb,MAAM,GAAG,GAAG,GAAG,OAAO,KAAK,KAAK,EAAE,CAAC;IACnC,IAAI,SAAS,KAAK,GAAG;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACvD,IAAI,SAAS,KAAK,GAAG;QAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACvC,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACtC,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/renderer.js b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/renderer.js @@ -0,0 +1,150 @@ +// ── Canvas Renderer ───────────────────────────────────────────────── +import { COLS, ROWS } from "./board.js"; +const CELL = 30; // pixels per cell +const GRID_LINE = 0.5; +const BORDER = 2; +const NEXT_CELL = 22; // cell size in next-piece preview +export class Renderer { + constructor(canvas, nextCanvas, holdCanvas, scoreEl, levelEl, linesEl, messageEl) { + canvas.width = COLS * CELL; + canvas.height = ROWS * CELL; + this.ctx = canvas.getContext("2d"); + nextCanvas.width = 4 * NEXT_CELL + 20; + nextCanvas.height = 4 * NEXT_CELL + 20; + this.nextCtx = nextCanvas.getContext("2d"); + holdCanvas.width = 4 * NEXT_CELL + 20; + holdCanvas.height = 4 * NEXT_CELL + 20; + this.holdCtx = holdCanvas.getContext("2d"); + this.scoreEl = scoreEl; + this.levelEl = levelEl; + this.linesEl = linesEl; + this.messageEl = messageEl; + } + draw(grid, piece, ghostY, nextPiece, holdPiece, score, holdLocked) { + this.drawBoard(grid, piece, ghostY); + this.drawPreview(this.nextCtx, nextPiece); + this.drawPreview(this.holdCtx, holdPiece, holdLocked); + this.scoreEl.textContent = score.score.toLocaleString(); + this.levelEl.textContent = String(score.level); + this.linesEl.textContent = String(score.lines); + } + showMessage(text) { + this.messageEl.textContent = text; + this.messageEl.style.display = text ? "flex" : "none"; + } + drawBoard(grid, piece, ghostY) { + const ctx = this.ctx; + const w = COLS * CELL; + const h = ROWS * CELL; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, w, h); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = GRID_LINE; + for (let c = 1; c < COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, h); + ctx.stroke(); + } + for (let r = 1; r < ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(w, r * CELL); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const color = grid[r][c]; + if (color) + this.drawCell(ctx, c, r, color, 1); + } + } + if (piece) { + const shape = piece.type.shapes[piece.rotation]; + const bufferRows = 4; // piece coords are in the full 24-row space; grid here is the visible 20 rows + // Ghost piece + if (ghostY !== null) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const drawY = ghostY + r - bufferRows; + const drawX = piece.pos.x + c; + if (drawY >= 0 && drawY < ROWS && drawX >= 0 && drawX < COLS) { + this.drawCell(ctx, drawX, drawY, piece.type.color, 0.2); + } + } + } + } + // Active piece + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const drawY = piece.pos.y + r - bufferRows; + const drawX = piece.pos.x + c; + if (drawY >= 0 && drawY < ROWS && drawX >= 0 && drawX < COLS) { + this.drawCell(ctx, drawX, drawY, piece.type.color, 1); + } + } + } + } + // Border + ctx.strokeStyle = "#555"; + ctx.lineWidth = BORDER; + ctx.strokeRect(0, 0, w, h); + } + drawCell(ctx, col, row, color, alpha) { + const x = col * CELL; + const y = row * CELL; + const inset = 1; + ctx.globalAlpha = alpha; + // Main fill + ctx.fillStyle = color; + ctx.fillRect(x + inset, y + inset, CELL - inset * 2, CELL - inset * 2); + // Highlight (top-left bevel) + ctx.fillStyle = "rgba(255,255,255,0.3)"; + ctx.fillRect(x + inset, y + inset, CELL - inset * 2, 3); + ctx.fillRect(x + inset, y + inset, 3, CELL - inset * 2); + // Shadow (bottom-right bevel) + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(x + inset, y + CELL - inset - 3, CELL - inset * 2, 3); + ctx.fillRect(x + CELL - inset - 3, y + inset, 3, CELL - inset * 2); + ctx.globalAlpha = 1; + } + drawPreview(ctx, type, dimmed = false) { + const w = ctx.canvas.width; + const h = ctx.canvas.height; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, w, h); + ctx.strokeStyle = "#333"; + ctx.lineWidth = 1; + ctx.strokeRect(0, 0, w, h); + if (!type) + return; + const shape = type.shapes[0]; + const rows = shape.length; + const cols = shape[0].length; + const offsetX = (w - cols * NEXT_CELL) / 2; + const offsetY = (h - rows * NEXT_CELL) / 2; + ctx.globalAlpha = dimmed ? 0.35 : 1; + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (!shape[r][c]) + continue; + const x = offsetX + c * NEXT_CELL; + const y = offsetY + r * NEXT_CELL; + ctx.fillStyle = type.color; + ctx.fillRect(x + 1, y + 1, NEXT_CELL - 2, NEXT_CELL - 2); + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x + 1, y + 1, NEXT_CELL - 2, 2); + ctx.fillRect(x + 1, y + 1, 2, NEXT_CELL - 2); + } + } + ctx.globalAlpha = 1; + } +} +//# sourceMappingURL=renderer.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/renderer.js.map b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/renderer.js.map @@ -0,0 +1 @@ +{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/types.js b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/types.js @@ -0,0 +1,3 @@ +// ── Type Definitions ──────────────────────────────────────────────── +export {}; +//# sourceMappingURL=types.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/types.js.map b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,uEAAuE"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,509 @@ +"use strict"; +// ── Types ────────────────────────────────────────────────────────────────────── +// ── Constants ────────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 32; +const PREVIEW_BLOCK = 24; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const GHOST_ALPHA = 0.25; +// Each shape is an array of rotations (0°, 90°, 180°, 270°). +// 1 = filled cell; coordinates are [row][col]. +const SHAPES = { + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + O: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +// SRS wall‑kick data (non‑I pieces) +const WALL_KICKS = { + "0>1": [{ x: 0, y: 0 }, { x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "1>0": [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], + "1>2": [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], + "2>1": [{ x: 0, y: 0 }, { x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "2>3": [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: -1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], + "3>2": [{ x: 0, y: 0 }, { x: -1, y: 0 }, { x: -1, y: 1 }, { x: 0, y: -2 }, { x: -1, y: -2 }], + "3>0": [{ x: 0, y: 0 }, { x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "0>3": [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], +}; +// SRS wall‑kick data for I piece +const WALL_KICKS_I = { + "0>1": [{ x: 0, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 1 }, { x: 1, y: -2 }], + "1>0": [{ x: 0, y: 0 }, { x: 2, y: 0 }, { x: -1, y: 0 }, { x: 2, y: -1 }, { x: -1, y: 2 }], + "1>2": [{ x: 0, y: 0 }, { x: -1, y: 0 }, { x: 2, y: 0 }, { x: -1, y: -2 }, { x: 2, y: 1 }], + "2>1": [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 2 }, { x: -2, y: -1 }], + "2>3": [{ x: 0, y: 0 }, { x: 2, y: 0 }, { x: -1, y: 0 }, { x: 2, y: -1 }, { x: -1, y: 2 }], + "3>2": [{ x: 0, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 1 }, { x: 1, y: -2 }], + "3>0": [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 2 }, { x: -2, y: -1 }], + "0>3": [{ x: 0, y: 0 }, { x: -1, y: 0 }, { x: 2, y: 0 }, { x: -1, y: -2 }, { x: 2, y: 1 }], +}; +// Points per lines cleared (original Nintendo scoring × level) +const LINE_POINTS = [0, 100, 300, 500, 800]; +// Frames per gravity tick at each level (simplified curve) +function gravityDelay(level) { + const delays = [800, 720, 630, 550, 470, 380, 300, 220, 140, 100, 80, 80, 80, 70, 70, 70, 50, 50, 50, 30]; + return delays[Math.min(level, delays.length - 1)]; +} +// ── Bag randomiser ───────────────────────────────────────────────────────────── +const PIECE_NAMES = Object.keys(SHAPES); // I O T S Z J L +function shuffledBag() { + const bag = [...PIECE_NAMES]; + for (let i = bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [bag[i], bag[j]] = [bag[j], bag[i]]; + } + return bag; +} +// ── Game state ───────────────────────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + // Current piece state + this.currentName = ""; + this.currentRotation = 0; + this.currentPos = { x: 0, y: 0 }; + // Piece queue + this.bag = []; + this.nextName = ""; + // Timing + this.lastTick = 0; + this.lockDelay = 0; + this.lockLimit = 500; // ms before lock + this.moveResetCount = 0; + this.maxMoveResets = 15; + this.animId = 0; + // Line‑clear animation + this.clearingRows = []; + this.clearTimer = 0; + this.clearDuration = 300; // ms + // ── Input ────────────────────────────────────────────────────────────────── + this.onKey = (e) => { + if (e.key === "r" || e.key === "R") { + this.restart(); + return; + } + if (this.gameOver) + return; + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.paused = !this.paused; + if (this.paused) { + this.overlayEl.textContent = "PAUSED"; + this.overlayEl.classList.add("visible"); + } + else { + this.overlayEl.classList.remove("visible"); + this.lastTick = performance.now(); + } + return; + } + if (this.paused) + return; + switch (e.key) { + case "ArrowLeft": + this.move(-1, 0); + break; + case "ArrowRight": + this.move(1, 0); + break; + case "ArrowDown": + if (this.move(0, 1)) + this.score += 1; + this.lockDelay = 0; + break; + case "ArrowUp": + this.rotate(1); + break; + case "z": + case "Z": + this.rotate(-1); + break; + case " ": + this.hardDrop(); + break; + } + e.preventDefault(); + }; + // ── Game loop ────────────────────────────────────────────────────────────── + this.loop = (now) => { + this.animId = requestAnimationFrame(this.loop); + if (this.gameOver || this.paused) { + this.draw(now); + return; + } + // Line‑clear animation in progress + if (this.clearingRows.length > 0) { + if (now - this.clearTimer >= this.clearDuration) { + this.finishClear(); + } + this.draw(now); + return; + } + const delay = gravityDelay(this.level); + if (now - this.lastTick >= delay) { + if (!this.move(0, 1)) { + this.lockDelay += now - this.lastTick; + if (this.lockDelay >= this.lockLimit) { + this.lock(); + } + } + else { + this.lockDelay = 0; + } + this.lastTick = now; + } + // Extra lock check if sitting on ground + if (this.isOnGround() && this.clearingRows.length === 0 && !this.gameOver) { + this.lockDelay += now - this.lastTick; + } + this.draw(now); + }; + this.canvas = document.getElementById("board"); + this.ctx = this.canvas.getContext("2d"); + this.canvas.width = COLS * BLOCK_SIZE; + this.canvas.height = ROWS * BLOCK_SIZE; + this.previewCanvas = document.getElementById("preview"); + this.previewCtx = this.previewCanvas.getContext("2d"); + this.previewCanvas.width = 4 * PREVIEW_BLOCK; + this.previewCanvas.height = 4 * PREVIEW_BLOCK; + this.scoreEl = document.getElementById("score"); + this.linesEl = document.getElementById("lines"); + this.levelEl = document.getElementById("level"); + this.overlayEl = document.getElementById("overlay"); + this.grid = this.emptyGrid(); + this.fillBag(); + this.nextName = this.pullPiece(); + this.spawnPiece(); + document.addEventListener("keydown", this.onKey); + this.lastTick = performance.now(); + this.animId = requestAnimationFrame(this.loop); + } + // ── Grid helpers ─────────────────────────────────────────────────────────── + emptyGrid() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); + } + shape() { + return SHAPES[this.currentName][this.currentRotation]; + } + collides(name, rotation, pos) { + const s = SHAPES[name][rotation]; + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const nx = pos.x + c; + const ny = pos.y + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && this.grid[ny][nx] !== null) + return true; + } + } + return false; + } + // ── Piece management ─────────────────────────────────────────────────────── + fillBag() { + if (this.bag.length <= 7) { + this.bag = this.bag.concat(shuffledBag()); + } + } + pullPiece() { + this.fillBag(); + return this.bag.shift(); + } + spawnPiece() { + this.currentName = this.nextName; + this.nextName = this.pullPiece(); + this.currentRotation = 0; + const s = this.shape(); + this.currentPos = { + x: Math.floor((COLS - s[0].length) / 2), + y: -1, + }; + this.lockDelay = 0; + this.moveResetCount = 0; + if (this.collides(this.currentName, this.currentRotation, this.currentPos)) { + this.gameOver = true; + this.overlayEl.textContent = "GAME OVER — Press R to restart"; + this.overlayEl.classList.add("visible"); + } + } + lock() { + const s = this.shape(); + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const x = this.currentPos.x + c; + const y = this.currentPos.y + r; + if (y < 0) { + this.gameOver = true; + this.overlayEl.textContent = "GAME OVER — Press R to restart"; + this.overlayEl.classList.add("visible"); + return; + } + this.grid[y][x] = this.currentName; + } + } + this.checkLines(); + } + // ── Line clearing ───────────────────────────────────────────────────────── + checkLines() { + const full = []; + for (let r = 0; r < ROWS; r++) { + if (this.grid[r].every((c) => c !== null)) + full.push(r); + } + if (full.length > 0) { + this.clearingRows = full; + this.clearTimer = performance.now(); + } + else { + this.spawnPiece(); + } + } + finishClear() { + const count = this.clearingRows.length; + // Remove rows top‑down and add empty rows at top + for (const row of this.clearingRows.sort((a, b) => b - a)) { + this.grid.splice(row, 1); + this.grid.unshift(Array(COLS).fill(null)); + } + this.lines += count; + this.score += LINE_POINTS[count] * (this.level + 1); + this.level = Math.floor(this.lines / 10); + this.clearingRows = []; + this.spawnPiece(); + } + // ── Movement & rotation ──────────────────────────────────────────────────── + move(dx, dy) { + const np = { x: this.currentPos.x + dx, y: this.currentPos.y + dy }; + if (!this.collides(this.currentName, this.currentRotation, np)) { + this.currentPos = np; + if (dy === 0 && this.moveResetCount < this.maxMoveResets && this.isOnGround()) { + this.lockDelay = 0; + this.moveResetCount++; + } + return true; + } + return false; + } + rotate(dir) { + const from = this.currentRotation; + const to = (from + dir + 4) % 4; + const key = `${from}>${to}`; + const kicks = this.currentName === "I" ? WALL_KICKS_I[key] : WALL_KICKS[key]; + if (!kicks) + return; + for (const k of kicks) { + const np = { x: this.currentPos.x + k.x, y: this.currentPos.y - k.y }; + if (!this.collides(this.currentName, to, np)) { + this.currentRotation = to; + this.currentPos = np; + if (this.moveResetCount < this.maxMoveResets && this.isOnGround()) { + this.lockDelay = 0; + this.moveResetCount++; + } + return; + } + } + } + hardDrop() { + let dropped = 0; + while (this.move(0, 1)) + dropped++; + this.score += dropped * 2; + this.lock(); + } + ghostY() { + let gy = this.currentPos.y; + while (!this.collides(this.currentName, this.currentRotation, { x: this.currentPos.x, y: gy + 1 })) { + gy++; + } + return gy; + } + isOnGround() { + return this.collides(this.currentName, this.currentRotation, { + x: this.currentPos.x, + y: this.currentPos.y + 1, + }); + } + // ── Rendering ────────────────────────────────────────────────────────────── + draw(now) { + const ctx = this.ctx; + const bs = BLOCK_SIZE; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let x = 0; x <= COLS; x++) { + ctx.beginPath(); + ctx.moveTo(x * bs, 0); + ctx.lineTo(x * bs, ROWS * bs); + ctx.stroke(); + } + for (let y = 0; y <= ROWS; y++) { + ctx.beginPath(); + ctx.moveTo(0, y * bs); + ctx.lineTo(COLS * bs, y * bs); + ctx.stroke(); + } + // Locked blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const cell = this.grid[r][c]; + if (cell) { + // Flash clearing rows + if (this.clearingRows.includes(r)) { + const t = (now - this.clearTimer) / this.clearDuration; + const flash = Math.floor(t * 6) % 2 === 0; + ctx.fillStyle = flash ? "#fff" : COLORS[cell]; + } + else { + ctx.fillStyle = COLORS[cell]; + } + this.drawBlock(ctx, c, r, bs); + } + } + } + if (!this.gameOver && this.clearingRows.length === 0) { + // Ghost piece + const gy = this.ghostY(); + const s = this.shape(); + ctx.globalAlpha = GHOST_ALPHA; + ctx.fillStyle = COLORS[this.currentName]; + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const x = this.currentPos.x + c; + const y = gy + r; + if (y >= 0) + this.drawBlock(ctx, x, y, bs); + } + } + ctx.globalAlpha = 1; + // Current piece + ctx.fillStyle = COLORS[this.currentName]; + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const x = this.currentPos.x + c; + const y = this.currentPos.y + r; + if (y >= 0) + this.drawBlock(ctx, x, y, bs); + } + } + } + // Preview + this.drawPreview(); + // HUD + this.scoreEl.textContent = String(this.score); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + } + drawBlock(ctx, col, row, size) { + const x = col * size; + const y = row * size; + ctx.fillRect(x + 1, y + 1, size - 2, size - 2); + // Highlight + ctx.save(); + ctx.globalAlpha = Math.min(ctx.globalAlpha, 0.35); + ctx.fillStyle = "#fff"; + ctx.fillRect(x + 1, y + 1, size - 2, 4); + ctx.fillRect(x + 1, y + 1, 4, size - 2); + ctx.restore(); + } + drawPreview() { + const ctx = this.previewCtx; + const bs = PREVIEW_BLOCK; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, this.previewCanvas.width, this.previewCanvas.height); + const s = SHAPES[this.nextName][0]; + const offX = (4 - s[0].length) / 2; + const offY = (4 - s.length) / 2; + ctx.fillStyle = COLORS[this.nextName]; + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const x = (offX + c) * bs; + const y = (offY + r) * bs; + ctx.fillRect(x + 1, y + 1, bs - 2, bs - 2); + } + } + } + // ── Restart ──────────────────────────────────────────────────────────────── + restart() { + this.grid = this.emptyGrid(); + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + this.clearingRows = []; + this.bag = []; + this.fillBag(); + this.nextName = this.pullPiece(); + this.overlayEl.classList.remove("visible"); + this.spawnPiece(); + this.lastTick = performance.now(); + } +} +// ── Bootstrap ────────────────────────────────────────────────────────────────── +window.addEventListener("DOMContentLoaded", () => { + new TetrisGame(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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C,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;IACD,CAAC,EAAE;QACD,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC;KAC1B;CACF,CAAC;AAEF,oCAAoC;AACpC,MAAM,UAAU,GAA+B;IAC7C,KAAK,EAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC;IAC9D,KAAK,EAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC;IAC5D,KAAK,EAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC;IAC5D,KAAK,EAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC;IAC9D,KAAK,EAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC;IAC3D,KAAK,EAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC;IAC/D,KAAK,EAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC;IAC9D,KAAK,EAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC;CAC7D,CAAC;AAEF,iCAAiC;AACjC,MAAM,YAAY,GAA+B;IAC/C,KAAK,EAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC;IAC7D,KAAK,EAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC;IAC7D,KAAK,EAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC;IAC7D,KAAK,EAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC;IAC7D,KAAK,EAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC;IAC7D,KAAK,EAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAC,CAAC;IAC7D,KAAK,EAAE,CAAC,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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,406 @@ +"use strict"; +// ─── Types ────────────────────────────────────────────────────────────────── +// ─── Constants ─────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; +const COLORS = { + 1: "#00f0f0", // I – cyan + 2: "#0000f0", // J – blue + 3: "#f0a000", // L – orange + 4: "#f0f000", // O – yellow + 5: "#00f000", // S – green + 6: "#a000f0", // T – purple + 7: "#f00000", // Z – red +}; +const PIECES = [ + // I + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + // J + [[2, 0, 0], [2, 2, 2], [0, 0, 0]], + // L + [[0, 0, 3], [3, 3, 3], [0, 0, 0]], + // O + [[4, 4], [4, 4]], + // S + [[0, 5, 5], [5, 5, 0], [0, 0, 0]], + // T + [[0, 6, 0], [6, 6, 6], [0, 0, 0]], + // Z + [[7, 7, 0], [0, 7, 7], [0, 0, 0]], +]; +// Scoring per number of lines cleared simultaneously (Tetris classic) +const LINE_SCORES = [0, 100, 300, 500, 800]; +// Speed in ms per drop (decreases every 10 lines) +function dropInterval(level) { + return Math.max(80, 1000 - level * 80); +} +// ─── Helpers ───────────────────────────────────────────────────────────────── +function rotate(matrix, dir) { + const N = matrix.length; + const result = Array.from({ length: N }, () => Array(N).fill(0)); + for (let r = 0; r < N; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (dir === 1) { + result[c][N - 1 - r] = matrix[r][c]; + } + else { + result[N - 1 - c][r] = matrix[r][c]; + } + } + } + return result; +} +function randomPiece() { + const idx = Math.floor(Math.random() * PIECES.length); + const matrix = PIECES[idx].map((row) => [...row]); + return { + matrix, + pos: { x: Math.floor(COLS / 2) - Math.floor(matrix[0].length / 2), y: 0 }, + color: COLORS[idx + 1], + }; +} +function cloneMatrix(m) { + return m.map((row) => [...row]); +} +// ─── Game ──────────────────────────────────────────────────────────────────── +class Tetris { + constructor() { + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + this.lastTime = 0; + this.dropAccum = 0; + this.animId = 0; + // Ghost piece drop row + this.ghostY = 0; + this.canvas = document.getElementById("board"); + this.ctx = this.canvas.getContext("2d"); + this.nextCanvas = document.getElementById("next"); + this.nextCtx = this.nextCanvas.getContext("2d"); + this.canvas.width = COLS * BLOCK; + this.canvas.height = ROWS * BLOCK; + this.nextCanvas.width = 4 * BLOCK; + this.nextCanvas.height = 4 * BLOCK; + this.board = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); + this.bindKeys(); + this.reset(); + } + // ── Reset / Start ─────────────────────────────────────────────────────── + reset() { + this.board = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); + this.score = 0; + this.lines = 0; + this.level = 0; + this.gameOver = false; + this.paused = false; + this.lastTime = 0; + this.dropAccum = 0; + this.next = randomPiece(); + this.spawnPiece(); + this.updateUI(); + cancelAnimationFrame(this.animId); + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + spawnPiece() { + this.current = this.next; + this.next = randomPiece(); + this.computeGhost(); + // Collision immediately → game over + if (this.collides(this.current.matrix, this.current.pos)) { + this.gameOver = true; + } + } + // ── Collision ─────────────────────────────────────────────────────────── + collides(matrix, pos) { + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (!matrix[r][c]) + continue; + const nx = pos.x + c; + const ny = pos.y + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && this.board[ny][nx]) + return true; + } + } + return false; + } + // ── Ghost piece ───────────────────────────────────────────────────────── + computeGhost() { + let y = this.current.pos.y; + while (!this.collides(this.current.matrix, { x: this.current.pos.x, y: y + 1 })) { + y++; + } + this.ghostY = y; + } + // ── Movement ──────────────────────────────────────────────────────────── + moveLeft() { + const pos = { x: this.current.pos.x - 1, y: this.current.pos.y }; + if (!this.collides(this.current.matrix, pos)) { + this.current.pos = pos; + this.computeGhost(); + } + } + moveRight() { + const pos = { x: this.current.pos.x + 1, y: this.current.pos.y }; + if (!this.collides(this.current.matrix, pos)) { + this.current.pos = pos; + this.computeGhost(); + } + } + softDrop() { + this.dropAccum = 0; + this.drop(); + this.score += 1; + this.updateUI(); + } + hardDrop() { + const dist = this.ghostY - this.current.pos.y; + this.current.pos.y = this.ghostY; + this.score += dist * 2; + this.lock(); + this.updateUI(); + } + rotatePiece(dir) { + const rotated = rotate(this.current.matrix, dir); + // Wall-kick offsets to try + const kicks = [0, -1, 1, -2, 2]; + for (const kick of kicks) { + const pos = { x: this.current.pos.x + kick, y: this.current.pos.y }; + if (!this.collides(rotated, pos)) { + this.current.matrix = rotated; + this.current.pos = pos; + this.computeGhost(); + return; + } + } + } + // ── Drop / Lock ───────────────────────────────────────────────────────── + drop() { + const pos = { x: this.current.pos.x, y: this.current.pos.y + 1 }; + if (!this.collides(this.current.matrix, pos)) { + this.current.pos = pos; + } + else { + this.lock(); + } + } + lock() { + const { matrix, pos } = this.current; + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (!matrix[r][c]) + continue; + const ny = pos.y + r; + const nx = pos.x + c; + if (ny < 0) { + this.gameOver = true; + return; + } + this.board[ny][nx] = matrix[r][c]; + } + } + this.clearLines(); + this.spawnPiece(); + } + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every((c) => c !== 0)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(0)); + cleared++; + r++; // re-check same row index after splice + } + } + if (cleared > 0) { + this.lines += cleared; + this.level = Math.floor(this.lines / 10); + this.score += LINE_SCORES[Math.min(cleared, 4)] * (this.level + 1); + this.updateUI(); + } + } + // ── Render ────────────────────────────────────────────────────────────── + drawBlock(ctx, x, y, color, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * BLOCK + 1, y * BLOCK + 1, BLOCK - 2, BLOCK - 2); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x * BLOCK + 1, y * BLOCK + 1, BLOCK - 2, 4); + ctx.fillRect(x * BLOCK + 1, y * BLOCK + 1, 4, BLOCK - 2); + // Shadow edge + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(x * BLOCK + 1, y * BLOCK + BLOCK - 5, BLOCK - 2, 4); + ctx.fillRect(x * BLOCK + BLOCK - 5, y * BLOCK + 1, 4, BLOCK - 2); + ctx.globalAlpha = 1; + } + drawBoard() { + const ctx = this.ctx; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.05)"; + ctx.lineWidth = 0.5; + for (let r = 0; r < ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(COLS * BLOCK, r * BLOCK); + ctx.stroke(); + } + for (let c = 0; c < COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, ROWS * BLOCK); + ctx.stroke(); + } + // Locked blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const v = this.board[r][c]; + if (v) + this.drawBlock(ctx, c, r, COLORS[v]); + } + } + } + drawGhost() { + const { matrix, pos } = this.current; + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (!matrix[r][c]) + continue; + this.drawBlock(this.ctx, pos.x + c, this.ghostY + r, this.current.color, 0.2); + } + } + } + drawPiece() { + const { matrix, pos, color } = this.current; + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (!matrix[r][c]) + continue; + this.drawBlock(this.ctx, pos.x + c, pos.y + r, color); + } + } + } + drawNext() { + const ctx = this.nextCtx; + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, this.nextCanvas.width, this.nextCanvas.height); + const { matrix, color } = this.next; + const offsetX = Math.floor((4 - matrix[0].length) / 2); + const offsetY = Math.floor((4 - matrix.length) / 2); + for (let r = 0; r < matrix.length; r++) { + for (let c = 0; c < matrix[r].length; c++) { + if (!matrix[r][c]) + continue; + this.drawBlock(ctx, offsetX + c, offsetY + r, color); + } + } + } + drawOverlay() { + const ctx = this.ctx; + ctx.fillStyle = "rgba(0,0,0,0.65)"; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + ctx.fillStyle = "#fff"; + ctx.textAlign = "center"; + if (this.gameOver) { + ctx.font = "bold 36px monospace"; + ctx.fillText("GAME OVER", this.canvas.width / 2, this.canvas.height / 2 - 20); + ctx.font = "18px monospace"; + ctx.fillText("Press R to restart", this.canvas.width / 2, this.canvas.height / 2 + 20); + } + else if (this.paused) { + ctx.font = "bold 36px monospace"; + ctx.fillText("PAUSED", this.canvas.width / 2, this.canvas.height / 2 - 20); + ctx.font = "18px monospace"; + ctx.fillText("Press P to resume", this.canvas.width / 2, this.canvas.height / 2 + 20); + } + } + render() { + this.drawBoard(); + if (!this.gameOver) { + this.drawGhost(); + this.drawPiece(); + } + this.drawNext(); + if (this.gameOver || this.paused) { + this.drawOverlay(); + } + } + // ── Game loop ─────────────────────────────────────────────────────────── + loop(time) { + const delta = time - this.lastTime; + this.lastTime = time; + if (!this.paused && !this.gameOver) { + this.dropAccum += delta; + if (this.dropAccum >= dropInterval(this.level)) { + this.dropAccum = 0; + this.drop(); + } + } + this.render(); + this.animId = requestAnimationFrame((t) => this.loop(t)); + } + // ── UI ────────────────────────────────────────────────────────────────── + updateUI() { + document.getElementById("score").textContent = String(this.score); + document.getElementById("lines").textContent = String(this.lines); + document.getElementById("level").textContent = String(this.level + 1); + } + // ── Input ─────────────────────────────────────────────────────────────── + bindKeys() { + document.addEventListener("keydown", (e) => { + if (e.key === "r" || e.key === "R") { + this.reset(); + return; + } + if (this.gameOver) + return; + if (e.key === "p" || e.key === "P") { + this.paused = !this.paused; + if (!this.paused) { + this.lastTime = performance.now(); + } + return; + } + if (this.paused) + return; + switch (e.key) { + case "ArrowLeft": + e.preventDefault(); + this.moveLeft(); + break; + case "ArrowRight": + e.preventDefault(); + this.moveRight(); + break; + case "ArrowDown": + e.preventDefault(); + this.softDrop(); + break; + case "ArrowUp": + e.preventDefault(); + this.rotatePiece(1); + break; + case "z": + case "Z": + this.rotatePiece(-1); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + } + }); + } +} +// ─── Bootstrap ──────────────────────────────────────────────────────────────── +window.addEventListener("DOMContentLoaded", () => { + new Tetris(); +}); diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,478 @@ +"use strict"; +// ───────────────────────────────────────────── +// Tetris – TypeScript / Canvas implementation +// ───────────────────────────────────────────── +// ── Constants ──────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 32; // px per cell +const PREVIEW_BLOCK = 24; // px for next-piece preview +// Drop-interval table (ms) indexed by level (capped at 29) +const SPEED_TABLE = [ + 800, 720, 630, 550, 470, 380, 300, 215, 130, 100, + 83, 83, 83, 67, 67, 67, 50, 50, 50, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 17, +]; +// Points awarded per lines-cleared, multiplied by level+1 +const LINE_POINTS = [0, 100, 300, 500, 800]; +const PIECES = [ + // I + { + color: '#00f0f0', + rotations: [ + [[0, 0], [0, 1], [0, 2], [0, 3]], + [[0, 2], [1, 2], [2, 2], [3, 2]], + [[2, 0], [2, 1], [2, 2], [2, 3]], + [[0, 1], [1, 1], [2, 1], [3, 1]], + ], + }, + // O + { + color: '#f0f000', + rotations: [ + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + [[0, 0], [0, 1], [1, 0], [1, 1]], + ], + }, + // T + { + color: '#a000f0', + rotations: [ + [[0, 1], [1, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [1, 2], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 1]], + [[0, 1], [1, 0], [1, 1], [2, 1]], + ], + }, + // S + { + color: '#00f000', + rotations: [ + [[0, 1], [0, 2], [1, 0], [1, 1]], + [[0, 1], [1, 1], [1, 2], [2, 2]], + [[1, 1], [1, 2], [2, 0], [2, 1]], + [[0, 0], [1, 0], [1, 1], [2, 1]], + ], + }, + // Z + { + color: '#f00000', + rotations: [ + [[0, 0], [0, 1], [1, 1], [1, 2]], + [[0, 2], [1, 1], [1, 2], [2, 1]], + [[1, 0], [1, 1], [2, 1], [2, 2]], + [[0, 1], [1, 0], [1, 1], [2, 0]], + ], + }, + // J + { + color: '#0000f0', + rotations: [ + [[0, 0], [1, 0], [1, 1], [1, 2]], + [[0, 1], [0, 2], [1, 1], [2, 1]], + [[1, 0], [1, 1], [1, 2], [2, 2]], + [[0, 1], [1, 1], [2, 0], [2, 1]], + ], + }, + // L + { + color: '#f0a000', + rotations: [ + [[0, 2], [1, 0], [1, 1], [1, 2]], + [[0, 1], [1, 1], [2, 1], [2, 2]], + [[1, 0], [1, 1], [1, 2], [2, 0]], + [[0, 0], [0, 1], [1, 1], [2, 1]], + ], + }, +]; +// ── Game class ──────────────────────────────── +class Tetris { + constructor() { + this.board = []; + this.active = null; + this.nextPieceIndex = 0; + this.score = 0; + this.lines = 0; + this.level = 0; + this.state = 'idle'; + this.lastDrop = 0; + this.animFrame = 0; + this.canvas = document.getElementById('game-canvas'); + this.ctx = this.canvas.getContext('2d'); + this.previewCanvas = document.getElementById('preview-canvas'); + this.previewCtx = this.previewCanvas.getContext('2d'); + this.scoreEl = document.getElementById('score'); + this.linesEl = document.getElementById('lines'); + this.levelEl = document.getElementById('level'); + this.messageEl = document.getElementById('message'); + this.canvas.width = COLS * BLOCK; + this.canvas.height = ROWS * BLOCK; + this.previewCanvas.width = 4 * PREVIEW_BLOCK; + this.previewCanvas.height = 4 * PREVIEW_BLOCK; + document.addEventListener('keydown', (e) => this.handleKey(e)); + document.getElementById('start-btn').addEventListener('click', () => this.startGame()); + this.drawIdle(); + } + // ── Initialise / start ──────────────────── + startGame() { + this.board = Array.from({ length: ROWS }, () => Array(COLS).fill(null)); + this.score = 0; + this.lines = 0; + this.level = 0; + this.state = 'playing'; + this.lastDrop = performance.now(); + this.nextPieceIndex = this.randomPieceIndex(); + this.updateLabels(); + this.setMessage(''); + this.spawnPiece(); + cancelAnimationFrame(this.animFrame); + this.loop(performance.now()); + } + // ── Random helpers ──────────────────────── + randomPieceIndex() { + return Math.floor(Math.random() * PIECES.length); + } + // ── Piece helpers ───────────────────────── + cells(piece) { + return PIECES[piece.pieceIndex].rotations[piece.rotation].map(([r, c]) => [r + piece.row, c + piece.col]); + } + isValid(piece) { + for (const [r, c] of this.cells(piece)) { + if (c < 0 || c >= COLS || r >= ROWS) + return false; + if (r >= 0 && this.board[r][c] !== null) + return false; + } + return true; + } + spawnPiece() { + const idx = this.nextPieceIndex; + this.nextPieceIndex = this.randomPieceIndex(); + this.active = { pieceIndex: idx, rotation: 0, row: 0, col: 3 }; + // I piece spawns one row higher to match standard Tetris + if (idx === 0) + this.active.col = 3; + if (!this.isValid(this.active)) { + this.gameOver(); + } + this.drawPreview(); + } + // ── Movement ────────────────────────────── + moveLeft() { + if (!this.active) + return; + const moved = { ...this.active, col: this.active.col - 1 }; + if (this.isValid(moved)) + this.active = moved; + } + moveRight() { + if (!this.active) + return; + const moved = { ...this.active, col: this.active.col + 1 }; + if (this.isValid(moved)) + this.active = moved; + } + softDrop() { + if (!this.active) + return; + const moved = { ...this.active, row: this.active.row + 1 }; + if (this.isValid(moved)) { + this.active = moved; + this.score += 1; + } + else { + this.lockPiece(); + } + this.lastDrop = performance.now(); + } + hardDrop() { + if (!this.active) + return; + let dropped = 0; + while (true) { + const current = this.active; + const moved = { ...current, row: current.row + 1 }; + if (this.isValid(moved)) { + this.active = moved; + dropped++; + } + else + break; + } + this.score += dropped * 2; + this.lockPiece(); + } + rotate(dir) { + if (!this.active) + return; + const numRots = PIECES[this.active.pieceIndex].rotations.length; + const newRot = ((this.active.rotation + dir) % numRots + numRots) % numRots; + const rotated = { ...this.active, rotation: newRot }; + // Wall-kick: try offsets [0, -1, +1, -2, +2] + for (const kick of [0, -1, 1, -2, 2]) { + const kicked = { ...rotated, col: rotated.col + kick }; + if (this.isValid(kicked)) { + this.active = kicked; + return; + } + } + } + // ── Locking & clearing ──────────────────── + lockPiece() { + if (!this.active) + return; + const color = PIECES[this.active.pieceIndex].color; + for (const [r, c] of this.cells(this.active)) { + if (r >= 0) + this.board[r][c] = color; + } + this.active = null; + this.clearLines(); + this.spawnPiece(); + } + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every(cell => cell !== null)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check same index + } + } + if (cleared > 0) { + this.score += LINE_POINTS[cleared] * (this.level + 1); + this.lines += cleared; + this.level = Math.floor(this.lines / 10); + this.updateLabels(); + } + } + // ── Game-over / pause ───────────────────── + gameOver() { + this.state = 'over'; + this.active = null; + cancelAnimationFrame(this.animFrame); + this.setMessage('GAME OVER'); + this.draw(); + } + togglePause() { + if (this.state === 'playing') { + this.state = 'paused'; + this.setMessage('PAUSED'); + cancelAnimationFrame(this.animFrame); + this.draw(); + } + else if (this.state === 'paused') { + this.state = 'playing'; + this.setMessage(''); + this.lastDrop = performance.now(); + this.loop(performance.now()); + } + } + // ── Main loop ───────────────────────────── + loop(timestamp) { + if (this.state !== 'playing') + return; + const interval = SPEED_TABLE[Math.min(this.level, SPEED_TABLE.length - 1)]; + if (timestamp - this.lastDrop >= interval) { + this.lastDrop = timestamp; + const moved = this.active ? { ...this.active, row: this.active.row + 1 } : null; + if (moved && this.isValid(moved)) { + this.active = moved; + } + else if (this.active) { + this.lockPiece(); + } + } + this.draw(); + this.animFrame = requestAnimationFrame((ts) => this.loop(ts)); + } + // ── Keyboard ────────────────────────────── + handleKey(e) { + if (this.state === 'idle') { + if (e.code === 'Enter' || e.code === 'Space') + this.startGame(); + return; + } + if (e.code === 'KeyP' || e.code === 'Escape') { + if (this.state === 'playing' || this.state === 'paused') + this.togglePause(); + return; + } + if (this.state === 'over') { + if (e.code === 'Enter' || e.code === 'Space') + this.startGame(); + return; + } + if (this.state !== 'playing') + return; + switch (e.code) { + case 'ArrowLeft': + e.preventDefault(); + this.moveLeft(); + break; + case 'ArrowRight': + e.preventDefault(); + this.moveRight(); + break; + case 'ArrowDown': + e.preventDefault(); + this.softDrop(); + break; + case 'ArrowUp': + e.preventDefault(); + this.rotate(1); + break; + case 'KeyZ': + e.preventDefault(); + this.rotate(-1); + break; + case 'KeyX': + e.preventDefault(); + this.rotate(1); + break; + case 'Space': + e.preventDefault(); + this.hardDrop(); + break; + } + } + // ── Drawing ─────────────────────────────── + drawIdle() { + this.ctx.fillStyle = '#111'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.drawGrid(); + this.setMessage('Press ENTER or click Start'); + } + draw() { + const ctx = this.ctx; + ctx.fillStyle = '#111'; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.drawGrid(); + this.drawBoard(); + if (this.active) { + this.drawGhost(); + this.drawPiece(this.active, ctx, BLOCK); + } + if (this.state === 'over') + this.drawOverlay(); + if (this.state === 'paused') + this.drawOverlay(true); + } + drawGrid() { + const ctx = this.ctx; + ctx.strokeStyle = 'rgba(255,255,255,0.05)'; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(COLS * BLOCK, r * BLOCK); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, ROWS * BLOCK); + ctx.stroke(); + } + } + drawBoard() { + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const color = this.board[r][c]; + if (color) + this.drawCell(this.ctx, r, c, color, BLOCK); + } + } + } + drawGhost() { + if (!this.active) + return; + let ghost = { ...this.active }; + while (true) { + const next = { ...ghost, row: ghost.row + 1 }; + if (this.isValid(next)) + ghost = next; + else + break; + } + const ctx = this.ctx; + for (const [r, c] of this.cells(ghost)) { + if (r < 0) + continue; + ctx.strokeStyle = PIECES[this.active.pieceIndex].color; + ctx.lineWidth = 1.5; + ctx.globalAlpha = 0.35; + ctx.strokeRect(c * BLOCK + 1, r * BLOCK + 1, BLOCK - 2, BLOCK - 2); + ctx.globalAlpha = 1; + } + } + drawPiece(piece, ctx, blockSize, offR = 0, offC = 0) { + const color = PIECES[piece.pieceIndex].color; + for (const [r, c] of this.cells(piece)) { + this.drawCell(ctx, r - offR, c - offC, color, blockSize); + } + } + drawCell(ctx, r, c, color, blockSize) { + const x = c * blockSize; + const y = r * blockSize; + const pad = 1; + // Fill + ctx.fillStyle = color; + ctx.fillRect(x + pad, y + pad, blockSize - pad * 2, blockSize - pad * 2); + // Highlight (top-left shine) + ctx.fillStyle = 'rgba(255,255,255,0.25)'; + ctx.fillRect(x + pad, y + pad, blockSize - pad * 2, 4); + ctx.fillRect(x + pad, y + pad, 4, blockSize - pad * 2); + // Shadow (bottom-right) + ctx.fillStyle = 'rgba(0,0,0,0.3)'; + ctx.fillRect(x + pad, y + blockSize - pad - 4, blockSize - pad * 2, 4); + ctx.fillRect(x + blockSize - pad - 4, y + pad, 4, blockSize - pad * 2); + } + drawPreview() { + const ctx = this.previewCtx; + const size = this.previewCanvas.width; + ctx.fillStyle = '#1a1a2e'; + ctx.fillRect(0, 0, size, size); + const pDef = PIECES[this.nextPieceIndex]; + const shape = pDef.rotations[0]; + // Compute bounding box + const minR = Math.min(...shape.map(([r]) => r)); + const maxR = Math.max(...shape.map(([r]) => r)); + const minC = Math.min(...shape.map(([, c]) => c)); + const maxC = Math.max(...shape.map(([, c]) => c)); + const h = maxR - minR + 1; + const w = maxC - minC + 1; + const offR = Math.floor((4 - h) / 2) - minR; + const offC = Math.floor((4 - w) / 2) - minC; + const preview = { + pieceIndex: this.nextPieceIndex, + rotation: 0, + row: offR, + col: offC, + }; + this.drawPiece(preview, ctx, PREVIEW_BLOCK, 0, 0); + } + drawOverlay(paused = false) { + const ctx = this.ctx; + ctx.fillStyle = 'rgba(0,0,0,0.55)'; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + } + // ── UI helpers ──────────────────────────── + updateLabels() { + this.scoreEl.textContent = String(this.score); + this.linesEl.textContent = String(this.lines); + this.levelEl.textContent = String(this.level); + } + setMessage(msg) { + this.messageEl.textContent = msg; + this.messageEl.style.display = msg ? 'block' : 'none'; + } +} +// ── Bootstrap ───────────────────────────────── +window.addEventListener('DOMContentLoaded', () => { + new Tetris(); +}); +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=none_effort=max_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,641 @@ +"use strict"; +// ============================================================================= +// TETRIS – Full browser implementation +// ============================================================================= +// ─── Constants ──────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell on the main board +const PREVIEW_PX = 120; // next-piece canvas size (square) +const PREVIEW_BLK = 24; // px per cell in the preview +// Delayed Auto Shift +const DAS_DELAY = 150; // ms before auto-repeat starts +const DAS_INTERVAL = 40; // ms between auto-repeat steps +// Lock delay: how long (ms) a grounded piece waits before locking +const LOCK_DELAY = 500; +// ─── Tetromino data ─────────────────────────────────────────────────────────── +const COLORS = { + I: "#00d4d4", + O: "#e6e600", + T: "#b300e6", + S: "#00cc00", + Z: "#e60000", + J: "#2222e6", + L: "#e67700", +}; +// Four rotation states for every piece, derived from SRS. +// Rows top-to-bottom, cols left-to-right. 1 = filled cell. +const SHAPES = { + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + O: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +const KICKS_JLSTZ = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +const KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +const PIECE_TYPES = ["I", "O", "T", "S", "Z", "J", "L"]; +// Scores awarded for clearing N lines simultaneously (multiplied by level) +const LINE_SCORES = [0, 100, 300, 500, 800]; +// ─── Board utilities (pure functions) ───────────────────────────────────────── +function makeBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function shape(p) { + return SHAPES[p.type][p.rot & 3]; +} +/** Enumerate every board cell occupied by piece p. */ +function cells(p) { + const s = shape(p); + const out = []; + for (let r = 0; r < s.length; r++) + for (let c = 0; c < s[r].length; c++) + if (s[r][c]) + out.push({ x: p.x + c, y: p.y + r }); + return out; +} +/** True if piece p is in a legal position on board. */ +function valid(board, p) { + for (const { x, y } of cells(p)) { + if (x < 0 || x >= COLS || y >= ROWS) + return false; + if (y >= 0 && board[y][x] !== null) + return false; + } + return true; +} +/** Return the lowest y the piece can occupy (for ghost rendering). */ +function ghostY(board, p) { + let y = p.y; + while (valid(board, { ...p, y: y + 1 })) + y++; + return y; +} +/** Attempt SRS rotation. Returns the new piece or null if blocked. */ +function tryRotate(board, p, dir) { + const n = 4; + const from = p.rot; + const to = ((from + dir) % n + n) % n; + const base = { ...p, rot: to }; + const table = p.type === "I" ? KICKS_I : KICKS_JLSTZ; + const kicks = table[`${from}>${to}`] ?? [[0, 0]]; + for (const [dx, dy] of kicks) { + const c = { ...base, x: base.x + dx, y: base.y - dy }; // negate dy + if (valid(board, c)) + return c; + } + return null; +} +/** Stamp piece onto board. */ +function lockPiece(board, p) { + for (const { x, y } of cells(p)) + if (y >= 0) + board[y][x] = COLORS[p.type]; +} +/** + * Remove all complete rows from board (mutates in-place). + * Returns the number of rows cleared. + */ +function clearLines(board) { + let count = 0; + for (let r = ROWS - 1; r >= 0;) { + if (board[r].every(c => c !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + count++; + } + else { + r--; + } + } + return count; +} +/** + * Drop interval in ms for a given level. + * Uses the NES Tetris frames-per-row table converted to milliseconds at 60 fps. + */ +function dropInterval(level) { + const FRAMES = [48, 43, 38, 33, 28, 23, 18, 13, 8, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1]; + const f = FRAMES[Math.min(level - 1, FRAMES.length - 1)]; + return (f / 60) * 1000; +} +// ─── 7-bag randomizer ───────────────────────────────────────────────────────── +class Bag { + constructor() { + this.pool = []; + } + next() { + if (this.pool.length === 0) { + this.pool = [...PIECE_TYPES]; + for (let i = this.pool.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.pool[i], this.pool[j]] = [this.pool[j], this.pool[i]]; + } + } + return this.pool.pop(); + } +} +// ─── Main game class ────────────────────────────────────────────────────────── +class Tetris { + constructor() { + // Game state + this.board = makeBoard(); + this.bag = new Bag(); + this.state = "playing"; + // Stats + this.score = 0; + this.lines = 0; + this.level = 1; + // Timing + this.lastTs = 0; + this.dropTimer = 0; // ms since last gravity step + // Lock delay + this.lockActive = false; + this.lockTimer = 0; + // Line-clear flash + this.clearTimer = 0; + this.clearRows = []; + // DAS + this.dasTimeouts = new Map(); + this.dasIntervals = new Map(); + this.canvas = document.getElementById("gameCanvas"); + this.ctx = this.canvas.getContext("2d"); + this.nCanvas = document.getElementById("nextCanvas"); + this.nCtx = this.nCanvas.getContext("2d"); + this.canvas.width = COLS * BLOCK; + this.canvas.height = ROWS * BLOCK; + this.nCanvas.width = PREVIEW_PX; + this.nCanvas.height = PREVIEW_PX; + // Pick first two pieces + this.nextType = this.bag.next(); + this.piece = this.spawn(); + this.bindKeys(); + this.refreshHUD(); + } + // ── Spawn ──────────────────────────────────────────────────────────────────── + spawn() { + const type = this.nextType; + this.nextType = this.bag.next(); + const s = SHAPES[type][0]; + const w = s[0].length; + const x = Math.floor((COLS - w) / 2); + // Offset so the first filled row appears at board row 0 + let firstFilled = 0; + for (let r = 0; r < s.length; r++) { + if (s[r].some(v => v !== 0)) { + firstFilled = r; + break; + } + } + return { type, rot: 0, x, y: -firstFilled }; + } + // ── Input ───────────────────────────────────────────────────────────────────── + bindKeys() { + const moveActions = { + ArrowLeft: () => this.shiftPiece(-1), + ArrowRight: () => this.shiftPiece(+1), + ArrowDown: () => this.softDrop(), + }; + document.addEventListener("keydown", e => { + if (this.state === "gameover") { + if (e.key === "Enter" || e.key === " ") + this.reset(); + return; + } + switch (e.key) { + case "ArrowLeft": + case "ArrowRight": + case "ArrowDown": + e.preventDefault(); + if (this.dasTimeouts.has(e.key) || this.dasIntervals.has(e.key)) + return; + moveActions[e.key](); + this.dasTimeouts.set(e.key, setTimeout(() => { + this.dasTimeouts.delete(e.key); + this.dasIntervals.set(e.key, setInterval(() => moveActions[e.key](), DAS_INTERVAL)); + }, DAS_DELAY)); + break; + case "ArrowUp": + case "x": + case "X": + e.preventDefault(); + this.rotatePiece(1); + break; + case "z": + case "Z": + e.preventDefault(); + this.rotatePiece(-1); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + case "p": + case "P": + this.togglePause(); + break; + } + }); + document.addEventListener("keyup", e => { + const t = this.dasTimeouts.get(e.key); + if (t !== undefined) { + clearTimeout(t); + this.dasTimeouts.delete(e.key); + } + const i = this.dasIntervals.get(e.key); + if (i !== undefined) { + clearInterval(i); + this.dasIntervals.delete(e.key); + } + }); + } + // ── Piece movement ─────────────────────────────────────────────────────────── + shiftPiece(dx) { + if (this.state !== "playing") + return; + const moved = { ...this.piece, x: this.piece.x + dx }; + if (!valid(this.board, moved)) + return; + this.piece = moved; + this.updateLockAfterMove(); + } + softDrop() { + if (this.state !== "playing") + return; + const moved = { ...this.piece, y: this.piece.y + 1 }; + if (valid(this.board, moved)) { + this.piece = moved; + this.score += 1; + this.dropTimer = 0; + this.updateLockAfterMove(); + this.refreshHUD(); + } + } + hardDrop() { + if (this.state !== "playing") + return; + const gy = ghostY(this.board, this.piece); + const dist = gy - this.piece.y; + this.score += dist * 2; + this.piece = { ...this.piece, y: gy }; + this.lock(); + } + rotatePiece(dir) { + if (this.state !== "playing") + return; + const rotated = tryRotate(this.board, this.piece, dir); + if (!rotated) + return; + this.piece = rotated; + this.updateLockAfterMove(); + } + /** After any successful move/rotation, decide whether to keep / reset lock delay. */ + updateLockAfterMove() { + const canFall = valid(this.board, { ...this.piece, y: this.piece.y + 1 }); + if (canFall) { + this.lockActive = false; + this.lockTimer = 0; + } + else if (this.lockActive) { + // Still grounded — reset timer to give the player more time + this.lockTimer = 0; + } + } + // ── Locking & line clearing ─────────────────────────────────────────────────── + lock() { + this.lockActive = false; + this.lockTimer = 0; + lockPiece(this.board, this.piece); + // Detect filled rows for the flash animation + const filled = []; + for (let r = 0; r < ROWS; r++) + if (this.board[r].every(c => c !== null)) + filled.push(r); + if (filled.length > 0) { + this.clearRows = filled; + this.clearTimer = 0; + this.state = "lineclear"; + } + else { + this.afterClear(0); + } + } + afterClear(cleared) { + if (cleared > 0) { + this.score += LINE_SCORES[cleared] * this.level; + this.lines += cleared; + this.level = Math.floor(this.lines / 10) + 1; + } + this.refreshHUD(); + this.piece = this.spawn(); + this.dropTimer = 0; + this.lockActive = false; + this.lockTimer = 0; + if (!valid(this.board, this.piece)) { + this.state = "gameover"; + this.showOverlay("gameOverOverlay"); + document.getElementById("finalScore").textContent = String(this.score); + } + else { + this.state = "playing"; + } + } + // ── Pause / reset ───────────────────────────────────────────────────────────── + togglePause() { + if (this.state === "gameover") + return; + if (this.state === "paused") { + this.state = "playing"; + this.hideOverlay("pauseOverlay"); + } + else if (this.state === "playing") { + this.state = "paused"; + this.showOverlay("pauseOverlay"); + } + } + reset() { + this.board = makeBoard(); + this.bag = new Bag(); + this.nextType = this.bag.next(); + this.piece = this.spawn(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.state = "playing"; + this.dropTimer = 0; + this.lockActive = false; + this.lockTimer = 0; + this.clearRows = []; + this.hideOverlay("gameOverOverlay"); + this.refreshHUD(); + } + // ── HUD helpers ─────────────────────────────────────────────────────────────── + refreshHUD() { + document.getElementById("score").textContent = String(this.score); + document.getElementById("level").textContent = String(this.level); + document.getElementById("lines").textContent = String(this.lines); + } + showOverlay(id) { + document.getElementById(id)?.classList.add("visible"); + } + hideOverlay(id) { + document.getElementById(id)?.classList.remove("visible"); + } + // ── Game loop ───────────────────────────────────────────────────────────────── + start() { + requestAnimationFrame(ts => { this.lastTs = ts; this.loop(ts); }); + } + loop(ts) { + const dt = Math.min(ts - this.lastTs, 50); // cap to avoid spiral-of-death + this.lastTs = ts; + this.update(dt); + this.render(); + requestAnimationFrame(ts => this.loop(ts)); + } + update(dt) { + if (this.state === "lineclear") { + this.clearTimer += dt; + if (this.clearTimer >= 300) { + const cleared = clearLines(this.board); + this.clearRows = []; + this.afterClear(cleared); + } + return; + } + if (this.state !== "playing") + return; + // ── Gravity ────────────────────────────────────────────────────────────── + this.dropTimer += dt; + const interval = dropInterval(this.level); + if (this.dropTimer >= interval) { + this.dropTimer -= interval; + const canFall = valid(this.board, { ...this.piece, y: this.piece.y + 1 }); + if (canFall) { + this.piece = { ...this.piece, y: this.piece.y + 1 }; + this.lockActive = false; + this.lockTimer = 0; + } + else { + // Piece is grounded — arm the lock timer if not already running + if (!this.lockActive) { + this.lockActive = true; + this.lockTimer = 0; + } + } + } + // ── Lock delay ─────────────────────────────────────────────────────────── + if (this.lockActive) { + this.lockTimer += dt; + if (this.lockTimer >= LOCK_DELAY) { + // Re-check: the player might have shifted the piece to a free column + if (!valid(this.board, { ...this.piece, y: this.piece.y + 1 })) { + this.lock(); + } + else { + this.lockActive = false; + this.lockTimer = 0; + } + } + } + } + // ── Rendering ───────────────────────────────────────────────────────────────── + render() { + this.drawBoard(); + this.drawPreview(); + } + drawBoard() { + const ctx = this.ctx; + const W = this.canvas.width; + const H = this.canvas.height; + // Background + ctx.fillStyle = "#0c0c1e"; + ctx.fillRect(0, 0, W, H); + // Subtle grid + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + ctx.lineWidth = 1; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(W, r * BLOCK); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, H); + ctx.stroke(); + } + // Locked blocks + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const color = this.board[r][c]; + if (!color) + continue; + const flashing = this.state === "lineclear" && this.clearRows.includes(r); + if (flashing) { + // Alternate bright white / dim for flash effect + const phase = Math.floor(this.clearTimer / 50) % 2; + if (phase === 0) { + this.drawBlock(ctx, c, r, "#ffffff", 1.0); + } + else { + this.drawBlock(ctx, c, r, color, 0.2); + } + } + else { + this.drawBlock(ctx, c, r, color, 1.0); + } + } + } + // Ghost piece + if (this.state === "playing" || this.state === "paused") { + const gy = ghostY(this.board, this.piece); + if (gy !== this.piece.y) + this.drawGhost(gy); + } + // Active piece + if (this.state !== "gameover") { + const s = shape(this.piece); + for (let r = 0; r < s.length; r++) + for (let c = 0; c < s[r].length; c++) + if (s[r][c] && this.piece.y + r >= 0) + this.drawBlock(ctx, this.piece.x + c, this.piece.y + r, COLORS[this.piece.type], 1.0); + } + // Pause veil drawn directly on the canvas + if (this.state === "paused") { + ctx.fillStyle = "rgba(0,0,0,0.55)"; + ctx.fillRect(0, 0, W, H); + ctx.fillStyle = "#00d4d4"; + ctx.font = "bold 34px 'Courier New', monospace"; + ctx.textAlign = "center"; + ctx.textBaseline = "middle"; + ctx.fillText("PAUSED", W / 2, H / 2 - 18); + ctx.fillStyle = "#666"; + ctx.font = "14px 'Courier New', monospace"; + ctx.fillText("press P to resume", W / 2, H / 2 + 18); + } + } + drawGhost(gy) { + const ctx = this.ctx; + const s = shape(this.piece); + ctx.save(); + ctx.strokeStyle = COLORS[this.piece.type]; + ctx.lineWidth = 2; + ctx.globalAlpha = 0.35; + for (let r = 0; r < s.length; r++) + for (let c = 0; c < s[r].length; c++) + if (s[r][c] && gy + r >= 0) + ctx.strokeRect((this.piece.x + c) * BLOCK + 2, (gy + r) * BLOCK + 2, BLOCK - 4, BLOCK - 4); + ctx.restore(); + } + drawBlock(ctx, col, row, color, alpha) { + const x = col * BLOCK; + const y = row * BLOCK; + const S = BLOCK; + const m = 1; + ctx.save(); + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x + m, y + m, S - m * 2, S - m * 2); + // Top/left highlight + ctx.fillStyle = "rgba(255,255,255,0.28)"; + ctx.fillRect(x + m, y + m, S - m * 2, 4); + ctx.fillRect(x + m, y + m, 4, S - m * 2); + // Bottom/right shadow + ctx.fillStyle = "rgba(0,0,0,0.38)"; + ctx.fillRect(x + m, y + S - m - 4, S - m * 2, 4); + ctx.fillRect(x + S - m - 4, y + m, 4, S - m * 2); + ctx.restore(); + } + drawPreview() { + const ctx = this.nCtx; + const W = this.nCanvas.width; + const H = this.nCanvas.height; + const bs = PREVIEW_BLK; + ctx.fillStyle = "#0c0c1e"; + ctx.fillRect(0, 0, W, H); + const s = SHAPES[this.nextType][0]; + const pw = s[0].length * bs; + const ph = s.length * bs; + const ox = Math.floor((W - pw) / 2); + const oy = Math.floor((H - ph) / 2); + const color = COLORS[this.nextType]; + for (let r = 0; r < s.length; r++) { + for (let c = 0; c < s[r].length; c++) { + if (!s[r][c]) + continue; + const px = ox + c * bs; + const py = oy + r * bs; + const m = 1; + ctx.fillStyle = color; + ctx.fillRect(px + m, py + m, bs - m * 2, bs - m * 2); + ctx.fillStyle = "rgba(255,255,255,0.28)"; + ctx.fillRect(px + m, py + m, bs - m * 2, 3); + ctx.fillRect(px + m, py + m, 3, bs - m * 2); + ctx.fillStyle = "rgba(0,0,0,0.38)"; + ctx.fillRect(px + m, py + bs - m - 3, bs - m * 2, 3); + ctx.fillRect(px + bs - m - 3, py + m, 3, bs - m * 2); + } + } + } +} +// ─── Bootstrap ──────────────────────────────────────────────────────────────── +window.addEventListener("DOMContentLoaded", () => { + const game = new Tetris(); + game.start(); +}); diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,395 @@ +"use strict"; +// Game constants +const COLS = 10; +const ROWS = 20; +const BLOCK_SIZE = 24; +const GRID_COLOR = '#333'; +const PIECE_COLORS = { + 'I': '#00f0f0', + 'O': '#f0f000', + 'T': '#a000f0', + 'S': '#00f000', + 'Z': '#f00000', + 'J': '#0000f0', + 'L': '#f0a000', +}; +// Tetris piece shapes +const SHAPES = { + 'I': [[[1, 1, 1, 1]]], + 'O': [[[1, 1], [1, 1]]], + 'T': [ + [[0, 1, 0], [1, 1, 1]], + [[1, 0], [1, 1], [1, 0]], + [[1, 1, 1], [0, 1, 0]], + [[0, 1], [1, 1], [0, 1]], + ], + 'S': [ + [[0, 1, 1], [1, 1, 0]], + [[1, 0], [1, 1], [0, 1]], + ], + 'Z': [ + [[1, 1, 0], [0, 1, 1]], + [[0, 1], [1, 1], [1, 0]], + ], + 'J': [ + [[1, 0, 0], [1, 1, 1]], + [[1, 1], [1, 0], [1, 0]], + [[1, 1, 1], [0, 0, 1]], + [[1, 0], [1, 0], [1, 1]], + ], + 'L': [ + [[0, 0, 1], [1, 1, 1]], + [[1, 0], [1, 0], [1, 1]], + [[1, 1, 1], [1, 0, 0]], + [[1, 1], [0, 1], [0, 1]], + ], +}; +class TetrisGame { + constructor() { + this.board = []; + this.currentPiece = null; + this.nextPiece = ''; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.paused = false; + this.dropCounter = 0; + this.dropInterval = 1000; + this.lastDropTime = 0; + this.keys = {}; + this.gameLoop = () => { + this.update(); + this.render(); + this.renderPreview(); + requestAnimationFrame(this.gameLoop); + }; + this.canvas = document.getElementById('gameCanvas'); + this.ctx = this.canvas.getContext('2d'); + this.previewCanvas = document.getElementById('previewCanvas'); + this.previewCtx = this.previewCanvas.getContext('2d'); + this.gameOverModal = document.getElementById('gameOverModal'); + this.finalScoreDisplay = document.getElementById('finalScore'); + this.restartButton = document.getElementById('restartButton'); + this.initBoard(); + this.setupEventListeners(); + this.nextPiece = this.getRandomPieceType(); + this.spawnNewPiece(); + this.lastDropTime = Date.now(); + this.gameLoop(); + } + initBoard() { + this.board = Array(ROWS) + .fill(null) + .map(() => Array(COLS).fill(0)); + } + setupEventListeners() { + window.addEventListener('keydown', (e) => this.handleKeyDown(e)); + window.addEventListener('keyup', (e) => this.handleKeyUp(e)); + this.restartButton.addEventListener('click', () => this.restart()); + } + handleKeyDown(e) { + if (this.gameOver) + return; + const key = e.key.toLowerCase(); + if (key === ' ') { + e.preventDefault(); + this.hardDrop(); + } + else if (key === 'z' || key === 'x') { + e.preventDefault(); + const rotateRight = key === 'x'; + this.rotatePiece(rotateRight); + } + else if (key === 'p') { + e.preventDefault(); + this.togglePause(); + } + else if (key === 'arrowleft' || key === 'arrowright' || key === 'arrowdown') { + e.preventDefault(); + this.keys[key] = true; + } + } + handleKeyUp(e) { + const key = e.key.toLowerCase(); + this.keys[key] = false; + } + getRandomPieceType() { + const types = Object.keys(SHAPES); + return types[Math.floor(Math.random() * types.length)]; + } + spawnNewPiece() { + const type = this.nextPiece; + this.nextPiece = this.getRandomPieceType(); + this.currentPiece = { + type, + x: Math.floor(COLS / 2) - 1, + y: 0, + rotation: 0, + }; + if (!this.isValidPosition(this.currentPiece)) { + this.endGame(); + } + } + getShape(piece) { + return SHAPES[piece.type][piece.rotation % SHAPES[piece.type].length]; + } + isValidPosition(piece) { + const shape = this.getShape(piece); + for (let y = 0; y < shape.length; y++) { + for (let x = 0; x < shape[y].length; x++) { + if (shape[y][x]) { + const boardX = piece.x + x; + const boardY = piece.y + y; + if (boardX < 0 || + boardX >= COLS || + boardY >= ROWS || + (boardY >= 0 && this.board[boardY][boardX])) { + return false; + } + } + } + } + return true; + } + movePiece(dx, dy) { + if (!this.currentPiece) + return false; + this.currentPiece.x += dx; + this.currentPiece.y += dy; + if (this.isValidPosition(this.currentPiece)) { + return true; + } + this.currentPiece.x -= dx; + this.currentPiece.y -= dy; + return false; + } + rotatePiece(rotateRight) { + if (!this.currentPiece || this.currentPiece.type === 'O') + return; + const originalRotation = this.currentPiece.rotation; + this.currentPiece.rotation = rotateRight + ? (this.currentPiece.rotation + 1) % SHAPES[this.currentPiece.type].length + : (this.currentPiece.rotation - 1 + SHAPES[this.currentPiece.type].length) % SHAPES[this.currentPiece.type].length; + if (!this.isValidPosition(this.currentPiece)) { + // Try wall kicks + const kicks = [-1, 1, -2, 2]; + let kicked = false; + for (const kick of kicks) { + this.currentPiece.x += kick; + if (this.isValidPosition(this.currentPiece)) { + kicked = true; + break; + } + this.currentPiece.x -= kick; + } + if (!kicked) { + this.currentPiece.rotation = originalRotation; + } + } + } + hardDrop() { + if (!this.currentPiece) + return; + while (this.movePiece(0, 1)) { + this.score += 2; + } + this.lockPiece(); + } + lockPiece() { + if (!this.currentPiece) + return; + const shape = this.getShape(this.currentPiece); + for (let y = 0; y < shape.length; y++) { + for (let x = 0; x < shape[y].length; x++) { + if (shape[y][x]) { + const boardY = this.currentPiece.y + y; + const boardX = this.currentPiece.x + x; + if (boardY >= 0 && boardY < ROWS && boardX >= 0 && boardX < COLS) { + this.board[boardY][boardX] = 1; + } + } + } + } + this.clearLines(); + this.spawnNewPiece(); + } + clearLines() { + const linesToClear = []; + for (let y = ROWS - 1; y >= 0; y--) { + if (this.board[y].every((cell) => cell === 1)) { + linesToClear.push(y); + } + } + if (linesToClear.length > 0) { + // Remove cleared lines + linesToClear.forEach((y) => { + this.board.splice(y, 1); + this.board.unshift(Array(COLS).fill(0)); + }); + // Update score + this.lines += linesToClear.length; + const lineBonus = [0, 100, 300, 500, 800]; + this.score += lineBonus[linesToClear.length] * this.level; + // Update level + this.level = Math.floor(this.lines / 10) + 1; + this.dropInterval = Math.max(100, 1000 - (this.level - 1) * 50); + this.updateDisplay(); + } + } + togglePause() { + this.paused = !this.paused; + } + endGame() { + this.gameOver = true; + this.finalScoreDisplay.textContent = this.score.toString(); + this.gameOverModal.classList.add('show'); + } + restart() { + this.gameOver = false; + this.paused = false; + this.score = 0; + this.lines = 0; + this.level = 1; + this.dropInterval = 1000; + this.currentPiece = null; + this.gameOverModal.classList.remove('show'); + this.initBoard(); + this.nextPiece = this.getRandomPieceType(); + this.spawnNewPiece(); + this.updateDisplay(); + this.lastDropTime = Date.now(); + } + updateDisplay() { + document.getElementById('scoreDisplay').textContent = this.score.toString(); + document.getElementById('levelDisplay').textContent = this.level.toString(); + document.getElementById('linesDisplay').textContent = this.lines.toString(); + } + render() { + // Clear canvas + this.ctx.fillStyle = '#1a1a2e'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid + this.ctx.strokeStyle = GRID_COLOR; + this.ctx.lineWidth = 0.5; + for (let x = 0; x <= COLS; x++) { + this.ctx.beginPath(); + this.ctx.moveTo(x * BLOCK_SIZE, 0); + this.ctx.lineTo(x * BLOCK_SIZE, this.canvas.height); + this.ctx.stroke(); + } + for (let y = 0; y <= ROWS; y++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, y * BLOCK_SIZE); + this.ctx.lineTo(this.canvas.width, y * BLOCK_SIZE); + this.ctx.stroke(); + } + // Draw board + for (let y = 0; y < ROWS; y++) { + for (let x = 0; x < COLS; x++) { + if (this.board[y][x]) { + this.drawBlock(x, y, '#666'); + } + } + } + // Draw current piece + if (this.currentPiece && !this.paused) { + this.drawPiece(this.currentPiece); + } + // Draw pause overlay + if (this.paused) { + this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.fillStyle = '#fff'; + this.ctx.font = '24px sans-serif'; + this.ctx.textAlign = 'center'; + this.ctx.textBaseline = 'middle'; + this.ctx.fillText('PAUSED', this.canvas.width / 2, this.canvas.height / 2); + } + } + drawBlock(x, y, color) { + this.ctx.fillStyle = color; + this.ctx.fillRect(x * BLOCK_SIZE + 1, y * BLOCK_SIZE + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + } + drawPiece(piece) { + const shape = this.getShape(piece); + const color = PIECE_COLORS[piece.type]; + for (let y = 0; y < shape.length; y++) { + for (let x = 0; x < shape[y].length; x++) { + if (shape[y][x]) { + this.drawBlock(piece.x + x, piece.y + y, color); + } + } + } + } + renderPreview() { + // Clear preview canvas + this.previewCtx.fillStyle = '#1a1a2e'; + this.previewCtx.fillRect(0, 0, this.previewCanvas.width, this.previewCanvas.height); + // Create preview piece + const type = this.nextPiece; + const shape = SHAPES[type][0]; + const color = PIECE_COLORS[type]; + // Calculate positioning + let minX = shape[0].length; + let minY = shape.length; + let maxX = 0; + let maxY = 0; + for (let y = 0; y < shape.length; y++) { + for (let x = 0; x < shape[y].length; x++) { + if (shape[y][x]) { + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + } + const previewBlockSize = 20; + const width = (maxX - minX + 1) * previewBlockSize; + const height = (maxY - minY + 1) * previewBlockSize; + const offsetX = (this.previewCanvas.width - width) / 2; + const offsetY = (this.previewCanvas.height - height) / 2; + for (let y = 0; y < shape.length; y++) { + for (let x = 0; x < shape[y].length; x++) { + if (shape[y][x]) { + this.previewCtx.fillStyle = color; + this.previewCtx.fillRect(offsetX + (x - minX) * previewBlockSize + 1, offsetY + (y - minY) * previewBlockSize + 1, previewBlockSize - 2, previewBlockSize - 2); + } + } + } + } + update() { + if (this.gameOver || this.paused) + return; + const now = Date.now(); + const deltaTime = now - this.lastDropTime; + // Handle continuous movement + if (this.keys['arrowleft']) { + this.movePiece(-1, 0); + } + if (this.keys['arrowright']) { + this.movePiece(1, 0); + } + if (this.keys['arrowdown']) { + this.movePiece(0, 1); + this.score += 1; + } + // Handle automatic drop + if (deltaTime > this.dropInterval) { + if (!this.movePiece(0, 1)) { + this.lockPiece(); + } + this.lastDropTime = now; + } + } +} +// Start game when DOM is ready +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', () => { + new TetrisGame(); + }); +} +else { + new TetrisGame(); +} diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=high_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/game.js @@ -0,0 +1,374 @@ +"use strict"; +// Tetris Game in TypeScript +// Define all Tetris pieces (tetrominoes) +const PIECES = [ + // I piece + [[1, 1, 1, 1]], + // O piece + [[1, 1], [1, 1]], + // T piece + [[0, 1, 0], [1, 1, 1]], + // S piece + [[0, 1, 1], [1, 1, 0]], + // Z piece + [[1, 1, 0], [0, 1, 1]], + // J piece + [[1, 0, 0], [1, 1, 1]], + // L piece + [[0, 0, 1], [1, 1, 1]], +]; +const COLORS = [ + '#00F0F0', // I - Cyan + '#F0F000', // O - Yellow + '#A000F0', // T - Purple + '#00F000', // S - Green + '#F00000', // Z - Red + '#0000F0', // J - Blue + '#F0A000', // L - Orange +]; +const BOARD_WIDTH = 10; +const BOARD_HEIGHT = 20; +const BLOCK_SIZE = 30; +class TetrisGame { + constructor(canvasId) { + this.dropInterval = 1000; + this.lastDropTime = 0; + this.gameRunning = true; + this.canvas = document.getElementById(canvasId); + this.ctx = this.canvas.getContext('2d'); + // Initialize board + this.state = { + board: Array(BOARD_HEIGHT) + .fill(null) + .map(() => Array(BOARD_WIDTH).fill(0)), + currentPiece: this.getRandomPiece(), + currentColor: Math.floor(Math.random() * PIECES.length), + currentX: 3, + currentY: 0, + score: 0, + level: 1, + linesCleared: 0, + gameOver: false, + nextPiece: this.getRandomPiece(), + nextColor: Math.floor(Math.random() * PIECES.length), + }; + this.setupEventListeners(); + } + getRandomPiece() { + const piece = PIECES[Math.floor(Math.random() * PIECES.length)]; + return piece.map((row) => [...row]); + } + setupEventListeners() { + document.addEventListener('keydown', (e) => this.handleKeyPress(e)); + } + handleKeyPress(e) { + if (this.state.gameOver) { + if (e.key === ' ' || e.key === 'Enter') { + this.resetGame(); + } + return; + } + switch (e.key) { + case 'ArrowLeft': + this.moveLeft(); + e.preventDefault(); + break; + case 'ArrowRight': + this.moveRight(); + e.preventDefault(); + break; + case 'ArrowDown': + this.moveDown(); + e.preventDefault(); + break; + case 'ArrowUp': + case 'z': + case 'Z': + this.rotatePiece(); + e.preventDefault(); + break; + case ' ': + this.hardDrop(); + e.preventDefault(); + break; + } + } + moveLeft() { + if (this.canMove(this.state.currentX - 1, this.state.currentY)) { + this.state.currentX--; + } + } + moveRight() { + if (this.canMove(this.state.currentX + 1, this.state.currentY)) { + this.state.currentX++; + } + } + moveDown() { + if (this.canMove(this.state.currentX, this.state.currentY + 1)) { + this.state.currentY++; + } + else { + this.lockPiece(); + } + } + hardDrop() { + while (this.canMove(this.state.currentX, this.state.currentY + 1)) { + this.state.currentY++; + } + this.lockPiece(); + } + rotatePiece() { + const rotated = this.rotate(this.state.currentPiece); + if (this.canRotate(rotated)) { + this.state.currentPiece = rotated; + } + } + rotate(piece) { + const rows = piece.length; + const cols = piece[0].length; + const rotated = Array(cols) + .fill(null) + .map(() => Array(rows).fill(0)); + for (let y = 0; y < rows; y++) { + for (let x = 0; x < cols; x++) { + rotated[x][rows - 1 - y] = piece[y][x]; + } + } + return rotated; + } + canRotate(piece) { + for (let y = 0; y < piece.length; y++) { + for (let x = 0; x < piece[y].length; x++) { + if (piece[y][x]) { + const boardX = this.state.currentX + x; + const boardY = this.state.currentY + y; + if (boardX < 0 || + boardX >= BOARD_WIDTH || + boardY >= BOARD_HEIGHT || + (boardY >= 0 && this.state.board[boardY][boardX] > 0)) { + return false; + } + } + } + } + return true; + } + canMove(x, y) { + for (let py = 0; py < this.state.currentPiece.length; py++) { + for (let px = 0; px < this.state.currentPiece[py].length; px++) { + if (this.state.currentPiece[py][px]) { + const boardX = x + px; + const boardY = y + py; + if (boardX < 0 || boardX >= BOARD_WIDTH || boardY >= BOARD_HEIGHT) { + return false; + } + if (boardY >= 0 && this.state.board[boardY][boardX] > 0) { + return false; + } + } + } + } + return true; + } + lockPiece() { + // Place the piece on the board + for (let py = 0; py < this.state.currentPiece.length; py++) { + for (let px = 0; px < this.state.currentPiece[py].length; px++) { + if (this.state.currentPiece[py][px]) { + const boardY = this.state.currentY + py; + const boardX = this.state.currentX + px; + if (boardY >= 0) { + this.state.board[boardY][boardX] = this.state.currentColor + 1; + } + } + } + } + // Check for completed lines + this.clearLines(); + // Get next piece + this.state.currentPiece = this.state.nextPiece; + this.state.currentColor = this.state.nextColor; + this.state.nextPiece = this.getRandomPiece(); + this.state.nextColor = Math.floor(Math.random() * PIECES.length); + this.state.currentX = 3; + this.state.currentY = 0; + // Check for game over + if (!this.canMove(this.state.currentX, this.state.currentY)) { + this.state.gameOver = true; + } + } + clearLines() { + let linesCleared = 0; + for (let y = BOARD_HEIGHT - 1; y >= 0; y--) { + if (this.state.board[y].every((cell) => cell > 0)) { + this.state.board.splice(y, 1); + this.state.board.unshift(Array(BOARD_WIDTH).fill(0)); + linesCleared++; + y++; + } + } + if (linesCleared > 0) { + this.state.linesCleared += linesCleared; + const points = [0, 100, 300, 500, 800][linesCleared] || 0; + this.state.score += points * this.state.level; + this.state.level = Math.floor(this.state.linesCleared / 10) + 1; + this.dropInterval = Math.max(100, 1000 - (this.state.level - 1) * 50); + } + } + resetGame() { + this.state = { + board: Array(BOARD_HEIGHT) + .fill(null) + .map(() => Array(BOARD_WIDTH).fill(0)), + currentPiece: this.getRandomPiece(), + currentColor: Math.floor(Math.random() * PIECES.length), + currentX: 3, + currentY: 0, + score: 0, + level: 1, + linesCleared: 0, + gameOver: false, + nextPiece: this.getRandomPiece(), + nextColor: Math.floor(Math.random() * PIECES.length), + }; + this.dropInterval = 1000; + } + draw() { + this.ctx.fillStyle = '#000'; + this.ctx.fillRect(0, 0, BOARD_WIDTH * BLOCK_SIZE, BOARD_HEIGHT * BLOCK_SIZE); + // Draw grid + this.ctx.strokeStyle = '#222'; + this.ctx.lineWidth = 0.5; + for (let x = 0; x <= BOARD_WIDTH; x++) { + this.ctx.beginPath(); + this.ctx.moveTo(x * BLOCK_SIZE, 0); + this.ctx.lineTo(x * BLOCK_SIZE, BOARD_HEIGHT * BLOCK_SIZE); + this.ctx.stroke(); + } + for (let y = 0; y <= BOARD_HEIGHT; y++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, y * BLOCK_SIZE); + this.ctx.lineTo(BOARD_WIDTH * BLOCK_SIZE, y * BLOCK_SIZE); + this.ctx.stroke(); + } + // Draw placed blocks + for (let y = 0; y < BOARD_HEIGHT; y++) { + for (let x = 0; x < BOARD_WIDTH; x++) { + const cellValue = this.state.board[y][x]; + if (cellValue > 0) { + this.drawBlock(x, y, COLORS[cellValue - 1]); + } + } + } + // Draw current piece + for (let py = 0; py < this.state.currentPiece.length; py++) { + for (let px = 0; px < this.state.currentPiece[py].length; px++) { + if (this.state.currentPiece[py][px]) { + const x = this.state.currentX + px; + const y = this.state.currentY + py; + if (y >= 0) { + this.drawBlock(x, y, COLORS[this.state.currentColor]); + } + } + } + } + // Update HUD + this.updateHUD(); + } + drawBlock(x, y, color) { + this.ctx.fillStyle = color; + this.ctx.fillRect(x * BLOCK_SIZE + 1, y * BLOCK_SIZE + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + // Draw highlight + this.ctx.strokeStyle = '#FFF'; + this.ctx.lineWidth = 2; + this.ctx.strokeRect(x * BLOCK_SIZE + 1, y * BLOCK_SIZE + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2); + } + updateHUD() { + const scoreEl = document.getElementById('score'); + const levelEl = document.getElementById('level'); + const linesEl = document.getElementById('lines'); + const gameOverEl = document.getElementById('gameOverMessage'); + const finalScoreEl = document.getElementById('finalScore'); + if (scoreEl) + scoreEl.textContent = this.state.score.toString(); + if (levelEl) + levelEl.textContent = this.state.level.toString(); + if (linesEl) + linesEl.textContent = this.state.linesCleared.toString(); + if (gameOverEl) { + if (this.state.gameOver) { + gameOverEl.style.display = 'block'; + if (finalScoreEl) { + finalScoreEl.textContent = `Final Score: ${this.state.score}`; + } + } + else { + gameOverEl.style.display = 'none'; + } + } + this.drawNextPiece(); + } + drawNextPiece() { + const previewCanvas = document.getElementById('preview'); + if (!previewCanvas) + return; + const ctx = previewCanvas.getContext('2d'); + ctx.fillStyle = '#000'; + ctx.fillRect(0, 0, previewCanvas.width, previewCanvas.height); + ctx.strokeStyle = '#222'; + ctx.lineWidth = 0.5; + for (let x = 0; x <= 4; x++) { + ctx.beginPath(); + ctx.moveTo(x * 30, 0); + ctx.lineTo(x * 30, 120); + ctx.stroke(); + } + for (let y = 0; y <= 4; y++) { + ctx.beginPath(); + ctx.moveTo(0, y * 30); + ctx.lineTo(120, y * 30); + ctx.stroke(); + } + const offsetX = (4 - this.state.nextPiece[0].length) / 2; + const offsetY = (4 - this.state.nextPiece.length) / 2; + for (let py = 0; py < this.state.nextPiece.length; py++) { + for (let px = 0; px < this.state.nextPiece[py].length; px++) { + if (this.state.nextPiece[py][px]) { + const x = offsetX + px; + const y = offsetY + py; + ctx.fillStyle = COLORS[this.state.nextColor]; + ctx.fillRect(x * 30 + 1, y * 30 + 1, 28, 28); + ctx.strokeStyle = '#FFF'; + ctx.lineWidth = 2; + ctx.strokeRect(x * 30 + 1, y * 30 + 1, 28, 28); + } + } + } + } + update(currentTime) { + if (this.state.gameOver) + return; + if (currentTime - this.lastDropTime > this.dropInterval) { + if (!this.canMove(this.state.currentX, this.state.currentY + 1)) { + this.lockPiece(); + } + else { + this.state.currentY++; + } + this.lastDropTime = currentTime; + } + this.draw(); + } + start() { + const gameLoop = (currentTime) => { + this.update(currentTime); + requestAnimationFrame(gameLoop); + }; + requestAnimationFrame(gameLoop); + } +} +// Initialize game when DOM is ready +document.addEventListener('DOMContentLoaded', () => { + const game = new TetrisGame('gameCanvas'); + game.start(); +}); diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.d.ts b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.d.ts @@ -0,0 +1,37 @@ +declare class TetrisGame { + private board; + private activePiece; + private nextPieceIndex; + private score; + private level; + private lines; + private dropInterval; + private lastDropTime; + private gameRunning; + private canvas; + private ctx; + constructor(canvasId: string); + private setupKeyboardControls; + private gameLoop; + private spawnPiece; + private canMovePiece; + private rotatePieceRight; + private rotatePieceLeft; + private rotatePieceShape; + private movePieceLeft; + private movePieceRight; + private dropPieceOneCell; + private dropPieceFast; + private dropPieceInstant; + private lockPiece; + private clearLines; + private render; + private drawCell; + private updateUI; + private renderNextPiece; + private togglePause; + private endGame; + restart(): void; +} +export { TetrisGame }; +//# sourceMappingURL=tetris.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.d.ts.map b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.d.ts","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"AAoDA,cAAM,UAAU;IACd,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,YAAY,CAAiC;IACrD,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,GAAG,CAA2B;gBAE1B,QAAQ,EAAE,MAAM;IA4B5B,OAAO,CAAC,qBAAqB;IAsC7B,OAAO,CAAC,QAAQ,CAUd;IAEF,OAAO,CAAC,UAAU;IAoBlB,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,gBAAgB;IAwBxB,OAAO,CAAC,eAAe;IAsBvB,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,SAAS;IA0BjB,OAAO,CAAC,UAAU;IA+BlB,OAAO,CAAC,MAAM;IA4Cd,OAAO,CAAC,QAAQ;IAqBhB,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,eAAe;IAmCvB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,OAAO;IAKR,OAAO,IAAI,IAAI;CAcvB;AAWD,OAAO,EAAE,UAAU,EAAE,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,403 @@ +// Tetris Game Implementation in TypeScript +// Tetromino shapes (as number arrays where 1 = filled, 0 = empty) +const PIECES = [ + // I piece (cyan) + [[1, 1, 1, 1]], + // O piece (yellow) + [[1, 1], [1, 1]], + // T piece (purple) + [[0, 1, 0], [1, 1, 1]], + // S piece (green) + [[0, 1, 1], [1, 1, 0]], + // Z piece (red) + [[1, 1, 0], [0, 1, 1]], + // J piece (blue) + [[1, 0, 0], [1, 1, 1]], + // L piece (orange) + [[0, 0, 1], [1, 1, 1]], +]; +const COLORS = [ + '#00f0f0', // cyan (I) + '#f0f000', // yellow (O) + '#a000f0', // purple (T) + '#00f000', // green (S) + '#f00000', // red (Z) + '#0000f0', // blue (J) + '#f0a000', // orange (L) +]; +const BOARD_WIDTH = 10; +const BOARD_HEIGHT = 20; +const CELL_SIZE = 25; +const INITIAL_DROP_INTERVAL = 800; +const LEVEL_SPEED_MULTIPLIER = 0.9; +class TetrisGame { + constructor(canvasId) { + this.activePiece = null; + this.score = 0; + this.level = 1; + this.lines = 0; + this.dropInterval = INITIAL_DROP_INTERVAL; + this.lastDropTime = 0; + this.gameRunning = true; + this.gameLoop = () => { + const now = Date.now(); + if (this.gameRunning && now - this.lastDropTime >= this.dropInterval) { + this.dropPieceOneCell(); + this.lastDropTime = now; + } + this.render(); + requestAnimationFrame(this.gameLoop); + }; + this.canvas = document.getElementById(canvasId); + if (!this.canvas) { + throw new Error(`Canvas with id "${canvasId}" not found`); + } + this.ctx = this.canvas.getContext('2d'); + this.canvas.width = BOARD_WIDTH * CELL_SIZE; + this.canvas.height = BOARD_HEIGHT * CELL_SIZE; + // Initialize board + this.board = Array.from({ length: BOARD_HEIGHT }, () => Array(BOARD_WIDTH).fill(0)); + // Get random piece for next + this.nextPieceIndex = Math.floor(Math.random() * PIECES.length); + // Spawn first piece + this.spawnPiece(); + // Setup keyboard controls + this.setupKeyboardControls(); + // Start game loop + this.gameLoop(); + } + setupKeyboardControls() { + document.addEventListener('keydown', (e) => { + if (!this.gameRunning) + return; + switch (e.key.toLowerCase()) { + case 'arrowleft': + e.preventDefault(); + this.movePieceLeft(); + break; + case 'arrowright': + e.preventDefault(); + this.movePieceRight(); + break; + case 'arrowdown': + e.preventDefault(); + this.dropPieceFast(); + break; + case ' ': + e.preventDefault(); + this.dropPieceInstant(); + break; + case 'z': + e.preventDefault(); + this.rotatePieceLeft(); + break; + case 'x': + case 'arrowup': + e.preventDefault(); + this.rotatePieceRight(); + break; + case 'p': + e.preventDefault(); + this.togglePause(); + break; + } + }); + } + spawnPiece() { + const shapeIndex = this.nextPieceIndex; + const shape = PIECES[shapeIndex]; + // Get next piece for preview + this.nextPieceIndex = Math.floor(Math.random() * PIECES.length); + this.activePiece = { + shape: shape.map(row => [...row]), + colorIndex: shapeIndex, + x: Math.floor((BOARD_WIDTH - shape[0].length) / 2), + y: 0, + }; + // Check if piece can't spawn (game over) + if (!this.canMovePiece(this.activePiece, 0, 0)) { + this.endGame(); + } + } + canMovePiece(piece, dx, dy) { + const newX = piece.x + dx; + const newY = piece.y + dy; + for (let y = 0; y < piece.shape.length; y++) { + for (let x = 0; x < piece.shape[y].length; x++) { + if (piece.shape[y][x] === 0) + continue; + const boardX = newX + x; + const boardY = newY + y; + // Check bounds + if (boardX < 0 || boardX >= BOARD_WIDTH || boardY >= BOARD_HEIGHT) { + return false; + } + // Check collision with placed pieces + if (boardY >= 0 && this.board[boardY][boardX] !== 0) { + return false; + } + } + } + return true; + } + rotatePieceRight() { + if (!this.activePiece) + return; + const rotated = this.rotatePieceShape(this.activePiece.shape); + const originalShape = this.activePiece.shape; + this.activePiece.shape = rotated; + // Wall kick: try to adjust position if rotation causes collision + if (!this.canMovePiece(this.activePiece, 0, 0)) { + // Try moving left + if (this.canMovePiece(this.activePiece, -1, 0)) { + this.activePiece.x -= 1; + } + // Try moving right + else if (this.canMovePiece(this.activePiece, 1, 0)) { + this.activePiece.x += 1; + } + // Rotation fails + else { + this.activePiece.shape = originalShape; + } + } + } + rotatePieceLeft() { + if (!this.activePiece) + return; + // Rotate left is same as rotating right 3 times + this.activePiece.shape = this.rotatePieceShape(this.activePiece.shape); + this.activePiece.shape = this.rotatePieceShape(this.activePiece.shape); + this.activePiece.shape = this.rotatePieceShape(this.activePiece.shape); + const originalShape = this.activePiece.shape; + // Wall kick + if (!this.canMovePiece(this.activePiece, 0, 0)) { + if (this.canMovePiece(this.activePiece, -1, 0)) { + this.activePiece.x -= 1; + } + else if (this.canMovePiece(this.activePiece, 1, 0)) { + this.activePiece.x += 1; + } + else { + this.activePiece.shape = originalShape; + } + } + } + rotatePieceShape(shape) { + const rows = shape.length; + const cols = shape[0].length; + const rotated = Array.from({ length: cols }, () => Array(rows).fill(0)); + for (let y = 0; y < rows; y++) { + for (let x = 0; x < cols; x++) { + rotated[x][rows - 1 - y] = shape[y][x]; + } + } + return rotated; + } + movePieceLeft() { + if (!this.activePiece || !this.canMovePiece(this.activePiece, -1, 0)) { + return; + } + this.activePiece.x -= 1; + } + movePieceRight() { + if (!this.activePiece || !this.canMovePiece(this.activePiece, 1, 0)) { + return; + } + this.activePiece.x += 1; + } + dropPieceOneCell() { + if (!this.activePiece) + return; + if (this.canMovePiece(this.activePiece, 0, 1)) { + this.activePiece.y += 1; + } + else { + this.lockPiece(); + } + } + dropPieceFast() { + if (!this.activePiece) + return; + while (this.canMovePiece(this.activePiece, 0, 1)) { + this.activePiece.y += 1; + } + this.lockPiece(); + } + dropPieceInstant() { + if (!this.activePiece) + return; + while (this.canMovePiece(this.activePiece, 0, 1)) { + this.activePiece.y += 1; + } + this.lockPiece(); + } + lockPiece() { + if (!this.activePiece) + return; + const { shape, colorIndex, x, y } = this.activePiece; + // Place piece on board + for (let py = 0; py < shape.length; py++) { + for (let px = 0; px < shape[py].length; px++) { + if (shape[py][px] === 0) + continue; + const boardY = y + py; + const boardX = x + px; + if (boardY >= 0) { + this.board[boardY][boardX] = colorIndex + 1; // +1 because 0 means empty + } + } + } + // Clear lines + this.clearLines(); + // Spawn next piece + this.spawnPiece(); + } + clearLines() { + let linesCleared = 0; + for (let y = BOARD_HEIGHT - 1; y >= 0; y--) { + if (this.board[y].every(cell => cell !== 0)) { + // Remove this line and add empty line at top + this.board.splice(y, 1); + this.board.unshift(Array(BOARD_WIDTH).fill(0)); + linesCleared++; + y++; // Check this row again + } + } + if (linesCleared > 0) { + this.lines += linesCleared; + // Scoring: Standard Tetris scoring + const pointsMap = [0, 100, 300, 500, 800]; + this.score += pointsMap[linesCleared] * this.level; + // Increase level every 10 lines + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel > this.level) { + this.level = newLevel; + this.dropInterval = INITIAL_DROP_INTERVAL * Math.pow(LEVEL_SPEED_MULTIPLIER, this.level - 1); + } + this.updateUI(); + } + } + render() { + // Clear canvas + this.ctx.fillStyle = '#1a1a1a'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw grid + this.ctx.strokeStyle = '#333333'; + this.ctx.lineWidth = 0.5; + for (let x = 0; x <= BOARD_WIDTH; x++) { + this.ctx.beginPath(); + this.ctx.moveTo(x * CELL_SIZE, 0); + this.ctx.lineTo(x * CELL_SIZE, this.canvas.height); + this.ctx.stroke(); + } + for (let y = 0; y <= BOARD_HEIGHT; y++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, y * CELL_SIZE); + this.ctx.lineTo(this.canvas.width, y * CELL_SIZE); + this.ctx.stroke(); + } + // Draw placed pieces + for (let y = 0; y < BOARD_HEIGHT; y++) { + for (let x = 0; x < BOARD_WIDTH; x++) { + const cellValue = this.board[y][x]; + if (cellValue !== 0) { + this.drawCell(x, y, COLORS[cellValue - 1]); + } + } + } + // Draw active piece + if (this.activePiece) { + const { shape, colorIndex, x, y } = this.activePiece; + for (let py = 0; py < shape.length; py++) { + for (let px = 0; px < shape[py].length; px++) { + if (shape[py][px] !== 0) { + this.drawCell(x + px, y + py, COLORS[colorIndex]); + } + } + } + } + } + drawCell(x, y, color) { + const padding = 1; + this.ctx.fillStyle = color; + this.ctx.fillRect(x * CELL_SIZE + padding, y * CELL_SIZE + padding, CELL_SIZE - 2 * padding, CELL_SIZE - 2 * padding); + // Add border for depth + this.ctx.strokeStyle = '#ffffff'; + this.ctx.lineWidth = 1; + this.ctx.strokeRect(x * CELL_SIZE + padding, y * CELL_SIZE + padding, CELL_SIZE - 2 * padding, CELL_SIZE - 2 * padding); + } + updateUI() { + const scoreElement = document.getElementById('score'); + const levelElement = document.getElementById('level'); + const linesElement = document.getElementById('lines'); + const nextElement = document.getElementById('next-piece'); + if (scoreElement) + scoreElement.textContent = this.score.toString(); + if (levelElement) + levelElement.textContent = this.level.toString(); + if (linesElement) + linesElement.textContent = this.lines.toString(); + if (nextElement) { + this.renderNextPiece(nextElement); + } + } + renderNextPiece(container) { + container.innerHTML = ''; + const canvas = document.createElement('canvas'); + canvas.width = 120; + canvas.height = 120; + canvas.style.backgroundColor = '#1a1a1a'; + canvas.style.border = '1px solid #666'; + const ctx = canvas.getContext('2d'); + const piece = PIECES[this.nextPieceIndex]; + const color = COLORS[this.nextPieceIndex]; + const cellSize = 24; + const offsetX = (120 - piece[0].length * cellSize) / 2; + const offsetY = (120 - piece.length * cellSize) / 2; + for (let y = 0; y < piece.length; y++) { + for (let x = 0; x < piece[y].length; x++) { + if (piece[y][x] !== 0) { + const px = offsetX + x * cellSize; + const py = offsetY + y * cellSize; + ctx.fillStyle = color; + ctx.fillRect(px + 1, py + 1, cellSize - 2, cellSize - 2); + ctx.strokeStyle = '#ffffff'; + ctx.lineWidth = 1; + ctx.strokeRect(px + 1, py + 1, cellSize - 2, cellSize - 2); + } + } + } + container.appendChild(canvas); + } + togglePause() { + // Note: This is just a flag toggle. A full implementation would pause the game loop. + } + endGame() { + this.gameRunning = false; + alert(`Game Over!\nFinal Score: ${this.score}\nLevel: ${this.level}\nLines: ${this.lines}`); + } + restart() { + this.board = Array.from({ length: BOARD_HEIGHT }, () => Array(BOARD_WIDTH).fill(0)); + this.score = 0; + this.level = 1; + this.lines = 0; + this.dropInterval = INITIAL_DROP_INTERVAL; + this.gameRunning = true; + this.lastDropTime = Date.now(); + this.nextPieceIndex = Math.floor(Math.random() * PIECES.length); + this.spawnPiece(); + this.updateUI(); + } +} +// Initialize game when DOM is ready +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', () => { + new TetrisGame('game-canvas'); + }); +} +else { + new TetrisGame('game-canvas'); +} +export { TetrisGame }; +//# sourceMappingURL=tetris.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tetris.js","sourceRoot":"","sources":["../src/tetris.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAK3C,kEAAkE;AAClE,MAAM,MAAM,GAAY;IACtB,iBAAiB;IACjB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAEd,mBAAmB;IACnB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEhB,mBAAmB;IACnB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAEtB,kBAAkB;IAClB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAEtB,gBAAgB;IAChB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAEtB,iBAAiB;IACjB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAEtB,mBAAmB;IACnB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,GAAG;IACb,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,aAAa;IACxB,SAAS,EAAE,aAAa;IACxB,SAAS,EAAE,YAAY;IACvB,SAAS,EAAE,UAAU;IACrB,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,aAAa;CACzB,CAAC;AAEF,MAAM,WAAW,GAAG,EAAE,CAAC;AACvB,MAAM,YAAY,GAAG,EAAE,CAAC;AACxB,MAAM,SAAS,GAAG,EAAE,CAAC;AACrB,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAClC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AASnC,MAAM,UAAU;IAad,YAAY,QAAgB;QAXpB,gBAAW,GAAuB,IAAI,CAAC;QAEvC,UAAK,GAAW,CAAC,CAAC;QAClB,UAAK,GAAW,CAAC,CAAC;QAClB,UAAK,GAAW,CAAC,CAAC;QAClB,iBAAY,GAAW,qBAAqB,CAAC;QAC7C,iBAAY,GAAW,CAAC,CAAC;QACzB,gBAAW,GAAY,IAAI,CAAC;QAsE5B,aAAQ,GAAG,GAAS,EAAE;YAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAEvB,IAAI,IAAI,CAAC,WAAW,IAAI,GAAG,GAAG,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBACrE,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACxB,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC;YAC1B,CAAC;YAED,IAAI,CAAC,MAAM,EAAE,CAAC;YACd,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC,CAAC;QA3EA,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAsB,CAAC;QACrE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,aAAa,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;QAEzC,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,WAAW,GAAG,SAAS,CAAC;QAC5C,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;QAE9C,mBAAmB;QACnB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,GAAG,EAAE,CACrD,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAC3B,CAAC;QAEF,4BAA4B;QAC5B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAEhE,oBAAoB;QACpB,IAAI,CAAC,UAAU,EAAE,CAAC;QAElB,0BAA0B;QAC1B,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAE7B,kBAAkB;QAClB,IAAI,CAAC,QAAQ,EAAE,CAAC;IAClB,CAAC;IAEO,qBAAqB;QAC3B,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;YACzC,IAAI,CAAC,IAAI,CAAC,WAAW;gBAAE,OAAO;YAE9B,QAAQ,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;gBAC5B,KAAK,WAAW;oBACd,CAAC,CAAC,cAAc,EAAE,CAAC;oBACnB,IAAI,CAAC,aAAa,EAAE,CAAC;oBACrB,MAAM;gBACR,KAAK,YAAY;oBACf,CAAC,CAAC,cAAc,EAAE,CAAC;oBACnB,IAAI,CAAC,cAAc,EAAE,CAAC;oBACtB,MAAM;gBACR,KAAK,WAAW;oBACd,CAAC,CAAC,cAAc,EAAE,CAAC;oBACnB,IAAI,CAAC,aAAa,EAAE,CAAC;oBACrB,MAAM;gBACR,KAAK,GAAG;oBACN,CAAC,CAAC,cAAc,EAAE,CAAC;oBACnB,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBACxB,MAAM;gBACR,KAAK,GAAG;oBACN,CAAC,CAAC,cAAc,EAAE,CAAC;oBACnB,IAAI,CAAC,eAAe,EAAE,CAAC;oBACvB,MAAM;gBACR,KAAK,GAAG,CAAC;gBACT,KAAK,SAAS;oBACZ,CAAC,CAAC,cAAc,EAAE,CAAC;oBACnB,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBACxB,MAAM;gBACR,KAAK,GAAG;oBACN,CAAC,CAAC,cAAc,EAAE,CAAC;oBACnB,IAAI,CAAC,WAAW,EAAE,CAAC;oBACnB,MAAM;YACV,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAcO,UAAU;QAChB,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;QAEjC,6BAA6B;QAC7B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAEhE,IAAI,CAAC,WAAW,GAAG;YACjB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;YACjC,UAAU,EAAE,UAAU;YACtB,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAClD,CAAC,EAAE,CAAC;SACL,CAAC;QAEF,yCAAyC;QACzC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YAC/C,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,KAAkB,EAAE,EAAU,EAAE,EAAU;QAC7D,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC;QAE1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/C,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;oBAAE,SAAS;gBAEtC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC;gBACxB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC;gBAExB,eAAe;gBACf,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,IAAI,WAAW,IAAI,MAAM,IAAI,YAAY,EAAE,CAAC;oBAClE,OAAO,KAAK,CAAC;gBACf,CAAC;gBAED,qCAAqC;gBACrC,IAAI,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;oBACpD,OAAO,KAAK,CAAC;gBACf,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,gBAAgB;QACtB,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAE9B,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC9D,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QAC7C,IAAI,CAAC,WAAW,CAAC,KAAK,GAAG,OAAO,CAAC;QAEjC,iEAAiE;QACjE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YAC/C,kBAAkB;YAClB,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBAC/C,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YACD,mBAAmB;iBACd,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACnD,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YACD,iBAAiB;iBACZ,CAAC;gBACJ,IAAI,CAAC,WAAW,CAAC,KAAK,GAAG,aAAa,CAAC;YACzC,CAAC;QACH,CAAC;IACH,CAAC;IAEO,eAAe;QACrB,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAE9B,gDAAgD;QAChD,IAAI,CAAC,WAAW,CAAC,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACvE,IAAI,CAAC,WAAW,CAAC,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACvE,IAAI,CAAC,WAAW,CAAC,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAEvE,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QAE7C,YAAY;QACZ,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YAC/C,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBAC/C,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;iBAAM,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACrD,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,WAAW,CAAC,KAAK,GAAG,aAAa,CAAC;YACzC,CAAC;QACH,CAAC;IACH,CAAC;IAEO,gBAAgB,CAAC,KAAY;QACnC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC;QAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC7B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAExE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC9B,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,aAAa;QACnB,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACrE,OAAO;QACT,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAEO,cAAc;QACpB,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACpE,OAAO;QACT,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAEO,gBAAgB;QACtB,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAE9B,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YAC9C,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,CAAC;IACH,CAAC;IAEO,aAAa;QACnB,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAE9B,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACjD,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QACD,IAAI,CAAC,SAAS,EAAE,CAAC;IACnB,CAAC;IAEO,gBAAgB;QACtB,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAE9B,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACjD,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QACD,IAAI,CAAC,SAAS,EAAE,CAAC;IACnB,CAAC;IAEO,SAAS;QACf,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAE9B,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC;QAErD,uBAAuB;QACvB,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;YACzC,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;gBAC7C,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;oBAAE,SAAS;gBAElC,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC;gBACtB,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC;gBAEtB,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;oBAChB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,UAAU,GAAG,CAAC,CAAC,CAAC,2BAA2B;gBAC1E,CAAC;YACH,CAAC;QACH,CAAC;QAED,cAAc;QACd,IAAI,CAAC,UAAU,EAAE,CAAC;QAElB,mBAAmB;QACnB,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAEO,UAAU;QAChB,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,KAAK,IAAI,CAAC,GAAG,YAAY,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC5C,6CAA6C;gBAC7C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACxB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC/C,YAAY,EAAE,CAAC;gBACf,CAAC,EAAE,CAAC,CAAC,uBAAuB;YAC9B,CAAC;QACH,CAAC;QAED,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC;YAE3B,mCAAmC;YACnC,MAAM,SAAS,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;YAC1C,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;YAEnD,gCAAgC;YAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;YACjD,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC1B,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;gBACtB,IAAI,CAAC,YAAY,GAAG,qBAAqB,GAAG,IAAI,CAAC,GAAG,CAAC,sBAAsB,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAC/F,CAAC;YAED,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,CAAC;IACH,CAAC;IAEO,MAAM;QACZ,eAAe;QACf,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAE/D,YAAY;QACZ,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,EAAE,CAAC,CAAC,CAAC;YAClC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACnD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACpB,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,YAAY,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;YAClC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;YAClD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACpB,CAAC;QAED,qBAAqB;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACnC,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;oBACpB,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC7C,CAAC;YACH,CAAC;QACH,CAAC;QAED,oBAAoB;QACpB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC;YACrD,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;gBACzC,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;oBAC7C,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;wBACxB,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;oBACpD,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAEO,QAAQ,CAAC,CAAS,EAAE,CAAS,EAAE,KAAa;QAClD,MAAM,OAAO,GAAG,CAAC,CAAC;QAClB,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC;QAC3B,IAAI,CAAC,GAAG,CAAC,QAAQ,CACf,CAAC,GAAG,SAAS,GAAG,OAAO,EACvB,CAAC,GAAG,SAAS,GAAG,OAAO,EACvB,SAAS,GAAG,CAAC,GAAG,OAAO,EACvB,SAAS,GAAG,CAAC,GAAG,OAAO,CACxB,CAAC;QAEF,uBAAuB;QACvB,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,UAAU,CACjB,CAAC,GAAG,SAAS,GAAG,OAAO,EACvB,CAAC,GAAG,SAAS,GAAG,OAAO,EACvB,SAAS,GAAG,CAAC,GAAG,OAAO,EACvB,SAAS,GAAG,CAAC,GAAG,OAAO,CACxB,CAAC;IACJ,CAAC;IAEO,QAAQ;QACd,MAAM,YAAY,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACtD,MAAM,YAAY,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACtD,MAAM,YAAY,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACtD,MAAM,WAAW,GAAG,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;QAE1D,IAAI,YAAY;YAAE,YAAY,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QACnE,IAAI,YAAY;YAAE,YAAY,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QACnE,IAAI,YAAY;YAAE,YAAY,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAEnE,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAEO,eAAe,CAAC,SAAsB;QAC5C,SAAS,CAAC,SAAS,GAAG,EAAE,CAAC;QAEzB,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC;QACnB,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC;QACpB,MAAM,CAAC,KAAK,CAAC,eAAe,GAAG,SAAS,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,gBAAgB,CAAC;QAEvC,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;QACrC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAE1C,MAAM,QAAQ,GAAG,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QACvD,MAAM,OAAO,GAAG,CAAC,GAAG,GAAG,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAEpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACzC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;oBACtB,MAAM,EAAE,GAAG,OAAO,GAAG,CAAC,GAAG,QAAQ,CAAC;oBAClC,MAAM,EAAE,GAAG,OAAO,GAAG,CAAC,GAAG,QAAQ,CAAC;oBAElC,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC;oBACtB,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;oBACzD,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC;oBAC5B,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;oBAClB,GAAG,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC;QACH,CAAC;QAED,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IAEO,WAAW;QACjB,qFAAqF;IACvF,CAAC;IAEO,OAAO;QACb,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,KAAK,CAAC,4BAA4B,IAAI,CAAC,KAAK,YAAY,IAAI,CAAC,KAAK,YAAY,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAC9F,CAAC;IAEM,OAAO;QACZ,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,GAAG,EAAE,CACrD,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAC3B,CAAC;QACF,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,YAAY,GAAG,qBAAqB,CAAC;QAC1C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAChE,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,QAAQ,EAAE,CAAC;IAClB,CAAC;CACF;AAED,oCAAoC;AACpC,IAAI,QAAQ,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;IACtC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;QACjD,IAAI,UAAU,CAAC,aAAa,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC;KAAM,CAAC;IACN,IAAI,UAAU,CAAC,aAAa,CAAC,CAAC;AAChC,CAAC;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/bundle.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/bundle.js @@ -0,0 +1,473 @@ +var __getOwnPropNames = Object.getOwnPropertyNames; +var __esm = (fn, res) => function __init() { + return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; +}; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; + +// src/game.ts +var PIECES, Tetris; +var init_game = __esm({ + "src/game.ts"() { + "use strict"; + PIECES = { + I: { + shape: [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + color: "#00F0F0" + }, + O: { + shape: [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + color: "#F0F000" + }, + T: { + shape: [[0, 1, 0, 0], [1, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + color: "#A000F0" + }, + S: { + shape: [[0, 1, 1, 0], [1, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + color: "#00F000" + }, + Z: { + shape: [[1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + color: "#F00000" + }, + J: { + shape: [[1, 0, 0, 0], [1, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + color: "#0000F0" + }, + L: { + shape: [[0, 0, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + color: "#F0A000" + } + }; + Tetris = class { + constructor(width = 10, height = 20) { + this.currentPiece = null; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.dropInterval = 1e3; + this.lastDropTime = 0; + this.paused = false; + this.width = width; + this.height = height; + this.board = Array(height).fill(null).map(() => Array(width).fill(0)); + const pieceKeys = Object.keys(PIECES); + this.nextPiece = PIECES[pieceKeys[Math.floor(Math.random() * pieceKeys.length)]]; + this.spawnPiece(); + } + spawnPiece() { + const piece = this.nextPiece; + const pieceKeys = Object.keys(PIECES); + this.nextPiece = PIECES[pieceKeys[Math.floor(Math.random() * pieceKeys.length)]]; + this.currentPiece = { + x: Math.floor(this.width / 2) - 2, + y: 0, + shape: piece.shape.map((row) => [...row]), + color: piece.color + }; + if (!this.canPlace(this.currentPiece)) { + this.gameOver = true; + } + } + canPlace(piece) { + for (let y = 0; y < piece.shape.length; y++) { + for (let x = 0; x < piece.shape[y].length; x++) { + if (piece.shape[y][x]) { + const boardX = piece.x + x; + const boardY = piece.y + y; + if (boardX < 0 || boardX >= this.width || boardY >= this.height) { + return false; + } + if (boardY >= 0 && this.board[boardY][boardX]) { + return false; + } + } + } + } + return true; + } + lockPiece() { + if (!this.currentPiece) return; + for (let y = 0; y < this.currentPiece.shape.length; y++) { + for (let x = 0; x < this.currentPiece.shape[y].length; x++) { + if (this.currentPiece.shape[y][x]) { + const boardX = this.currentPiece.x + x; + const boardY = this.currentPiece.y + y; + if (boardY >= 0) { + this.board[boardY][boardX] = this.colorToNumber(this.currentPiece.color); + } + } + } + } + this.clearLines(); + this.spawnPiece(); + } + colorToNumber(color) { + const colorMap = { + "#00F0F0": 1, + "#F0F000": 2, + "#A000F0": 3, + "#00F000": 4, + "#F00000": 5, + "#0000F0": 6, + "#F0A000": 7 + }; + return colorMap[color] || 1; + } + clearLines() { + let clearedLines = 0; + for (let y = this.height - 1; y >= 0; y--) { + if (this.board[y].every((cell) => cell !== 0)) { + this.board.splice(y, 1); + this.board.unshift(Array(this.width).fill(0)); + clearedLines++; + y++; + } + } + if (clearedLines > 0) { + this.lines += clearedLines; + const points = [0, 100, 300, 500, 800]; + this.score += points[clearedLines] * this.level; + this.updateLevel(); + } + } + updateLevel() { + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel !== this.level) { + this.level = newLevel; + this.dropInterval = Math.max(100, 1e3 - (this.level - 1) * 100); + } + } + movePiece(dx, dy = 0) { + if (!this.currentPiece || this.gameOver || this.paused) return false; + const newPiece = { + ...this.currentPiece, + x: this.currentPiece.x + dx, + y: this.currentPiece.y + dy + }; + if (this.canPlace(newPiece)) { + this.currentPiece = newPiece; + return true; + } + if (dy > 0) { + this.lockPiece(); + return true; + } + return false; + } + rotatePiece() { + if (!this.currentPiece || this.gameOver || this.paused) return false; + const rotated = this.rotateShape(this.currentPiece.shape); + const newPiece = { ...this.currentPiece, shape: rotated }; + if (this.canPlace(newPiece)) { + this.currentPiece = newPiece; + return true; + } + return false; + } + rotateShape(shape) { + const n = shape.length; + const rotated = Array(n).fill(null).map(() => Array(n).fill(0)); + for (let y = 0; y < n; y++) { + for (let x = 0; x < n; x++) { + rotated[x][n - 1 - y] = shape[y][x]; + } + } + return rotated; + } + update(deltaTime) { + if (this.gameOver || this.paused) return; + this.lastDropTime += deltaTime; + if (this.lastDropTime >= this.dropInterval) { + this.lastDropTime = 0; + if (!this.movePiece(0, 1)) { + } + } + } + togglePause() { + this.paused = !this.paused; + } + restart() { + this.board = Array(this.height).fill(null).map(() => Array(this.width).fill(0)); + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.lastDropTime = 0; + this.paused = false; + this.dropInterval = 1e3; + const pieceKeys = Object.keys(PIECES); + this.nextPiece = PIECES[pieceKeys[Math.floor(Math.random() * pieceKeys.length)]]; + this.spawnPiece(); + } + getBoard() { + return this.board; + } + getCurrentPiece() { + return this.currentPiece; + } + getNextPiece() { + return this.nextPiece; + } + }; + } +}); + +// src/renderer.ts +var COLORS, Renderer, NextPieceRenderer; +var init_renderer = __esm({ + "src/renderer.ts"() { + "use strict"; + COLORS = { + 0: "#1a1a1a", + 1: "#00F0F0", + // I + 2: "#F0F000", + // O + 3: "#A000F0", + // T + 4: "#00F000", + // S + 5: "#F00000", + // Z + 6: "#0000F0", + // J + 7: "#F0A000" + // L + }; + Renderer = class { + constructor(canvas, blockSize = 30) { + this.gridLineColor = "#333333"; + this.canvas = canvas; + const ctx = canvas.getContext("2d"); + if (!ctx) throw new Error("Could not get canvas context"); + this.ctx = ctx; + this.blockSize = blockSize; + this.width = canvas.width; + this.height = canvas.height; + this.ctx.fillStyle = "#000000"; + this.ctx.fillRect(0, 0, this.width, this.height); + } + render(game) { + this.ctx.fillStyle = "#000000"; + this.ctx.fillRect(0, 0, this.width, this.height); + this.drawBoard(game); + if (game.getCurrentPiece()) { + this.drawPiece(game.getCurrentPiece()); + } + this.drawGrid(game); + if (game.gameOver) { + this.drawGameOver(); + } + if (game.paused) { + this.drawPause(); + } + } + drawBoard(game) { + const board = game.getBoard(); + for (let y = 0; y < board.length; y++) { + for (let x = 0; x < board[y].length; x++) { + if (board[y][x] !== 0) { + this.drawBlock(x, y, COLORS[board[y][x]]); + } + } + } + } + drawPiece(piece) { + for (let y = 0; y < piece.shape.length; y++) { + for (let x = 0; x < piece.shape[y].length; x++) { + if (piece.shape[y][x]) { + const boardX = piece.x + x; + const boardY = piece.y + y; + if (boardY >= 0) { + this.drawBlock(boardX, boardY, piece.color); + } + } + } + } + } + drawBlock(x, y, color) { + const px = x * this.blockSize; + const py = y * this.blockSize; + this.ctx.fillStyle = color; + this.ctx.fillRect(px, py, this.blockSize, this.blockSize); + this.ctx.strokeStyle = "#000000"; + this.ctx.lineWidth = 1; + this.ctx.strokeRect(px, py, this.blockSize, this.blockSize); + this.ctx.strokeStyle = "rgba(255, 255, 255, 0.2)"; + this.ctx.lineWidth = 1; + this.ctx.beginPath(); + this.ctx.moveTo(px, py); + this.ctx.lineTo(px + this.blockSize, py); + this.ctx.lineTo(px + this.blockSize, py + this.blockSize); + this.ctx.stroke(); + } + drawGrid(game) { + this.ctx.strokeStyle = this.gridLineColor; + this.ctx.lineWidth = 0.5; + for (let x = 0; x <= game.width; x++) { + this.ctx.beginPath(); + this.ctx.moveTo(x * this.blockSize, 0); + this.ctx.lineTo(x * this.blockSize, game.height * this.blockSize); + this.ctx.stroke(); + } + for (let y = 0; y <= game.height; y++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, y * this.blockSize); + this.ctx.lineTo(game.width * this.blockSize, y * this.blockSize); + this.ctx.stroke(); + } + } + drawGameOver() { + this.ctx.fillStyle = "rgba(0, 0, 0, 0.7)"; + this.ctx.fillRect(0, 0, this.width, this.height); + this.ctx.fillStyle = "#FF0000"; + this.ctx.font = "bold 48px Arial"; + this.ctx.textAlign = "center"; + this.ctx.textBaseline = "middle"; + this.ctx.fillText("GAME OVER", this.width / 2, this.height / 2 - 30); + this.ctx.fillStyle = "#FFFFFF"; + this.ctx.font = "24px Arial"; + this.ctx.fillText("Press R to restart", this.width / 2, this.height / 2 + 30); + } + drawPause() { + this.ctx.fillStyle = "rgba(0, 0, 0, 0.5)"; + this.ctx.fillRect(0, 0, this.width, this.height); + this.ctx.fillStyle = "#FFFF00"; + this.ctx.font = "bold 48px Arial"; + this.ctx.textAlign = "center"; + this.ctx.textBaseline = "middle"; + this.ctx.fillText("PAUSED", this.width / 2, this.height / 2); + this.ctx.fillStyle = "#FFFFFF"; + this.ctx.font = "20px Arial"; + this.ctx.fillText("Press P to resume", this.width / 2, this.height / 2 + 50); + } + }; + NextPieceRenderer = class { + constructor(canvas, blockSize = 20) { + this.canvas = canvas; + const ctx = canvas.getContext("2d"); + if (!ctx) throw new Error("Could not get canvas context"); + this.ctx = ctx; + this.blockSize = blockSize; + this.ctx.fillStyle = "#1a1a1a"; + this.ctx.fillRect(0, 0, canvas.width, canvas.height); + } + render(piece) { + this.ctx.fillStyle = "#1a1a1a"; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.strokeStyle = "#666666"; + this.ctx.lineWidth = 2; + this.ctx.strokeRect(1, 1, this.canvas.width - 2, this.canvas.height - 2); + const startX = (4 - piece.shape[0].length) * this.blockSize; + const startY = 0; + for (let y = 0; y < piece.shape.length; y++) { + for (let x = 0; x < piece.shape[y].length; x++) { + if (piece.shape[y][x]) { + const px = startX + x * this.blockSize; + const py = startY + y * this.blockSize; + this.ctx.fillStyle = piece.color; + this.ctx.fillRect(px, py, this.blockSize, this.blockSize); + this.ctx.strokeStyle = "#000000"; + this.ctx.lineWidth = 1; + this.ctx.strokeRect(px, py, this.blockSize, this.blockSize); + } + } + } + } + }; + } +}); + +// src/main.ts +var require_main = __commonJS({ + "src/main.ts"() { + init_game(); + init_renderer(); + var TetrisApp = class { + constructor() { + this.lastFrameTime = 0; + this.isRunning = true; + this.gameCanvas = document.getElementById("gameCanvas"); + this.nextPieceCanvas = document.getElementById("nextPieceCanvas"); + if (!this.gameCanvas || !this.nextPieceCanvas) { + throw new Error("Required canvas elements not found"); + } + this.scoreDisplay = document.getElementById("score"); + this.levelDisplay = document.getElementById("level"); + this.linesDisplay = document.getElementById("lines"); + this.game = new Tetris(10, 20); + this.renderer = new Renderer(this.gameCanvas, 30); + this.nextPieceRenderer = new NextPieceRenderer(this.nextPieceCanvas, 20); + this.setupEventListeners(); + this.startGameLoop(); + this.render(); + } + setupEventListeners() { + document.addEventListener("keydown", (e) => this.handleKeyDown(e)); + } + handleKeyDown(event) { + switch (event.key.toLowerCase()) { + case "arrowleft": + event.preventDefault(); + this.game.movePiece(-1, 0); + break; + case "arrowright": + event.preventDefault(); + this.game.movePiece(1, 0); + break; + case "arrowdown": + event.preventDefault(); + this.game.movePiece(0, 1); + break; + case " ": + event.preventDefault(); + this.game.rotatePiece(); + break; + case "p": + event.preventDefault(); + this.game.togglePause(); + break; + case "r": + event.preventDefault(); + this.game.restart(); + break; + case "enter": + event.preventDefault(); + if (!this.isRunning) { + this.game.restart(); + } + break; + } + } + startGameLoop() { + const loop = (timestamp) => { + if (this.lastFrameTime === 0) { + this.lastFrameTime = timestamp; + } + const deltaTime = timestamp - this.lastFrameTime; + this.lastFrameTime = timestamp; + this.game.update(deltaTime); + this.render(); + requestAnimationFrame(loop); + }; + requestAnimationFrame(loop); + } + render() { + this.renderer.render(this.game); + const nextPiece = this.game.getNextPiece(); + this.nextPieceRenderer.render(nextPiece); + this.scoreDisplay.textContent = this.game.score.toString(); + this.levelDisplay.textContent = this.game.level.toString(); + this.linesDisplay.textContent = this.game.lines.toString(); + } + }; + document.addEventListener("DOMContentLoaded", () => { + new TetrisApp(); + }); + } +}); +export default require_main(); diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts @@ -0,0 +1,48 @@ +export type Piece = { + shape: number[][]; + color: string; +}; +export declare const PIECES: { + [key: string]: Piece; +}; +export declare class Tetris { + width: number; + height: number; + board: number[][]; + currentPiece: { + x: number; + y: number; + shape: number[][]; + color: string; + } | null; + nextPiece: Piece; + score: number; + lines: number; + level: number; + gameOver: boolean; + dropInterval: number; + lastDropTime: number; + paused: boolean; + constructor(width?: number, height?: number); + private spawnPiece; + private canPlace; + private lockPiece; + private colorToNumber; + private clearLines; + private updateLevel; + movePiece(dx: number, dy?: number): boolean; + rotatePiece(): boolean; + private rotateShape; + update(deltaTime: number): void; + togglePause(): void; + restart(): void; + getBoard(): number[][]; + getCurrentPiece(): { + x: number; + y: number; + shape: number[][]; + color: string; + } | null; + getNextPiece(): Piece; +} +//# sourceMappingURL=game.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts.map b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"game.d.ts","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,KAAK,GAAG;IAClB,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAA;CA6B1C,CAAC;AAEF,qBAAa,MAAM;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;IAClB,YAAY,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAQ;IACvF,SAAS,EAAE,KAAK,CAAC;IACjB,KAAK,EAAE,MAAM,CAAK;IAClB,KAAK,EAAE,MAAM,CAAK;IAClB,KAAK,EAAE,MAAM,CAAK;IAClB,QAAQ,EAAE,OAAO,CAAS;IAC1B,YAAY,EAAE,MAAM,CAAQ;IAC5B,YAAY,EAAE,MAAM,CAAK;IACzB,MAAM,EAAE,OAAO,CAAS;gBAEZ,KAAK,GAAE,MAAW,EAAE,MAAM,GAAE,MAAW;IAYnD,OAAO,CAAC,UAAU;IAiBlB,OAAO,CAAC,QAAQ;IAoBhB,OAAO,CAAC,SAAS;IAoBjB,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,UAAU;IAoBlB,OAAO,CAAC,WAAW;IAQnB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,GAAE,MAAU,GAAG,OAAO;IAsB9C,WAAW,IAAI,OAAO;IAetB,OAAO,CAAC,WAAW;IAenB,MAAM,CAAC,SAAS,EAAE,MAAM;IAaxB,WAAW;IAIX,OAAO;IAgBP,QAAQ;IAIR,eAAe;WAjNI,MAAM;WAAK,MAAM;eAAS,MAAM,EAAE,EAAE;eAAS,MAAM;;IAqNtE,YAAY;CAGb"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js @@ -0,0 +1,216 @@ +// Tetris Game Logic +export const PIECES = { + I: { + shape: [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + color: "#00F0F0", + }, + O: { + shape: [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + color: "#F0F000", + }, + T: { + shape: [[0, 1, 0, 0], [1, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + color: "#A000F0", + }, + S: { + shape: [[0, 1, 1, 0], [1, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + color: "#00F000", + }, + Z: { + shape: [[1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + color: "#F00000", + }, + J: { + shape: [[1, 0, 0, 0], [1, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + color: "#0000F0", + }, + L: { + shape: [[0, 0, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + color: "#F0A000", + }, +}; +export class Tetris { + constructor(width = 10, height = 20) { + this.currentPiece = null; + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.dropInterval = 1000; + this.lastDropTime = 0; + this.paused = false; + this.width = width; + this.height = height; + this.board = Array(height) + .fill(null) + .map(() => Array(width).fill(0)); + const pieceKeys = Object.keys(PIECES); + this.nextPiece = PIECES[pieceKeys[Math.floor(Math.random() * pieceKeys.length)]]; + this.spawnPiece(); + } + spawnPiece() { + const piece = this.nextPiece; + const pieceKeys = Object.keys(PIECES); + this.nextPiece = PIECES[pieceKeys[Math.floor(Math.random() * pieceKeys.length)]]; + this.currentPiece = { + x: Math.floor(this.width / 2) - 2, + y: 0, + shape: piece.shape.map((row) => [...row]), + color: piece.color, + }; + if (!this.canPlace(this.currentPiece)) { + this.gameOver = true; + } + } + canPlace(piece) { + for (let y = 0; y < piece.shape.length; y++) { + for (let x = 0; x < piece.shape[y].length; x++) { + if (piece.shape[y][x]) { + const boardX = piece.x + x; + const boardY = piece.y + y; + if (boardX < 0 || boardX >= this.width || boardY >= this.height) { + return false; + } + if (boardY >= 0 && this.board[boardY][boardX]) { + return false; + } + } + } + } + return true; + } + lockPiece() { + if (!this.currentPiece) + return; + for (let y = 0; y < this.currentPiece.shape.length; y++) { + for (let x = 0; x < this.currentPiece.shape[y].length; x++) { + if (this.currentPiece.shape[y][x]) { + const boardX = this.currentPiece.x + x; + const boardY = this.currentPiece.y + y; + if (boardY >= 0) { + this.board[boardY][boardX] = this.colorToNumber(this.currentPiece.color); + } + } + } + } + this.clearLines(); + this.spawnPiece(); + } + colorToNumber(color) { + const colorMap = { + "#00F0F0": 1, + "#F0F000": 2, + "#A000F0": 3, + "#00F000": 4, + "#F00000": 5, + "#0000F0": 6, + "#F0A000": 7, + }; + return colorMap[color] || 1; + } + clearLines() { + let clearedLines = 0; + for (let y = this.height - 1; y >= 0; y--) { + if (this.board[y].every((cell) => cell !== 0)) { + this.board.splice(y, 1); + this.board.unshift(Array(this.width).fill(0)); + clearedLines++; + y++; // Check this row again + } + } + if (clearedLines > 0) { + this.lines += clearedLines; + const points = [0, 100, 300, 500, 800]; + this.score += points[clearedLines] * this.level; + this.updateLevel(); + } + } + updateLevel() { + const newLevel = Math.floor(this.lines / 10) + 1; + if (newLevel !== this.level) { + this.level = newLevel; + this.dropInterval = Math.max(100, 1000 - (this.level - 1) * 100); + } + } + movePiece(dx, dy = 0) { + if (!this.currentPiece || this.gameOver || this.paused) + return false; + const newPiece = { + ...this.currentPiece, + x: this.currentPiece.x + dx, + y: this.currentPiece.y + dy, + }; + if (this.canPlace(newPiece)) { + this.currentPiece = newPiece; + return true; + } + if (dy > 0) { + this.lockPiece(); + return true; + } + return false; + } + rotatePiece() { + if (!this.currentPiece || this.gameOver || this.paused) + return false; + // Rotate the shape + const rotated = this.rotateShape(this.currentPiece.shape); + const newPiece = { ...this.currentPiece, shape: rotated }; + if (this.canPlace(newPiece)) { + this.currentPiece = newPiece; + return true; + } + return false; + } + rotateShape(shape) { + const n = shape.length; + const rotated = Array(n) + .fill(null) + .map(() => Array(n).fill(0)); + for (let y = 0; y < n; y++) { + for (let x = 0; x < n; x++) { + rotated[x][n - 1 - y] = shape[y][x]; + } + } + return rotated; + } + update(deltaTime) { + if (this.gameOver || this.paused) + return; + this.lastDropTime += deltaTime; + if (this.lastDropTime >= this.dropInterval) { + this.lastDropTime = 0; + if (!this.movePiece(0, 1)) { + // Piece couldn't move down, it's already locked + } + } + } + togglePause() { + this.paused = !this.paused; + } + restart() { + this.board = Array(this.height) + .fill(null) + .map(() => Array(this.width).fill(0)); + this.score = 0; + this.lines = 0; + this.level = 1; + this.gameOver = false; + this.lastDropTime = 0; + this.paused = false; + this.dropInterval = 1000; + const pieceKeys = Object.keys(PIECES); + this.nextPiece = PIECES[pieceKeys[Math.floor(Math.random() * pieceKeys.length)]]; + this.spawnPiece(); + } + getBoard() { + return this.board; + } + getCurrentPiece() { + return this.currentPiece; + } + getNextPiece() { + return this.nextPiece; + } +} +//# sourceMappingURL=game.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js.map b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/game.js.map @@ -0,0 +1 @@ +{"version":3,"file":"game.js","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/main.d.ts b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/main.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=main.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/main.d.ts.map b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/main.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/main.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/main.js @@ -0,0 +1,98 @@ +// Main Tetris Application +import { Tetris } from "./game"; +import { Renderer, NextPieceRenderer } from "./renderer"; +class TetrisApp { + constructor() { + this.lastFrameTime = 0; + this.isRunning = true; + // Get canvas elements + this.gameCanvas = document.getElementById("gameCanvas"); + this.nextPieceCanvas = document.getElementById("nextPieceCanvas"); + if (!this.gameCanvas || !this.nextPieceCanvas) { + throw new Error("Required canvas elements not found"); + } + // Get display elements + this.scoreDisplay = document.getElementById("score"); + this.levelDisplay = document.getElementById("level"); + this.linesDisplay = document.getElementById("lines"); + // Initialize game and renderers + this.game = new Tetris(10, 20); + this.renderer = new Renderer(this.gameCanvas, 30); + this.nextPieceRenderer = new NextPieceRenderer(this.nextPieceCanvas, 20); + // Set up event listeners + this.setupEventListeners(); + // Start game loop + this.startGameLoop(); + // Initial render + this.render(); + } + setupEventListeners() { + document.addEventListener("keydown", (e) => this.handleKeyDown(e)); + } + handleKeyDown(event) { + switch (event.key.toLowerCase()) { + case "arrowleft": + event.preventDefault(); + this.game.movePiece(-1, 0); + break; + case "arrowright": + event.preventDefault(); + this.game.movePiece(1, 0); + break; + case "arrowdown": + event.preventDefault(); + this.game.movePiece(0, 1); + break; + case " ": + event.preventDefault(); + this.game.rotatePiece(); + break; + case "p": + event.preventDefault(); + this.game.togglePause(); + break; + case "r": + event.preventDefault(); + this.game.restart(); + break; + case "enter": + event.preventDefault(); + if (!this.isRunning) { + this.game.restart(); + } + break; + } + } + startGameLoop() { + const loop = (timestamp) => { + if (this.lastFrameTime === 0) { + this.lastFrameTime = timestamp; + } + const deltaTime = timestamp - this.lastFrameTime; + this.lastFrameTime = timestamp; + // Update game + this.game.update(deltaTime); + // Render + this.render(); + // Continue loop + requestAnimationFrame(loop); + }; + requestAnimationFrame(loop); + } + render() { + // Render main game canvas + this.renderer.render(this.game); + // Render next piece + const nextPiece = this.game.getNextPiece(); + this.nextPieceRenderer.render(nextPiece); + // Update UI + this.scoreDisplay.textContent = this.game.score.toString(); + this.levelDisplay.textContent = this.game.level.toString(); + this.linesDisplay.textContent = this.game.lines.toString(); + } +} +// Initialize app when DOM is ready +document.addEventListener("DOMContentLoaded", () => { + new TetrisApp(); +}); +//# sourceMappingURL=main.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/main.js.map b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/main.js.map @@ -0,0 +1 @@ +{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/renderer.d.ts b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/renderer.d.ts @@ -0,0 +1,28 @@ +import type { Tetris } from "./game"; +export declare class Renderer { + canvas: HTMLCanvasElement; + ctx: CanvasRenderingContext2D; + blockSize: number; + width: number; + height: number; + gridLineColor: string; + constructor(canvas: HTMLCanvasElement, blockSize?: number); + render(game: Tetris): void; + private drawBoard; + private drawPiece; + private drawBlock; + private drawGrid; + private drawGameOver; + private drawPause; +} +export declare class NextPieceRenderer { + canvas: HTMLCanvasElement; + ctx: CanvasRenderingContext2D; + blockSize: number; + constructor(canvas: HTMLCanvasElement, blockSize?: number); + render(piece: { + shape: number[][]; + color: string; + }): void; +} +//# sourceMappingURL=renderer.d.ts.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/renderer.d.ts.map b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/renderer.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAarC,qBAAa,QAAQ;IACnB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,GAAG,EAAE,wBAAwB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAa;gBAEtB,MAAM,EAAE,iBAAiB,EAAE,SAAS,GAAE,MAAW;IAc7D,MAAM,CAAC,IAAI,EAAE,MAAM;IA2BnB,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,SAAS;IAmBjB,OAAO,CAAC,SAAS;IAuBjB,OAAO,CAAC,QAAQ;IAqBhB,OAAO,CAAC,YAAY;IAiBpB,OAAO,CAAC,SAAS;CAgBlB;AAED,qBAAa,iBAAiB;IAC5B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,GAAG,EAAE,wBAAwB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;gBAEN,MAAM,EAAE,iBAAiB,EAAE,SAAS,GAAE,MAAW;IAY7D,MAAM,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;CAgCnD"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/renderer.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/renderer.js @@ -0,0 +1,177 @@ +// Tetris Game Renderer +const COLORS = { + 0: "#1a1a1a", + 1: "#00F0F0", // I + 2: "#F0F000", // O + 3: "#A000F0", // T + 4: "#00F000", // S + 5: "#F00000", // Z + 6: "#0000F0", // J + 7: "#F0A000", // L +}; +export class Renderer { + constructor(canvas, blockSize = 30) { + this.gridLineColor = "#333333"; + this.canvas = canvas; + const ctx = canvas.getContext("2d"); + if (!ctx) + throw new Error("Could not get canvas context"); + this.ctx = ctx; + this.blockSize = blockSize; + this.width = canvas.width; + this.height = canvas.height; + // Set background + this.ctx.fillStyle = "#000000"; + this.ctx.fillRect(0, 0, this.width, this.height); + } + render(game) { + // Clear canvas + this.ctx.fillStyle = "#000000"; + this.ctx.fillRect(0, 0, this.width, this.height); + // Draw board + this.drawBoard(game); + // Draw current piece + if (game.getCurrentPiece()) { + this.drawPiece(game.getCurrentPiece()); + } + // Draw grid + this.drawGrid(game); + // Draw game over overlay + if (game.gameOver) { + this.drawGameOver(); + } + // Draw pause overlay + if (game.paused) { + this.drawPause(); + } + } + drawBoard(game) { + const board = game.getBoard(); + for (let y = 0; y < board.length; y++) { + for (let x = 0; x < board[y].length; x++) { + if (board[y][x] !== 0) { + this.drawBlock(x, y, COLORS[board[y][x]]); + } + } + } + } + drawPiece(piece) { + for (let y = 0; y < piece.shape.length; y++) { + for (let x = 0; x < piece.shape[y].length; x++) { + if (piece.shape[y][x]) { + const boardX = piece.x + x; + const boardY = piece.y + y; + if (boardY >= 0) { + this.drawBlock(boardX, boardY, piece.color); + } + } + } + } + } + drawBlock(x, y, color) { + const px = x * this.blockSize; + const py = y * this.blockSize; + // Draw filled block + this.ctx.fillStyle = color; + this.ctx.fillRect(px, py, this.blockSize, this.blockSize); + // Draw border + this.ctx.strokeStyle = "#000000"; + this.ctx.lineWidth = 1; + this.ctx.strokeRect(px, py, this.blockSize, this.blockSize); + // Draw highlight for depth + this.ctx.strokeStyle = "rgba(255, 255, 255, 0.2)"; + this.ctx.lineWidth = 1; + this.ctx.beginPath(); + this.ctx.moveTo(px, py); + this.ctx.lineTo(px + this.blockSize, py); + this.ctx.lineTo(px + this.blockSize, py + this.blockSize); + this.ctx.stroke(); + } + drawGrid(game) { + this.ctx.strokeStyle = this.gridLineColor; + this.ctx.lineWidth = 0.5; + // Vertical lines + for (let x = 0; x <= game.width; x++) { + this.ctx.beginPath(); + this.ctx.moveTo(x * this.blockSize, 0); + this.ctx.lineTo(x * this.blockSize, game.height * this.blockSize); + this.ctx.stroke(); + } + // Horizontal lines + for (let y = 0; y <= game.height; y++) { + this.ctx.beginPath(); + this.ctx.moveTo(0, y * this.blockSize); + this.ctx.lineTo(game.width * this.blockSize, y * this.blockSize); + this.ctx.stroke(); + } + } + drawGameOver() { + // Semi-transparent overlay + this.ctx.fillStyle = "rgba(0, 0, 0, 0.7)"; + this.ctx.fillRect(0, 0, this.width, this.height); + // Text + this.ctx.fillStyle = "#FF0000"; + this.ctx.font = "bold 48px Arial"; + this.ctx.textAlign = "center"; + this.ctx.textBaseline = "middle"; + this.ctx.fillText("GAME OVER", this.width / 2, this.height / 2 - 30); + this.ctx.fillStyle = "#FFFFFF"; + this.ctx.font = "24px Arial"; + this.ctx.fillText("Press R to restart", this.width / 2, this.height / 2 + 30); + } + drawPause() { + // Semi-transparent overlay + this.ctx.fillStyle = "rgba(0, 0, 0, 0.5)"; + this.ctx.fillRect(0, 0, this.width, this.height); + // Text + this.ctx.fillStyle = "#FFFF00"; + this.ctx.font = "bold 48px Arial"; + this.ctx.textAlign = "center"; + this.ctx.textBaseline = "middle"; + this.ctx.fillText("PAUSED", this.width / 2, this.height / 2); + this.ctx.fillStyle = "#FFFFFF"; + this.ctx.font = "20px Arial"; + this.ctx.fillText("Press P to resume", this.width / 2, this.height / 2 + 50); + } +} +export class NextPieceRenderer { + constructor(canvas, blockSize = 20) { + this.canvas = canvas; + const ctx = canvas.getContext("2d"); + if (!ctx) + throw new Error("Could not get canvas context"); + this.ctx = ctx; + this.blockSize = blockSize; + // Set background + this.ctx.fillStyle = "#1a1a1a"; + this.ctx.fillRect(0, 0, canvas.width, canvas.height); + } + render(piece) { + // Clear canvas + this.ctx.fillStyle = "#1a1a1a"; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + // Draw border + this.ctx.strokeStyle = "#666666"; + this.ctx.lineWidth = 2; + this.ctx.strokeRect(1, 1, this.canvas.width - 2, this.canvas.height - 2); + // Draw piece + const startX = (4 - piece.shape[0].length) * this.blockSize; + const startY = 0; + for (let y = 0; y < piece.shape.length; y++) { + for (let x = 0; x < piece.shape[y].length; x++) { + if (piece.shape[y][x]) { + const px = startX + x * this.blockSize; + const py = startY + y * this.blockSize; + // Draw filled block + this.ctx.fillStyle = piece.color; + this.ctx.fillRect(px, py, this.blockSize, this.blockSize); + // Draw border + this.ctx.strokeStyle = "#000000"; + this.ctx.lineWidth = 1; + this.ctx.strokeRect(px, py, this.blockSize, this.blockSize); + } + } + } + } +} +//# sourceMappingURL=renderer.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/renderer.js.map b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=haiku_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/renderer.js.map @@ -0,0 +1 @@ +{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAAA,uBAAuB;AAIvB,MAAM,MAAM,GAA8B;IACxC,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS,EAAE,IAAI;IAClB,CAAC,EAAE,SAAS,EAAE,IAAI;IAClB,CAAC,EAAE,SAAS,EAAE,IAAI;IAClB,CAAC,EAAE,SAAS,EAAE,IAAI;IAClB,CAAC,EAAE,SAAS,EAAE,IAAI;IAClB,CAAC,EAAE,SAAS,EAAE,IAAI;IAClB,CAAC,EAAE,SAAS,EAAE,IAAI;CACnB,CAAC;AAEF,MAAM,OAAO,QAAQ;IAQnB,YAAY,MAAyB,EAAE,YAAoB,EAAE;QAF7D,kBAAa,GAAW,SAAS,CAAC;QAGhC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAC1D,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAE5B,iBAAiB;QACjB,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,CAAC,IAAY;QACjB,eAAe;QACf,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAEjD,aAAa;QACb,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAErB,qBAAqB;QACrB,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,eAAe,EAAG,CAAC,CAAC;QAC1C,CAAC;QAED,YAAY;QACZ,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEpB,yBAAyB;QACzB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,CAAC;QAED,qBAAqB;QACrB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,CAAC;IACH,CAAC;IAEO,SAAS,CAAC,IAAY;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAE9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACzC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;oBACtB,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAEO,SAAS,CAAC,KAKjB;QACC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/C,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBACtB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;oBAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;oBAC3B,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;wBAChB,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;oBAC9C,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAEO,SAAS,CAAC,CAAS,EAAE,CAAS,EAAE,KAAa;QACnD,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;QAC9B,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;QAE9B,oBAAoB;QACpB,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC;QAC3B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAE1D,cAAc;QACd,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAE5D,2BAA2B;QAC3B,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,0BAA0B,CAAC;QAClD,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACxB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1D,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;IACpB,CAAC;IAEO,QAAQ,CAAC,IAAY;QAC3B,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC;QAC1C,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC;QAEzB,iBAAiB;QACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YACvC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;YAClE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACpB,CAAC;QAED,mBAAmB;QACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;YACvC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;YACjE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAEO,YAAY;QAClB,2BAA2B;QAC3B,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,oBAAoB,CAAC;QAC1C,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAEjD,OAAO;QACP,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAClC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,QAAQ,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QAErE,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,oBAAoB,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IAChF,CAAC;IAEO,SAAS;QACf,2BAA2B;QAC3B,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,oBAAoB,CAAC;QAC1C,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAEjD,OAAO;QACP,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAClC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,QAAQ,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAE7D,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,mBAAmB,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/E,CAAC;CACF;AAED,MAAM,OAAO,iBAAiB;IAK5B,YAAY,MAAyB,EAAE,YAAoB,EAAE;QAC3D,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAC1D,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAE3B,iBAAiB;QACjB,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,CAAC,KAA2C;QAChD,eAAe;QACf,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAE/D,cAAc;QACd,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAEzE,aAAa;QACb,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;QAC5D,MAAM,MAAM,GAAG,CAAC,CAAC;QAEjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/C,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBACtB,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;oBACvC,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;oBAEvC,oBAAoB;oBACpB,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC;oBACjC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;oBAE1D,cAAc;oBACd,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC;oBACjC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;oBACvB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC9D,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/board.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/board.js @@ -0,0 +1,45 @@ +/** Board state: the locked-in grid of cells */ +export const COLS = 10; +export const ROWS = 20; +/** Extra hidden rows above the visible area for spawning */ +export const BUFFER_ROWS = 4; +export const TOTAL_ROWS = ROWS + BUFFER_ROWS; +export class Board { + constructor() { + this.grid = Board.emptyGrid(); + } + static emptyGrid() { + return Array.from({ length: TOTAL_ROWS }, () => Array(COLS).fill(null)); + } + /** Returns true if (x, y) is in-bounds and empty */ + isFree(x, y) { + if (x < 0 || x >= COLS || y < 0 || y >= TOTAL_ROWS) + return false; + return this.grid[y][x] === null; + } + /** Lock a piece's cells into the grid */ + lock(cells, type) { + for (const c of cells) { + if (c.y >= 0 && c.y < TOTAL_ROWS && c.x >= 0 && c.x < COLS) { + this.grid[c.y][c.x] = type; + } + } + } + /** Clear completed lines, return number cleared */ + clearLines() { + let cleared = 0; + for (let y = TOTAL_ROWS - 1; y >= 0; y--) { + if (this.grid[y].every((cell) => cell !== null)) { + this.grid.splice(y, 1); + this.grid.unshift(Array(COLS).fill(null)); + cleared++; + y++; // re-check same row index since rows shifted down + } + } + return cleared; + } + reset() { + this.grid = Board.emptyGrid(); + } +} +//# sourceMappingURL=board.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/board.js.map b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/board.js.map @@ -0,0 +1 @@ +{"version":3,"file":"board.js","sourceRoot":"","sources":["../src/board.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAI/C,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;AACvB,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;AACvB,4DAA4D;AAC5D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAC7B,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,GAAG,WAAW,CAAC;AAI7C,MAAM,OAAO,KAAK;IAGhB;QACE,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;IAChC,CAAC;IAED,MAAM,CAAC,SAAS;QACd,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,KAAK,CAAO,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChF,CAAC;IAED,oDAAoD;IACpD,MAAM,CAAC,CAAS,EAAE,CAAS;QACzB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,UAAU;YAAE,OAAO,KAAK,CAAC;QACjE,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAClC,CAAC;IAED,yCAAyC;IACzC,IAAI,CAAC,KAAiC,EAAE,IAAmB;QACzD,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,UAAU,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC;gBAC3D,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;YAC7B,CAAC;QACH,CAAC;IACH,CAAC;IAED,mDAAmD;IACnD,UAAU;QACR,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,IAAI,CAAC,GAAG,UAAU,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;gBAChD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACvB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAO,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBAChD,OAAO,EAAE,CAAC;gBACV,CAAC,EAAE,CAAC,CAAC,kDAAkD;YACzD,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;IAChC,CAAC;CACF"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js @@ -0,0 +1,354 @@ +/** Core Tetris game logic: state machine, scoring, controls */ +import { Board, BUFFER_ROWS } from "./board.js"; +import { PieceBag, getShape, getWallKicks } from "./pieces.js"; +/** NES-style level speed curve (ms per drop) */ +function getDropInterval(level) { + // Speeds up as level increases; floor at 50ms + const speeds = [800, 720, 630, 550, 470, 380, 300, 220, 150, 100, 80, 80, 80, 70, 70, 70, 50, 50, 50, 50]; + return speeds[Math.min(level, speeds.length - 1)]; +} +/** Scoring: original BPS scoring with level multiplier */ +function lineScore(lines, level) { + const table = [0, 100, 300, 500, 800]; + return table[lines] * (level + 1); +} +export class Game { + constructor(renderer) { + this.current = null; + this.currentPos = { x: 0, y: 0 }; + this.nextType = null; + this.holdType = null; + this.holdUsed = false; + this.score = 0; + this.level = 0; + this.lines = 0; + this.gameOver = false; + this.paused = false; + this.started = false; + this.dropTimer = 0; + this.lastTime = 0; + this.lockDelay = 500; // ms + this.lockTimer = 0; + this.isOnGround = false; + // DAS (Delayed Auto Shift) for smooth horizontal movement + this.dasDirection = 0; + this.dasTimer = 0; + this.dasDelay = 170; // ms before auto-repeat starts + this.dasInterval = 50; // ms between auto-repeats + this.dasReady = false; + // Soft drop + this.softDropping = false; + // Track pressed keys for DAS + this.keysDown = new Set(); + this.board = new Board(); + this.renderer = renderer; + this.bag = new PieceBag(); + } + start() { + this.board.reset(); + this.score = 0; + this.level = 0; + this.lines = 0; + this.gameOver = false; + this.paused = false; + this.started = true; + this.holdType = null; + this.holdUsed = false; + this.bag = new PieceBag(); + this.nextType = this.bag.next(); + this.spawnPiece(); + this.renderer.hideMessage(); + this.lastTime = performance.now(); + requestAnimationFrame((t) => this.loop(t)); + } + loop(time) { + if (this.gameOver) { + this.render(); + this.renderer.showMessage("GAME OVER — Press R to restart"); + return; + } + if (!this.started) + return; + const dt = time - this.lastTime; + this.lastTime = time; + if (!this.paused) { + this.updateDAS(dt); + this.updateDrop(dt); + } + this.render(); + requestAnimationFrame((t) => this.loop(t)); + } + updateDAS(dt) { + if (this.dasDirection === 0) + return; + this.dasTimer += dt; + if (!this.dasReady) { + if (this.dasTimer >= this.dasDelay) { + this.dasReady = true; + this.dasTimer -= this.dasDelay; + this.movePiece(this.dasDirection, 0); + } + } + else { + while (this.dasTimer >= this.dasInterval) { + this.dasTimer -= this.dasInterval; + this.movePiece(this.dasDirection, 0); + } + } + } + updateDrop(dt) { + if (!this.current) + return; + const interval = this.softDropping + ? Math.min(getDropInterval(this.level), 50) + : getDropInterval(this.level); + // Check if piece is on the ground + const onGround = !this.canMove(0, 1); + if (onGround) { + if (!this.isOnGround) { + this.isOnGround = true; + this.lockTimer = 0; + } + this.lockTimer += dt; + if (this.lockTimer >= this.lockDelay) { + this.lockPiece(); + return; + } + } + else { + this.isOnGround = false; + this.lockTimer = 0; + } + this.dropTimer += dt; + if (this.dropTimer >= interval) { + this.dropTimer -= interval; + if (this.canMove(0, 1)) { + this.currentPos.y++; + if (this.softDropping) { + this.score += 1; + } + } + } + } + spawnPiece() { + const type = this.nextType; + this.nextType = this.bag.next(); + this.current = { type, cells: getShape(type, 0), rotation: 0 }; + this.currentPos = { x: 3, y: BUFFER_ROWS - 2 }; // Spawn near top of buffer + this.dropTimer = 0; + this.lockTimer = 0; + this.isOnGround = false; + this.holdUsed = false; + // If spawn position is blocked, game over + if (!this.isValid(this.getAbsoluteCells())) { + this.gameOver = true; + } + } + getAbsoluteCells(cells, pos) { + const c = cells ?? this.current.cells; + const p = pos ?? this.currentPos; + return c.map((cell) => ({ x: cell.x + p.x, y: cell.y + p.y })); + } + isValid(cells) { + return cells.every((c) => this.board.isFree(c.x, c.y)); + } + canMove(dx, dy) { + if (!this.current) + return false; + const moved = this.getAbsoluteCells().map((c) => ({ x: c.x + dx, y: c.y + dy })); + return this.isValid(moved); + } + movePiece(dx, dy) { + if (this.canMove(dx, dy)) { + this.currentPos.x += dx; + this.currentPos.y += dy; + if (this.isOnGround && !this.canMove(0, 1)) { + // Reset lock timer on successful move while on ground (lock delay reset) + this.lockTimer = 0; + } + return true; + } + return false; + } + rotatePiece(dir) { + if (!this.current) + return; + const fromRot = this.current.rotation; + const toRot = (fromRot + dir + 4) % 4; + const newCells = getShape(this.current.type, toRot); + // Try base rotation + const baseCells = this.getAbsoluteCells(newCells); + if (this.isValid(baseCells)) { + this.current.cells = newCells; + this.current.rotation = toRot; + if (this.isOnGround) + this.lockTimer = 0; + return; + } + // Try wall kicks + const kicks = getWallKicks(this.current.type, fromRot, toRot); + for (const kick of kicks) { + const kicked = baseCells.map((c) => ({ x: c.x + kick.x, y: c.y - kick.y })); + if (this.isValid(kicked)) { + this.currentPos.x += kick.x; + this.currentPos.y -= kick.y; + this.current.cells = newCells; + this.current.rotation = toRot; + if (this.isOnGround) + this.lockTimer = 0; + return; + } + } + } + hardDrop() { + if (!this.current) + return; + let dropDist = 0; + while (this.canMove(0, 1)) { + this.currentPos.y++; + dropDist++; + } + this.score += dropDist * 2; + this.lockPiece(); + } + lockPiece() { + if (!this.current) + return; + const cells = this.getAbsoluteCells(); + this.board.lock(cells, this.current.type); + const cleared = this.board.clearLines(); + if (cleared > 0) { + this.lines += cleared; + this.score += lineScore(cleared, this.level); + // Level up every 10 lines + this.level = Math.floor(this.lines / 10); + } + this.current = null; + this.spawnPiece(); + } + getGhostCells() { + if (!this.current) + return null; + let dy = 0; + while (true) { + const test = this.getAbsoluteCells().map((c) => ({ x: c.x, y: c.y + dy + 1 })); + if (!this.isValid(test)) + break; + dy++; + } + return this.getAbsoluteCells().map((c) => ({ x: c.x, y: c.y + dy })); + } + holdPiece() { + if (!this.current || this.holdUsed) + return; + const currentType = this.current.type; + if (this.holdType === null) { + this.holdType = currentType; + this.current = null; + this.spawnPiece(); + } + else { + const swapType = this.holdType; + this.holdType = currentType; + this.current = { type: swapType, cells: getShape(swapType, 0), rotation: 0 }; + this.currentPos = { x: 3, y: BUFFER_ROWS - 2 }; + this.dropTimer = 0; + this.lockTimer = 0; + this.isOnGround = false; + } + this.holdUsed = true; + } + render() { + this.renderer.draw(this.board, this.current ? this.getAbsoluteCells() : null, this.current?.type ?? null, this.getGhostCells(), this.nextType, this.holdType, this.score, this.level, this.lines); + } + handleKeyDown(e) { + // Prevent default for game keys + const gameKeys = [ + "ArrowLeft", "ArrowRight", "ArrowDown", "ArrowUp", + "Space", "KeyZ", "KeyX", "KeyC", "KeyP", "KeyR", + ]; + if (gameKeys.includes(e.code)) { + e.preventDefault(); + } + if (this.keysDown.has(e.code)) + return; // ignore key repeat + this.keysDown.add(e.code); + if (e.code === "KeyR") { + this.start(); + return; + } + if (e.code === "KeyP" && this.started && !this.gameOver) { + this.paused = !this.paused; + if (this.paused) { + this.renderer.showMessage("PAUSED"); + } + else { + this.renderer.hideMessage(); + this.lastTime = performance.now(); + } + return; + } + if (this.paused || this.gameOver || !this.started) + return; + switch (e.code) { + case "ArrowLeft": + this.movePiece(-1, 0); + this.dasDirection = -1; + this.dasTimer = 0; + this.dasReady = false; + break; + case "ArrowRight": + this.movePiece(1, 0); + this.dasDirection = 1; + this.dasTimer = 0; + this.dasReady = false; + break; + case "ArrowDown": + this.softDropping = true; + break; + case "ArrowUp": + case "KeyX": + this.rotatePiece(1); + break; + case "KeyZ": + this.rotatePiece(-1); + break; + case "Space": + this.hardDrop(); + break; + case "KeyC": + this.holdPiece(); + break; + } + } + handleKeyUp(e) { + this.keysDown.delete(e.code); + switch (e.code) { + case "ArrowLeft": + if (this.dasDirection === -1) { + this.dasDirection = 0; + // If right is still held, switch DAS + if (this.keysDown.has("ArrowRight")) { + this.dasDirection = 1; + this.dasTimer = 0; + this.dasReady = false; + } + } + break; + case "ArrowRight": + if (this.dasDirection === 1) { + this.dasDirection = 0; + if (this.keysDown.has("ArrowLeft")) { + this.dasDirection = -1; + this.dasTimer = 0; + this.dasReady = false; + } + } + break; + case "ArrowDown": + this.softDropping = false; + break; + } + } +} +//# sourceMappingURL=game.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js.map b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/game.js.map @@ -0,0 +1 @@ +{"version":3,"file":"game.js","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js @@ -0,0 +1,20 @@ +/** Entry point: wires up DOM elements and starts the game */ +import { Game } from "./game.js"; +import { Renderer } from "./renderer.js"; +function main() { + const canvas = document.getElementById("game-canvas"); + const previewCanvas = document.getElementById("preview-canvas"); + const holdCanvas = document.getElementById("hold-canvas"); + const scoreEl = document.getElementById("score-value"); + const levelEl = document.getElementById("level-value"); + const linesEl = document.getElementById("lines-value"); + const messageEl = document.getElementById("message"); + const renderer = new Renderer(canvas, previewCanvas, holdCanvas, scoreEl, levelEl, linesEl, messageEl); + const game = new Game(renderer); + document.addEventListener("keydown", (e) => game.handleKeyDown(e)); + document.addEventListener("keyup", (e) => game.handleKeyUp(e)); + // Start immediately + game.start(); +} +document.addEventListener("DOMContentLoaded", main); +//# sourceMappingURL=main.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js.map b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/main.js.map @@ -0,0 +1 @@ +{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,SAAS,IAAI;IACX,MAAM,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAsB,CAAC;IAC3E,MAAM,aAAa,GAAG,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAsB,CAAC;IACrF,MAAM,UAAU,GAAG,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAsB,CAAC;IAC/E,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAE,CAAC;IACxD,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAE,CAAC;IACxD,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAE,CAAC;IACxD,MAAM,SAAS,GAAG,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAE,CAAC;IAEtD,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACvG,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC;IAEhC,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/D,oBAAoB;IACpB,IAAI,CAAC,KAAK,EAAE,CAAC;AACf,CAAC;AAED,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.js @@ -0,0 +1,107 @@ +/** Tetromino shape definitions and rotation logic */ +// Each tetromino defined as 4 rotation states (clockwise). +// Coordinates are relative to a pivot. +const SHAPES = { + I: [ + [{ x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }, { x: 3, y: 1 }], + [{ x: 2, y: 0 }, { x: 2, y: 1 }, { x: 2, y: 2 }, { x: 2, y: 3 }], + [{ x: 0, y: 2 }, { x: 1, y: 2 }, { x: 2, y: 2 }, { x: 3, y: 2 }], + [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 1, y: 2 }, { x: 1, y: 3 }], + ], + O: [ + [{ x: 1, y: 0 }, { x: 2, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 1, y: 0 }, { x: 2, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 1, y: 0 }, { x: 2, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 1, y: 0 }, { x: 2, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + ], + T: [ + [{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 1 }, { x: 1, y: 2 }], + [{ x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }, { x: 1, y: 2 }], + [{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 1, y: 2 }], + ], + S: [ + [{ x: 1, y: 0 }, { x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }], + [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 1 }, { x: 2, y: 2 }], + [{ x: 1, y: 1 }, { x: 2, y: 1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 1, y: 2 }], + ], + Z: [ + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 2, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 1 }, { x: 1, y: 2 }], + [{ x: 0, y: 1 }, { x: 1, y: 1 }, { x: 1, y: 2 }, { x: 2, y: 2 }], + [{ x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 0, y: 2 }], + ], + J: [ + [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 1, y: 0 }, { x: 2, y: 0 }, { x: 1, y: 1 }, { x: 1, y: 2 }], + [{ x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }, { x: 2, y: 2 }], + [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], + ], + L: [ + [{ x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }], + [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 1, y: 2 }, { x: 2, y: 2 }], + [{ x: 0, y: 1 }, { x: 1, y: 1 }, { x: 2, y: 1 }, { x: 0, y: 2 }], + [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 1, y: 2 }], + ], +}; +/** SRS wall-kick data for J, L, S, T, Z pieces */ +const WALL_KICKS = { + "0>1": [{ x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "1>0": [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], + "1>2": [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: -2 }, { x: 1, y: -2 }], + "2>1": [{ x: -1, y: 0 }, { x: -1, y: -1 }, { x: 0, y: 2 }, { x: -1, y: 2 }], + "2>3": [{ x: 1, y: 0 }, { x: 1, y: -1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], + "3>2": [{ x: -1, y: 0 }, { x: -1, y: 1 }, { x: 0, y: -2 }, { x: -1, y: -2 }], + "3>0": [{ x: -1, y: 0 }, { x: -1, y: 1 }, { x: 0, y: -2 }, { x: -1, y: -2 }], + "0>3": [{ x: 1, y: 0 }, { x: 1, y: -1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], +}; +/** SRS wall-kick data for I piece */ +const I_WALL_KICKS = { + "0>1": [{ x: -2, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 1 }, { x: 1, y: -2 }], + "1>0": [{ x: 2, y: 0 }, { x: -1, y: 0 }, { x: 2, y: -1 }, { x: -1, y: 2 }], + "1>2": [{ x: -1, y: 0 }, { x: 2, y: 0 }, { x: -1, y: -2 }, { x: 2, y: 1 }], + "2>1": [{ x: 1, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 2 }, { x: -2, y: -1 }], + "2>3": [{ x: 2, y: 0 }, { x: -1, y: 0 }, { x: 2, y: -1 }, { x: -1, y: 2 }], + "3>2": [{ x: -2, y: 0 }, { x: 1, y: 0 }, { x: -2, y: 1 }, { x: 1, y: -2 }], + "3>0": [{ x: 1, y: 0 }, { x: -2, y: 0 }, { x: 1, y: 2 }, { x: -2, y: -1 }], + "0>3": [{ x: -1, y: 0 }, { x: 2, y: 0 }, { x: -1, y: -2 }, { x: 2, y: 1 }], +}; +export const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const TYPES = ["I", "O", "T", "S", "Z", "J", "L"]; +/** 7-bag randomizer: shuffles all 7 pieces, deals them, then reshuffles */ +export class PieceBag { + constructor() { + this.bag = []; + } + next() { + if (this.bag.length === 0) { + this.bag = [...TYPES]; + // Fisher-Yates shuffle + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop(); + } +} +export function getShape(type, rotation) { + return SHAPES[type][rotation % 4]; +} +export function getWallKicks(type, fromRot, toRot) { + const key = `${fromRot}>${toRot}`; + if (type === "O") + return []; + const table = type === "I" ? I_WALL_KICKS : WALL_KICKS; + return table[key] ?? []; +} +//# sourceMappingURL=pieces.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.js.map b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/pieces.js.map @@ -0,0 +1 @@ +{"version":3,"file":"pieces.js","sourceRoot":"","sources":["../src/pieces.ts"],"names":[],"mappings":"AAAA,qDAAqD;AAerD,2DAA2D;AAC3D,uCAAuC;AACvC,MAAM,MAAM,GAAqC;IAC/C,CAAC,EAAE;QACD,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KACjE;IACD,CAAC,EAAE;QACD,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KACjE;IACD,CAAC,EAAE;QACD,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KACjE;IACD,CAAC,EAAE;QACD,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KACjE;IACD,CAAC,EAAE;QACD,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KACjE;IACD,CAAC,EAAE;QACD,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KACjE;IACD,CAAC,EAAE;QACD,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EA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AC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC1E,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;CAC3E,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAkC;IACnD,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;CACb,CAAC;AAEF,MAAM,KAAK,GAAoB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAEnE,2EAA2E;AAC3E,MAAM,OAAO,QAAQ;IAArB;QACU,QAAG,GAAoB,EAAE,CAAC;IAapC,CAAC;IAXC,IAAI;QACF,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;YACtB,uBAAuB;YACvB,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC9C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAG,CAAC;IACzB,CAAC;CACF;AAED,MAAM,UAAU,QAAQ,CAAC,IAAmB,EAAE,QAAgB;IAC5D,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAmB,EAAE,OAAe,EAAE,KAAa;IAC9E,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,KAAK,EAAE,CAAC;IAClC,IAAI,IAAI,KAAK,GAAG;QAAE,OAAO,EAAE,CAAC;IAC5B,MAAM,KAAK,GAAG,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC;IACvD,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;AAC1B,CAAC"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.js @@ -0,0 +1,126 @@ +/** Canvas-based renderer for the Tetris board, HUD, and next-piece preview */ +import { COLS, ROWS, BUFFER_ROWS, TOTAL_ROWS } from "./board.js"; +import { COLORS, getShape } from "./pieces.js"; +const CELL = 30; // px per cell +const BORDER = 1; +const PREVIEW_CELL = 22; +export class Renderer { + constructor(canvas, previewCanvas, holdCanvas, scoreEl, levelEl, linesEl, messageEl) { + canvas.width = COLS * CELL; + canvas.height = ROWS * CELL; + this.ctx = canvas.getContext("2d"); + previewCanvas.width = 4 * PREVIEW_CELL; + previewCanvas.height = 4 * PREVIEW_CELL; + this.previewCtx = previewCanvas.getContext("2d"); + holdCanvas.width = 4 * PREVIEW_CELL; + holdCanvas.height = 4 * PREVIEW_CELL; + this.holdCtx = holdCanvas.getContext("2d"); + this.scoreEl = scoreEl; + this.levelEl = levelEl; + this.linesEl = linesEl; + this.messageEl = messageEl; + } + draw(board, activeCells, activeType, ghostCells, nextType, holdType, score, level, lines) { + const ctx = this.ctx; + // Background + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, COLS * CELL, ROWS * CELL); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let x = 0; x <= COLS; x++) { + ctx.beginPath(); + ctx.moveTo(x * CELL, 0); + ctx.lineTo(x * CELL, ROWS * CELL); + ctx.stroke(); + } + for (let y = 0; y <= ROWS; y++) { + ctx.beginPath(); + ctx.moveTo(0, y * CELL); + ctx.lineTo(COLS * CELL, y * CELL); + ctx.stroke(); + } + // Locked cells (offset by BUFFER_ROWS so buffer rows aren't drawn) + for (let row = BUFFER_ROWS; row < TOTAL_ROWS; row++) { + for (let col = 0; col < COLS; col++) { + const cell = board.grid[row][col]; + if (cell) { + this.drawCell(ctx, col, row - BUFFER_ROWS, CELL, COLORS[cell], 1); + } + } + } + // Ghost piece + if (ghostCells && activeType) { + for (const c of ghostCells) { + const vy = c.y - BUFFER_ROWS; + if (vy >= 0) { + this.drawCell(ctx, c.x, vy, CELL, COLORS[activeType], 0.2); + } + } + } + // Active piece + if (activeCells && activeType) { + for (const c of activeCells) { + const vy = c.y - BUFFER_ROWS; + if (vy >= 0) { + this.drawCell(ctx, c.x, vy, CELL, COLORS[activeType], 1); + } + } + } + // Next-piece preview + this.drawPreview(this.previewCtx, nextType); + // Hold-piece preview + this.drawPreview(this.holdCtx, holdType); + // HUD + this.scoreEl.textContent = score.toLocaleString(); + this.levelEl.textContent = String(level); + this.linesEl.textContent = String(lines); + } + showMessage(text) { + this.messageEl.textContent = text; + this.messageEl.hidden = false; + } + hideMessage() { + this.messageEl.hidden = true; + } + drawPreview(ctx, type) { + const w = ctx.canvas.width; + const h = ctx.canvas.height; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, w, h); + if (!type) + return; + const shape = getShape(type, 0); + // Center the shape + const minX = Math.min(...shape.map((p) => p.x)); + const maxX = Math.max(...shape.map((p) => p.x)); + const minY = Math.min(...shape.map((p) => p.y)); + const maxY = Math.max(...shape.map((p) => p.y)); + const shapeW = maxX - minX + 1; + const shapeH = maxY - minY + 1; + const offX = (w - shapeW * PREVIEW_CELL) / 2 - minX * PREVIEW_CELL; + const offY = (h - shapeH * PREVIEW_CELL) / 2 - minY * PREVIEW_CELL; + for (const p of shape) { + const px = offX + p.x * PREVIEW_CELL; + const py = offY + p.y * PREVIEW_CELL; + ctx.fillStyle = COLORS[type]; + ctx.fillRect(px + BORDER, py + BORDER, PREVIEW_CELL - BORDER * 2, PREVIEW_CELL - BORDER * 2); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.18)"; + ctx.fillRect(px + BORDER, py + BORDER, PREVIEW_CELL - BORDER * 2, 3); + } + } + drawCell(ctx, col, row, size, color, alpha) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(col * size + BORDER, row * size + BORDER, size - BORDER * 2, size - BORDER * 2); + // Highlight top edge + ctx.fillStyle = "rgba(255,255,255,0.2)"; + ctx.fillRect(col * size + BORDER, row * size + BORDER, size - BORDER * 2, 3); + // Shadow bottom edge + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(col * size + BORDER, (row + 1) * size - BORDER - 3, size - BORDER * 2, 3); + ctx.globalAlpha = 1; + } +} +//# sourceMappingURL=renderer.js.map +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.js.map b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/renderer.js.map @@ -0,0 +1 @@ +{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"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"} +\ No newline at end of file diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,486 @@ +"use strict"; +// ─── Types & Constants ────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const CELL = 32; // px per cell +const PREVIEW_CELL = 20; +const COLORS = { + I: "#00f0f0", + O: "#f0f000", + T: "#a000f0", + S: "#00f000", + Z: "#f00000", + J: "#0000f0", + L: "#f0a000", +}; +const SHAPES = { + I: [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0], + ], + O: [ + [1, 1], + [1, 1], + ], + T: [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ], + S: [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + Z: [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + J: [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + L: [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], +}; +const PIECE_NAMES = Object.keys(SHAPES); +// SRS wall-kick data (non-I pieces) +const WALL_KICKS = { + "0>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "1>0": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "1>2": [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + "2>1": [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + "2>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + "3>2": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "3>0": [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + "0>3": [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +// SRS wall-kick data for I piece +const WALL_KICKS_I = { + "0>1": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "1>0": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "1>2": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + "2>1": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "2>3": [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + "3>2": [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + "3>0": [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + "0>3": [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// ─── Scoring ──────────────────────────────────────────────────────── +const LINE_POINTS = [0, 100, 300, 500, 800]; // 0,1,2,3,4 lines +// ─── Game State ───────────────────────────────────────────────────── +class TetrisGame { + constructor(boardCanvas, previewCanvas, scoreEl, levelEl, linesEl, overlayEl) { + this.currentType = ""; + this.rotationState = 0; + this.bag = []; + this.score = 0; + this.level = 1; + this.lines = 0; + this.gameOver = false; + this.paused = false; + this.dropInterval = 1000; + this.lastDrop = 0; + this.animationId = 0; + this.lockDelay = 500; + this.lockTimer = 0; + this.isGrounded = false; + // ── Main loop ─────────────────────────────────────────────────── + this.loop = (now) => { + this.animationId = requestAnimationFrame(this.loop); + if (this.gameOver) { + this.drawBoard(); + this.drawPreview(); + this.updateHUD(); + this.overlayEl.textContent = "GAME OVER — press Enter"; + this.overlayEl.style.display = "flex"; + cancelAnimationFrame(this.animationId); + // keep one last frame request for restart detection + requestAnimationFrame(this.waitForRestart); + return; + } + if (this.paused) + return; + // Gravity + const grounded = this.collides(this.current, this.current.x, this.current.y + 1); + if (grounded) { + if (!this.isGrounded) { + this.isGrounded = true; + this.lockTimer = now; + } + // Lock after delay + if (now - this.lockTimer >= this.lockDelay) { + this.lock(); + } + } + else { + this.isGrounded = false; + if (now - this.lastDrop >= this.dropInterval) { + this.current.y++; + this.lastDrop = now; + } + } + this.drawBoard(); + this.drawPreview(); + this.updateHUD(); + }; + this.waitForRestart = (_now) => { + if (!this.gameOver) { + this.lastDrop = performance.now(); + this.loop(performance.now()); + } + else { + requestAnimationFrame(this.waitForRestart); + } + }; + this.ctx = boardCanvas.getContext("2d"); + this.previewCtx = previewCanvas.getContext("2d"); + this.scoreEl = scoreEl; + this.levelEl = levelEl; + this.linesEl = linesEl; + this.overlayEl = overlayEl; + boardCanvas.width = COLS * CELL; + boardCanvas.height = ROWS * CELL; + previewCanvas.width = 4 * PREVIEW_CELL + 20; + previewCanvas.height = 4 * PREVIEW_CELL + 20; + this.board = this.createBoard(); + this.next = this.getNextFromBag(); + this.current = this.spawnPiece(); + this.bindKeys(); + this.lastDrop = performance.now(); + this.loop(performance.now()); + } + // ── Board helpers ─────────────────────────────────────────────── + createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); + } + // ── Bag randomiser (7-bag) ────────────────────────────────────── + refillBag() { + const a = [...PIECE_NAMES]; + for (let i = a.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [a[i], a[j]] = [a[j], a[i]]; + } + this.bag = a; + } + getNextFromBag() { + if (this.bag.length === 0) + this.refillBag(); + const type = this.bag.pop(); + return { type, shape: SHAPES[type], color: COLORS[type] }; + } + // ── Piece spawning ────────────────────────────────────────────── + spawnPiece() { + const info = this.next; + this.next = this.getNextFromBag(); + this.currentType = info.type; + this.rotationState = 0; + const piece = { + shape: info.shape.map((r) => [...r]), + color: info.color, + x: Math.floor((COLS - info.shape[0].length) / 2), + y: 0, + }; + if (this.collides(piece, piece.x, piece.y)) { + this.gameOver = true; + } + this.isGrounded = false; + this.lockTimer = 0; + return piece; + } + // ── Collision detection ───────────────────────────────────────── + collides(piece, px, py) { + for (let r = 0; r < piece.shape.length; r++) { + for (let c = 0; c < piece.shape[r].length; c++) { + if (!piece.shape[r][c]) + continue; + const nx = px + c; + const ny = py + r; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return true; + if (ny >= 0 && this.board[ny][nx]) + return true; + } + } + return false; + } + // ── Rotation (SRS) ───────────────────────────────────────────── + rotateCW(shape) { + const n = shape.length; + const out = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) + for (let c = 0; c < n; c++) + out[c][n - 1 - r] = shape[r][c]; + return out; + } + rotateCCW(shape) { + const n = shape.length; + const out = Array.from({ length: n }, () => Array(n).fill(0)); + for (let r = 0; r < n; r++) + for (let c = 0; c < n; c++) + out[n - 1 - c][r] = shape[r][c]; + return out; + } + tryRotate(dir) { + const oldRot = this.rotationState; + const newRot = (oldRot + dir + 4) % 4; + const newShape = dir === 1 + ? this.rotateCW(this.current.shape) + : this.rotateCCW(this.current.shape); + const key = `${oldRot}>${newRot}`; + const kicks = this.currentType === "I" ? WALL_KICKS_I[key] : WALL_KICKS[key]; + if (!kicks) + return; + for (const [dx, dy] of kicks) { + if (!this.collides({ ...this.current, shape: newShape }, this.current.x + dx, this.current.y - dy)) { + this.current.shape = newShape; + this.current.x += dx; + this.current.y -= dy; + this.rotationState = newRot; + // Reset lock timer on successful rotation while grounded + if (this.isGrounded) + this.lockTimer = performance.now(); + return; + } + } + } + // ── Movement ──────────────────────────────────────────────────── + move(dx, dy) { + if (!this.collides(this.current, this.current.x + dx, this.current.y + dy)) { + this.current.x += dx; + this.current.y += dy; + // Reset lock timer on successful horizontal move while grounded + if (dx !== 0 && this.isGrounded) + this.lockTimer = performance.now(); + return true; + } + return false; + } + hardDrop() { + let dropDist = 0; + while (!this.collides(this.current, this.current.x, this.current.y + 1)) { + this.current.y++; + dropDist++; + } + this.score += dropDist * 2; + this.lock(); + } + // ── Ghost piece (shadow) ──────────────────────────────────────── + ghostY() { + let gy = this.current.y; + while (!this.collides(this.current, this.current.x, gy + 1)) + gy++; + return gy; + } + // ── Locking & line clearing ───────────────────────────────────── + lock() { + for (let r = 0; r < this.current.shape.length; r++) { + for (let c = 0; c < this.current.shape[r].length; c++) { + if (!this.current.shape[r][c]) + continue; + const by = this.current.y + r; + const bx = this.current.x + c; + if (by < 0) { + this.gameOver = true; + return; + } + this.board[by][bx] = this.current.color; + } + } + this.clearLines(); + this.current = this.spawnPiece(); + this.lastDrop = performance.now(); + } + clearLines() { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (this.board[r].every((c) => c !== null)) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check this row index + } + } + if (cleared > 0) { + this.lines += cleared; + this.score += LINE_POINTS[cleared] * this.level; + this.level = Math.floor(this.lines / 10) + 1; + this.dropInterval = Math.max(50, 1000 - (this.level - 1) * 80); + } + } + // ── Input ─────────────────────────────────────────────────────── + bindKeys() { + document.addEventListener("keydown", (e) => { + if (this.gameOver) { + if (e.key === "Enter") + this.restart(); + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + this.paused = !this.paused; + this.overlayEl.textContent = this.paused ? "PAUSED" : ""; + this.overlayEl.style.display = this.paused ? "flex" : "none"; + if (!this.paused) + this.lastDrop = performance.now(); + return; + } + if (this.paused) + return; + switch (e.key) { + case "ArrowLeft": + case "a": + e.preventDefault(); + this.move(-1, 0); + break; + case "ArrowRight": + case "d": + e.preventDefault(); + this.move(1, 0); + break; + case "ArrowDown": + case "s": + e.preventDefault(); + if (this.move(0, 1)) + this.score += 1; + this.lastDrop = performance.now(); + break; + case "ArrowUp": + case "w": + e.preventDefault(); + this.tryRotate(1); + break; + case "z": + case "Z": + e.preventDefault(); + this.tryRotate(-1); + break; + case " ": + e.preventDefault(); + this.hardDrop(); + break; + } + }); + } + restart() { + this.board = this.createBoard(); + this.bag = []; + this.score = 0; + this.level = 1; + this.lines = 0; + this.dropInterval = 1000; + this.gameOver = false; + this.paused = false; + this.next = this.getNextFromBag(); + this.current = this.spawnPiece(); + this.lastDrop = performance.now(); + this.overlayEl.style.display = "none"; + } + // ── Rendering ─────────────────────────────────────────────────── + drawCell(ctx, x, y, size, color, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size, y * size, size, size); + // Highlight (top-left bevel) + ctx.fillStyle = "rgba(255,255,255,0.3)"; + ctx.fillRect(x * size, y * size, size, 2); + ctx.fillRect(x * size, y * size, 2, size); + // Shadow (bottom-right bevel) + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(x * size, y * size + size - 2, size, 2); + ctx.fillRect(x * size + size - 2, y * size, 2, size); + ctx.globalAlpha = 1; + } + drawBoard() { + const ctx = this.ctx; + ctx.fillStyle = "#111"; + ctx.fillRect(0, 0, COLS * CELL, ROWS * CELL); + // Grid lines + ctx.strokeStyle = "#222"; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL); + ctx.lineTo(COLS * CELL, r * CELL); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL, 0); + ctx.lineTo(c * CELL, ROWS * CELL); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (this.board[r][c]) { + this.drawCell(ctx, c, r, CELL, this.board[r][c]); + } + } + } + // Ghost piece + const gy = this.ghostY(); + for (let r = 0; r < this.current.shape.length; r++) { + for (let c = 0; c < this.current.shape[r].length; c++) { + if (!this.current.shape[r][c]) + continue; + this.drawCell(ctx, this.current.x + c, gy + r, CELL, this.current.color, 0.2); + } + } + // Active piece + for (let r = 0; r < this.current.shape.length; r++) { + for (let c = 0; c < this.current.shape[r].length; c++) { + if (!this.current.shape[r][c]) + continue; + const py = this.current.y + r; + if (py < 0) + continue; + this.drawCell(ctx, this.current.x + c, py, CELL, this.current.color); + } + } + } + drawPreview() { + const ctx = this.previewCtx; + const cw = ctx.canvas.width; + const ch = ctx.canvas.height; + ctx.fillStyle = "#1a1a2e"; + ctx.fillRect(0, 0, cw, ch); + const shape = this.next.shape; + const rows = shape.length; + const cols = shape[0].length; + const offX = Math.floor((cw - cols * PREVIEW_CELL) / 2); + const offY = Math.floor((ch - rows * PREVIEW_CELL) / 2); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (!shape[r][c]) + continue; + ctx.fillStyle = this.next.color; + ctx.fillRect(offX + c * PREVIEW_CELL, offY + r * PREVIEW_CELL, PREVIEW_CELL, PREVIEW_CELL); + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(offX + c * PREVIEW_CELL, offY + r * PREVIEW_CELL, PREVIEW_CELL, 2); + ctx.fillRect(offX + c * PREVIEW_CELL, offY + r * PREVIEW_CELL, 2, PREVIEW_CELL); + ctx.fillStyle = "rgba(0,0,0,0.25)"; + ctx.fillRect(offX + c * PREVIEW_CELL, offY + r * PREVIEW_CELL + PREVIEW_CELL - 2, PREVIEW_CELL, 2); + ctx.fillRect(offX + c * PREVIEW_CELL + PREVIEW_CELL - 2, offY + r * PREVIEW_CELL, 2, PREVIEW_CELL); + } + } + } + updateHUD() { + this.scoreEl.textContent = this.score.toLocaleString(); + this.levelEl.textContent = String(this.level); + this.linesEl.textContent = String(this.lines); + } +} +// ─── Bootstrap ──────────────────────────────────────────────────── +function boot() { + const game = new TetrisGame(document.getElementById("board"), document.getElementById("preview"), document.getElementById("score-val"), document.getElementById("level-val"), document.getElementById("lines-val"), document.getElementById("overlay")); + // expose for debugging + window["tetris"] = game; +} +document.addEventListener("DOMContentLoaded", boot); diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/bundle.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/bundle.js @@ -0,0 +1,711 @@ +"use strict"; +(() => { + var __getOwnPropNames = Object.getOwnPropertyNames; + var __esm = (fn, res) => function __init() { + return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; + }; + var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; + + // src/pieces.ts + function rotateCW(shape) { + const rows = shape.length; + const cols = shape[0].length; + const result = []; + for (let c = 0; c < cols; c++) { + result[c] = []; + for (let r = rows - 1; r >= 0; r--) { + result[c].push(shape[r][c]); + } + } + return result; + } + function buildRotations(base) { + const r0 = base; + const r1 = rotateCW(r0); + const r2 = rotateCW(r1); + const r3 = rotateCW(r2); + return [r0, r1, r2, r3]; + } + function parse(template) { + return template.trim().split("\n").map((line) => [...line.trim()].map((ch) => ch === "#")); + } + function getKicks(pieceName, fromRot, toRot) { + const key = `${fromRot}>${toRot}`; + if (pieceName === "I") return I_KICKS[key] ?? [[0, 0]]; + if (pieceName === "O") return [[0, 0]]; + return JLSTZ_KICKS[key] ?? [[0, 0]]; + } + var I_BASE, O_BASE, T_BASE, S_BASE, Z_BASE, L_BASE, J_BASE, PIECES, JLSTZ_KICKS, I_KICKS, BagRandomizer; + var init_pieces = __esm({ + "src/pieces.ts"() { + "use strict"; + I_BASE = parse(` +.... +#### +.... +.... +`); + O_BASE = parse(` +## +## +`); + T_BASE = parse(` +.#. +### +... +`); + S_BASE = parse(` +.## +##. +... +`); + Z_BASE = parse(` +##. +.## +... +`); + L_BASE = parse(` +..# +### +... +`); + J_BASE = parse(` +#.. +### +... +`); + PIECES = [ + { name: "I", color: "#00f0f0", shapes: buildRotations(I_BASE) }, + { name: "O", color: "#f0f000", shapes: buildRotations(O_BASE) }, + { name: "T", color: "#a000f0", shapes: buildRotations(T_BASE) }, + { name: "S", color: "#00f000", shapes: buildRotations(S_BASE) }, + { name: "Z", color: "#f00000", shapes: buildRotations(Z_BASE) }, + { name: "L", color: "#f0a000", shapes: buildRotations(L_BASE) }, + { name: "J", color: "#0000f0", shapes: buildRotations(J_BASE) } + ]; + JLSTZ_KICKS = { + "0>1": [[0, 0], [0, -1], [-1, -1], [2, 0], [2, -1]], + "1>0": [[0, 0], [0, 1], [1, 1], [-2, 0], [-2, 1]], + "1>2": [[0, 0], [0, 1], [1, 1], [-2, 0], [-2, 1]], + "2>1": [[0, 0], [0, -1], [-1, -1], [2, 0], [2, -1]], + "2>3": [[0, 0], [0, 1], [-1, 1], [2, 0], [2, 1]], + "3>2": [[0, 0], [0, -1], [1, -1], [-2, 0], [-2, -1]], + "3>0": [[0, 0], [0, -1], [1, -1], [-2, 0], [-2, -1]], + "0>3": [[0, 0], [0, 1], [-1, 1], [2, 0], [2, 1]] + }; + I_KICKS = { + "0>1": [[0, 0], [0, -2], [0, 1], [-1, -2], [2, 1]], + "1>0": [[0, 0], [0, 2], [0, -1], [1, 2], [-2, -1]], + "1>2": [[0, 0], [0, -1], [0, 2], [2, -1], [-1, 2]], + "2>1": [[0, 0], [0, 1], [0, -2], [-2, 1], [1, -2]], + "2>3": [[0, 0], [0, 2], [0, -1], [1, 2], [-2, -1]], + "3>2": [[0, 0], [0, -2], [0, 1], [-1, -2], [2, 1]], + "3>0": [[0, 0], [0, 1], [0, -2], [-2, 1], [1, -2]], + "0>3": [[0, 0], [0, -1], [0, 2], [2, -1], [-1, 2]] + }; + BagRandomizer = class { + constructor() { + this.bag = []; + } + next() { + if (this.bag.length === 0) { + this.bag = [...PIECES]; + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop(); + } + }; + } + }); + + // src/board.ts + function createGrid() { + const grid = []; + for (let r = 0; r < TOTAL_ROWS; r++) { + grid.push(new Array(COLS).fill(null)); + } + return grid; + } + function collides(grid, piece, rowOff = 0, colOff = 0) { + const shape = piece.def.shapes[piece.rotation]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) continue; + const boardR = piece.row + r + rowOff; + const boardC = piece.col + c + colOff; + if (boardC < 0 || boardC >= COLS || boardR >= TOTAL_ROWS) return true; + if (boardR < 0) continue; + if (grid[boardR][boardC] !== null) return true; + } + } + return false; + } + function lockPiece(grid, piece) { + const shape = piece.def.shapes[piece.rotation]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) continue; + const boardR = piece.row + r; + const boardC = piece.col + c; + if (boardR >= 0 && boardR < TOTAL_ROWS && boardC >= 0 && boardC < COLS) { + grid[boardR][boardC] = piece.def.color; + } + } + } + } + function clearLines(grid) { + let cleared = 0; + for (let r = TOTAL_ROWS - 1; r >= 0; r--) { + if (grid[r].every((cell) => cell !== null)) { + grid.splice(r, 1); + grid.unshift(new Array(COLS).fill(null)); + cleared++; + r++; + } + } + return cleared; + } + function isTopOut(grid) { + for (let r = 0; r < HIDDEN_ROWS; r++) { + if (grid[r].some((cell) => cell !== null)) return true; + } + return false; + } + var ROWS, COLS, HIDDEN_ROWS, TOTAL_ROWS; + var init_board = __esm({ + "src/board.ts"() { + "use strict"; + ROWS = 20; + COLS = 10; + HIDDEN_ROWS = 4; + TOTAL_ROWS = ROWS + HIDDEN_ROWS; + } + }); + + // src/game.ts + function getSpeed(level) { + if (level >= LEVEL_SPEEDS.length) return LEVEL_SPEEDS[LEVEL_SPEEDS.length - 1]; + return LEVEL_SPEEDS[level]; + } + var LINE_SCORES, LEVEL_SPEEDS, Game; + var init_game = __esm({ + "src/game.ts"() { + "use strict"; + init_pieces(); + init_board(); + LINE_SCORES = [0, 40, 100, 300, 1200]; + LEVEL_SPEEDS = [ + 800, + 720, + 630, + 550, + 470, + 380, + 300, + 220, + 140, + 100, + 83, + 83, + 83, + 67, + 67, + 67, + 50, + 50, + 50, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 17 + ]; + Game = class { + constructor() { + this.dropTimer = 0; + this.lastTime = 0; + this.softDropping = false; + this.lockDelay = 0; + this.LOCK_DELAY_MS = 500; + this.lockMoves = 0; + this.MAX_LOCK_MOVES = 15; + this.bag = new BagRandomizer(); + const first = this.bag.next(); + const next = this.bag.next(); + this.state = { + grid: createGrid(), + active: this.spawnPiece(first), + next, + score: 0, + lines: 0, + level: 0, + gameOver: false, + paused: false + }; + } + spawnPiece(def) { + const shape = def.shapes[0]; + const col = Math.floor((COLS - shape[0].length) / 2); + const row = HIDDEN_ROWS - shape.findIndex((r) => r.some(Boolean)); + return { def, rotation: 0, row: row - 1, col }; + } + /** Main update loop — call with requestAnimationFrame timestamp */ + update(timestamp) { + if (this.state.gameOver || this.state.paused) { + this.lastTime = timestamp; + return; + } + if (this.lastTime === 0) this.lastTime = timestamp; + const dt = timestamp - this.lastTime; + this.lastTime = timestamp; + const speed = this.softDropping ? Math.min(getSpeed(this.state.level), 50) : getSpeed(this.state.level); + const resting = collides(this.state.grid, this.state.active, 1, 0); + if (resting) { + this.lockDelay += dt; + if (this.lockDelay >= this.LOCK_DELAY_MS || this.lockMoves >= this.MAX_LOCK_MOVES) { + this.lock(); + return; + } + } else { + this.lockDelay = 0; + } + this.dropTimer += dt; + if (this.dropTimer >= speed) { + this.dropTimer = 0; + this.moveDown(); + } + } + moveDown() { + if (!collides(this.state.grid, this.state.active, 1, 0)) { + this.state.active.row++; + if (this.softDropping) { + this.state.score += 1; + } + return true; + } + return false; + } + lock() { + lockPiece(this.state.grid, this.state.active); + const cleared = clearLines(this.state.grid); + if (cleared > 0) { + this.state.lines += cleared; + this.state.score += LINE_SCORES[cleared] * (this.state.level + 1); + this.state.level = Math.floor(this.state.lines / 10); + } + if (isTopOut(this.state.grid)) { + this.state.gameOver = true; + this.onStateChange?.(); + return; + } + this.state.active = this.spawnPiece(this.state.next); + this.state.next = this.bag.next(); + this.dropTimer = 0; + this.lockDelay = 0; + this.lockMoves = 0; + if (collides(this.state.grid, this.state.active)) { + this.state.gameOver = true; + } + this.onStateChange?.(); + } + /* ── Player actions ── */ + moveLeft() { + if (this.state.gameOver || this.state.paused) return; + if (!collides(this.state.grid, this.state.active, 0, -1)) { + this.state.active.col--; + this.resetLockIfMoved(); + } + } + moveRight() { + if (this.state.gameOver || this.state.paused) return; + if (!collides(this.state.grid, this.state.active, 0, 1)) { + this.state.active.col++; + this.resetLockIfMoved(); + } + } + rotateCW() { + this.tryRotate(1); + } + rotateCCW() { + this.tryRotate(-1); + } + tryRotate(dir) { + if (this.state.gameOver || this.state.paused) return; + const piece = this.state.active; + const fromRot = piece.rotation; + const toRot = (fromRot + dir + 4) % 4; + const kicks = getKicks(piece.def.name, fromRot, toRot); + for (const [kickRow, kickCol] of kicks) { + const testPiece = { + ...piece, + rotation: toRot, + row: piece.row - kickRow, + // SRS kick rows are inverted from our coordinate system + col: piece.col + kickCol + }; + if (!collides(this.state.grid, testPiece)) { + this.state.active = testPiece; + this.resetLockIfMoved(); + return; + } + } + } + hardDrop() { + if (this.state.gameOver || this.state.paused) return; + let dropped = 0; + while (!collides(this.state.grid, this.state.active, 1, 0)) { + this.state.active.row++; + dropped++; + } + this.state.score += dropped * 2; + this.lock(); + } + setSoftDrop(active) { + this.softDropping = active; + } + togglePause() { + if (this.state.gameOver) return; + this.state.paused = !this.state.paused; + } + restart() { + this.bag = new BagRandomizer(); + const first = this.bag.next(); + const next = this.bag.next(); + this.state = { + grid: createGrid(), + active: this.spawnPiece(first), + next, + score: 0, + lines: 0, + level: 0, + gameOver: false, + paused: false + }; + this.dropTimer = 0; + this.lastTime = 0; + this.lockDelay = 0; + this.lockMoves = 0; + this.softDropping = false; + } + /** Get the ghost piece row (where the piece would land) */ + getGhostRow() { + let offset = 0; + while (!collides(this.state.grid, this.state.active, offset + 1, 0)) { + offset++; + } + return this.state.active.row + offset; + } + resetLockIfMoved() { + if (collides(this.state.grid, this.state.active, 1, 0)) { + this.lockDelay = 0; + this.lockMoves++; + } + } + }; + } + }); + + // src/renderer.ts + var CELL_SIZE, BORDER, BOARD_WIDTH, BOARD_HEIGHT, COLORS, Renderer; + var init_renderer = __esm({ + "src/renderer.ts"() { + "use strict"; + init_board(); + CELL_SIZE = 30; + BORDER = 1; + BOARD_WIDTH = COLS * CELL_SIZE; + BOARD_HEIGHT = ROWS * CELL_SIZE; + COLORS = { + bg: "#111", + gridLine: "#222", + ghost: "rgba(255,255,255,0.15)", + locked: "#333", + text: "#eee", + textDim: "#888", + panelBg: "#1a1a1a", + border: "#444" + }; + Renderer = class { + constructor(canvas, previewCanvas) { + this.canvas = canvas; + this.ctx = canvas.getContext("2d"); + this.previewCanvas = previewCanvas; + this.previewCtx = previewCanvas.getContext("2d"); + canvas.width = BOARD_WIDTH; + canvas.height = BOARD_HEIGHT; + previewCanvas.width = CELL_SIZE * 5; + previewCanvas.height = CELL_SIZE * 5; + } + draw(state, ghostRow) { + const ctx = this.ctx; + ctx.fillStyle = COLORS.bg; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + ctx.strokeStyle = COLORS.gridLine; + ctx.lineWidth = 0.5; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * CELL_SIZE); + ctx.lineTo(BOARD_WIDTH, r * CELL_SIZE); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * CELL_SIZE, 0); + ctx.lineTo(c * CELL_SIZE, BOARD_HEIGHT); + ctx.stroke(); + } + for (let r = HIDDEN_ROWS; r < TOTAL_ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const cell = state.grid[r][c]; + if (cell) { + this.drawCell(ctx, r - HIDDEN_ROWS, c, cell); + } + } + } + if (!state.gameOver && !state.paused) { + const shape = state.active.def.shapes[state.active.rotation]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) continue; + const drawR = ghostRow + r - HIDDEN_ROWS; + const drawC = state.active.col + c; + if (drawR >= 0 && drawR < ROWS) { + this.drawCell(ctx, drawR, drawC, COLORS.ghost, true); + } + } + } + } + if (!state.gameOver && !state.paused) { + const shape = state.active.def.shapes[state.active.rotation]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) continue; + const drawR = state.active.row + r - HIDDEN_ROWS; + const drawC = state.active.col + c; + if (drawR >= 0 && drawR < ROWS) { + this.drawCell(ctx, drawR, drawC, state.active.def.color); + } + } + } + } + if (state.paused) { + ctx.fillStyle = "rgba(0, 0, 0, 0.7)"; + ctx.fillRect(0, 0, BOARD_WIDTH, BOARD_HEIGHT); + ctx.fillStyle = COLORS.text; + ctx.font = "bold 28px monospace"; + ctx.textAlign = "center"; + ctx.fillText("PAUSED", BOARD_WIDTH / 2, BOARD_HEIGHT / 2); + ctx.font = "14px monospace"; + ctx.fillStyle = COLORS.textDim; + ctx.fillText("Press P to resume", BOARD_WIDTH / 2, BOARD_HEIGHT / 2 + 30); + } + if (state.gameOver) { + ctx.fillStyle = "rgba(0, 0, 0, 0.75)"; + ctx.fillRect(0, 0, BOARD_WIDTH, BOARD_HEIGHT); + ctx.fillStyle = "#f44"; + ctx.font = "bold 32px monospace"; + ctx.textAlign = "center"; + ctx.fillText("GAME OVER", BOARD_WIDTH / 2, BOARD_HEIGHT / 2 - 10); + ctx.fillStyle = COLORS.text; + ctx.font = "16px monospace"; + ctx.fillText(`Score: ${state.score}`, BOARD_WIDTH / 2, BOARD_HEIGHT / 2 + 25); + ctx.font = "14px monospace"; + ctx.fillStyle = COLORS.textDim; + ctx.fillText("Press R to restart", BOARD_WIDTH / 2, BOARD_HEIGHT / 2 + 55); + } + this.drawPreview(state.next); + this.updateScoreboard(state); + } + drawCell(ctx, row, col, color, isGhost = false) { + const x = col * CELL_SIZE; + const y = row * CELL_SIZE; + const inset = BORDER; + if (isGhost) { + ctx.fillStyle = color; + ctx.fillRect(x + inset, y + inset, CELL_SIZE - inset * 2, CELL_SIZE - inset * 2); + return; + } + ctx.fillStyle = color; + ctx.fillRect(x + inset, y + inset, CELL_SIZE - inset * 2, CELL_SIZE - inset * 2); + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x + inset, y + inset, CELL_SIZE - inset * 2, 3); + ctx.fillRect(x + inset, y + inset, 3, CELL_SIZE - inset * 2); + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(x + inset, y + CELL_SIZE - inset - 3, CELL_SIZE - inset * 2, 3); + ctx.fillRect(x + CELL_SIZE - inset - 3, y + inset, 3, CELL_SIZE - inset * 2); + } + drawPreview(piece) { + const ctx = this.previewCtx; + const size = CELL_SIZE; + ctx.fillStyle = COLORS.panelBg; + ctx.fillRect(0, 0, this.previewCanvas.width, this.previewCanvas.height); + const shape = piece.shapes[0]; + const shapeH = shape.length; + const shapeW = shape[0].length; + const offsetX = Math.floor((5 - shapeW) / 2); + const offsetY = Math.floor((5 - shapeH) / 2); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) continue; + const x = (offsetX + c) * size; + const y = (offsetY + r) * size; + ctx.fillStyle = piece.color; + ctx.fillRect(x + 1, y + 1, size - 2, size - 2); + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x + 1, y + 1, size - 2, 3); + ctx.fillRect(x + 1, y + 1, 3, size - 2); + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(x + 1, y + size - 4, size - 2, 3); + ctx.fillRect(x + size - 4, y + 1, 3, size - 2); + } + } + } + updateScoreboard(state) { + const scoreEl = document.getElementById("score-value"); + const linesEl = document.getElementById("lines-value"); + const levelEl = document.getElementById("level-value"); + if (scoreEl) scoreEl.textContent = state.score.toString(); + if (linesEl) linesEl.textContent = state.lines.toString(); + if (levelEl) levelEl.textContent = state.level.toString(); + } + }; + } + }); + + // src/main.ts + var require_main = __commonJS({ + "src/main.ts"() { + init_game(); + init_renderer(); + function main() { + const canvas = document.getElementById("game-canvas"); + const previewCanvas = document.getElementById("preview-canvas"); + if (!canvas || !previewCanvas) { + throw new Error("Required canvas elements not found"); + } + const game = new Game(); + const renderer = new Renderer(canvas, previewCanvas); + const DAS_DELAY = 170; + const DAS_RATE = 50; + const heldKeys = /* @__PURE__ */ new Set(); + const keyTimers = /* @__PURE__ */ new Map(); + function executeAction(key) { + switch (key) { + case "ArrowLeft": + game.moveLeft(); + break; + case "ArrowRight": + game.moveRight(); + break; + case "ArrowDown": + break; + case "ArrowUp": + game.rotateCW(); + break; + case "KeyZ": + case "ControlLeft": + case "ControlRight": + game.rotateCCW(); + break; + case "Space": + game.hardDrop(); + break; + case "KeyP": + case "Escape": + game.togglePause(); + break; + case "KeyR": + if (game.state.gameOver) { + game.restart(); + } + break; + } + } + function startAutoRepeat(key) { + if (key !== "ArrowLeft" && key !== "ArrowRight") return; + const delay = setTimeout(() => { + const interval = setInterval(() => { + executeAction(key); + }, DAS_RATE); + const entry = keyTimers.get(key); + if (entry) entry.interval = interval; + }, DAS_DELAY); + keyTimers.set(key, { delay, interval: 0 }); + } + function stopAutoRepeat(key) { + const entry = keyTimers.get(key); + if (entry) { + clearTimeout(entry.delay); + clearInterval(entry.interval); + keyTimers.delete(key); + } + } + document.addEventListener("keydown", (e) => { + const gameKeys = [ + "ArrowLeft", + "ArrowRight", + "ArrowUp", + "ArrowDown", + "Space", + "KeyZ", + "KeyP", + "KeyR", + "Escape" + ]; + const key = e.code; + if (gameKeys.includes(key)) { + e.preventDefault(); + } + if (heldKeys.has(key)) return; + heldKeys.add(key); + if (key === "ArrowDown") { + game.setSoftDrop(true); + } + executeAction(key); + startAutoRepeat(key); + }); + document.addEventListener("keyup", (e) => { + const key = e.code; + heldKeys.delete(key); + stopAutoRepeat(key); + if (key === "ArrowDown") { + game.setSoftDrop(false); + } + }); + window.addEventListener("blur", () => { + heldKeys.clear(); + keyTimers.forEach((entry) => { + clearTimeout(entry.delay); + clearInterval(entry.interval); + }); + keyTimers.clear(); + game.setSoftDrop(false); + }); + function loop(timestamp) { + game.update(timestamp); + renderer.draw(game.state, game.getGhostRow()); + requestAnimationFrame(loop); + } + requestAnimationFrame(loop); + } + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", main); + } else { + main(); + } + } + }); + require_main(); +})(); +//# sourceMappingURL=bundle.js.map diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/bundle.js.map b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=opus_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/bundle.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../src/pieces.ts", "../src/board.ts", "../src/game.ts", "../src/renderer.ts", "../src/main.ts"], + "sourcesContent": ["import { PieceDef, Shape, Kick } from \"./types\";\n\n/**\n * Rotate a shape matrix 90\u00B0 clockwise.\n */\nfunction rotateCW(shape: Shape): Shape {\n const rows = shape.length;\n const cols = shape[0].length;\n const result: Shape = [];\n for (let c = 0; c < cols; c++) {\n result[c] = [];\n for (let r = rows - 1; r >= 0; r--) {\n result[c].push(shape[r][c]);\n }\n }\n return result;\n}\n\nfunction buildRotations(base: Shape): Shape[] {\n const r0 = base;\n const r1 = rotateCW(r0);\n const r2 = rotateCW(r1);\n const r3 = rotateCW(r2);\n return [r0, r1, r2, r3];\n}\n\n// Helper to parse a string template into a Shape\nfunction parse(template: string): Shape {\n return template\n .trim()\n .split(\"\\n\")\n .map((line) => [...line.trim()].map((ch) => ch === \"#\"));\n}\n\n/* \u2500\u2500 Tetromino definitions \u2500\u2500 */\n\nconst I_BASE = parse(`\n....\n####\n....\n....\n`);\n\nconst O_BASE = parse(`\n##\n##\n`);\n\nconst T_BASE = parse(`\n.#.\n###\n...\n`);\n\nconst S_BASE = parse(`\n.##\n##.\n...\n`);\n\nconst Z_BASE = parse(`\n##.\n.##\n...\n`);\n\nconst L_BASE = parse(`\n..#\n###\n...\n`);\n\nconst J_BASE = parse(`\n#..\n###\n...\n`);\n\nexport const PIECES: PieceDef[] = [\n { name: \"I\", color: \"#00f0f0\", shapes: buildRotations(I_BASE) },\n { name: \"O\", color: \"#f0f000\", shapes: buildRotations(O_BASE) },\n { name: \"T\", color: \"#a000f0\", shapes: buildRotations(T_BASE) },\n { name: \"S\", color: \"#00f000\", shapes: buildRotations(S_BASE) },\n { name: \"Z\", color: \"#f00000\", shapes: buildRotations(Z_BASE) },\n { name: \"L\", color: \"#f0a000\", shapes: buildRotations(L_BASE) },\n { name: \"J\", color: \"#0000f0\", shapes: buildRotations(J_BASE) },\n];\n\n/* \u2500\u2500 SRS Wall Kick Data \u2500\u2500 */\n// Kicks for J, L, S, T, Z pieces\nconst JLSTZ_KICKS: Record<string, Kick[]> = {\n \"0>1\": [[0, 0], [0, -1], [-1, -1], [2, 0], [2, -1]],\n \"1>0\": [[0, 0], [0, 1], [1, 1], [-2, 0], [-2, 1]],\n \"1>2\": [[0, 0], [0, 1], [1, 1], [-2, 0], [-2, 1]],\n \"2>1\": [[0, 0], [0, -1], [-1, -1], [2, 0], [2, -1]],\n \"2>3\": [[0, 0], [0, 1], [-1, 1], [2, 0], [2, 1]],\n \"3>2\": [[0, 0], [0, -1], [1, -1], [-2, 0], [-2, -1]],\n \"3>0\": [[0, 0], [0, -1], [1, -1], [-2, 0], [-2, -1]],\n \"0>3\": [[0, 0], [0, 1], [-1, 1], [2, 0], [2, 1]],\n};\n\n// Kicks for I piece\nconst I_KICKS: Record<string, Kick[]> = {\n \"0>1\": [[0, 0], [0, -2], [0, 1], [-1, -2], [2, 1]],\n \"1>0\": [[0, 0], [0, 2], [0, -1], [1, 2], [-2, -1]],\n \"1>2\": [[0, 0], [0, -1], [0, 2], [2, -1], [-1, 2]],\n \"2>1\": [[0, 0], [0, 1], [0, -2], [-2, 1], [1, -2]],\n \"2>3\": [[0, 0], [0, 2], [0, -1], [1, 2], [-2, -1]],\n \"3>2\": [[0, 0], [0, -2], [0, 1], [-1, -2], [2, 1]],\n \"3>0\": [[0, 0], [0, 1], [0, -2], [-2, 1], [1, -2]],\n \"0>3\": [[0, 0], [0, -1], [0, 2], [2, -1], [-1, 2]],\n};\n\nexport function getKicks(pieceName: string, fromRot: number, toRot: number): Kick[] {\n const key = `${fromRot}>${toRot}`;\n if (pieceName === \"I\") return I_KICKS[key] ?? [[0, 0]];\n if (pieceName === \"O\") return [[0, 0]]; // O doesn't kick\n return JLSTZ_KICKS[key] ?? [[0, 0]];\n}\n\n/** 7-bag randomizer */\nexport class BagRandomizer {\n private bag: PieceDef[] = [];\n\n next(): PieceDef {\n if (this.bag.length === 0) {\n this.bag = [...PIECES];\n // Fisher-Yates shuffle\n for (let i = this.bag.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]];\n }\n }\n return this.bag.pop()!;\n }\n}\n", "import { Grid, Cell, ActivePiece } from \"./types\";\n\nexport const ROWS = 20;\nexport const COLS = 10;\nexport const HIDDEN_ROWS = 4; // extra rows above visible area for spawning\nexport const TOTAL_ROWS = ROWS + HIDDEN_ROWS;\n\nexport function createGrid(): Grid {\n const grid: Grid = [];\n for (let r = 0; r < TOTAL_ROWS; r++) {\n grid.push(new Array<Cell>(COLS).fill(null));\n }\n return grid;\n}\n\n/** Check whether a piece at the given position collides with walls or locked cells */\nexport function collides(grid: Grid, piece: ActivePiece, rowOff = 0, colOff = 0): boolean {\n const shape = piece.def.shapes[piece.rotation];\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const boardR = piece.row + r + rowOff;\n const boardC = piece.col + c + colOff;\n // Out of bounds\n if (boardC < 0 || boardC >= COLS || boardR >= TOTAL_ROWS) return true;\n // Above the ceiling is okay (pieces spawn there)\n if (boardR < 0) continue;\n // Occupied cell\n if (grid[boardR][boardC] !== null) return true;\n }\n }\n return false;\n}\n\n/** Lock the active piece into the grid */\nexport function lockPiece(grid: Grid, piece: ActivePiece): void {\n const shape = piece.def.shapes[piece.rotation];\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const boardR = piece.row + r;\n const boardC = piece.col + c;\n if (boardR >= 0 && boardR < TOTAL_ROWS && boardC >= 0 && boardC < COLS) {\n grid[boardR][boardC] = piece.def.color;\n }\n }\n }\n}\n\n/** Clear completed lines, return the number cleared */\nexport function clearLines(grid: Grid): number {\n let cleared = 0;\n for (let r = TOTAL_ROWS - 1; r >= 0; r--) {\n if (grid[r].every((cell) => cell !== null)) {\n grid.splice(r, 1);\n grid.unshift(new Array<Cell>(COLS).fill(null));\n cleared++;\n r++; // re-check same index since rows shifted down\n }\n }\n return cleared;\n}\n\n/** Check if any locked block is in the hidden zone (game over condition) */\nexport function isTopOut(grid: Grid): boolean {\n for (let r = 0; r < HIDDEN_ROWS; r++) {\n if (grid[r].some((cell) => cell !== null)) return true;\n }\n return false;\n}\n", "import { GameState, ActivePiece, PieceDef } from \"./types\";\nimport { BagRandomizer, getKicks } from \"./pieces\";\nimport {\n COLS,\n HIDDEN_ROWS,\n TOTAL_ROWS,\n createGrid,\n collides,\n lockPiece,\n clearLines,\n isTopOut,\n} from \"./board\";\n\n/** Points awarded per lines cleared (indexed 1-4) */\nconst LINE_SCORES = [0, 40, 100, 300, 1200];\n\n/** Frames per gravity drop at each level (NES-style curve, capped at level 29) */\nconst LEVEL_SPEEDS: number[] = [\n 800, 720, 630, 550, 470, 380, 300, 220, 140, 100,\n 83, 83, 83, 67, 67, 67, 50, 50, 50, 33,\n 33, 33, 33, 33, 33, 33, 33, 33, 33, 17,\n];\n\nfunction getSpeed(level: number): number {\n if (level >= LEVEL_SPEEDS.length) return LEVEL_SPEEDS[LEVEL_SPEEDS.length - 1];\n return LEVEL_SPEEDS[level];\n}\n\nexport class Game {\n state: GameState;\n private bag: BagRandomizer;\n private dropTimer = 0;\n private lastTime = 0;\n private softDropping = false;\n private lockDelay = 0;\n private readonly LOCK_DELAY_MS = 500;\n private lockMoves = 0;\n private readonly MAX_LOCK_MOVES = 15;\n\n // Callbacks\n onStateChange?: () => void;\n\n constructor() {\n this.bag = new BagRandomizer();\n const first = this.bag.next();\n const next = this.bag.next();\n this.state = {\n grid: createGrid(),\n active: this.spawnPiece(first),\n next,\n score: 0,\n lines: 0,\n level: 0,\n gameOver: false,\n paused: false,\n };\n }\n\n private spawnPiece(def: PieceDef): ActivePiece {\n const shape = def.shapes[0];\n const col = Math.floor((COLS - shape[0].length) / 2);\n // Spawn so that piece top is at the top of the visible area\n const row = HIDDEN_ROWS - shape.findIndex((r) => r.some(Boolean));\n return { def, rotation: 0, row: row - 1, col };\n }\n\n /** Main update loop \u2014 call with requestAnimationFrame timestamp */\n update(timestamp: number): void {\n if (this.state.gameOver || this.state.paused) {\n this.lastTime = timestamp;\n return;\n }\n\n if (this.lastTime === 0) this.lastTime = timestamp;\n const dt = timestamp - this.lastTime;\n this.lastTime = timestamp;\n\n const speed = this.softDropping\n ? Math.min(getSpeed(this.state.level), 50)\n : getSpeed(this.state.level);\n\n // Check if piece is resting on something\n const resting = collides(this.state.grid, this.state.active, 1, 0);\n\n if (resting) {\n this.lockDelay += dt;\n if (this.lockDelay >= this.LOCK_DELAY_MS || this.lockMoves >= this.MAX_LOCK_MOVES) {\n this.lock();\n return;\n }\n } else {\n this.lockDelay = 0;\n }\n\n this.dropTimer += dt;\n if (this.dropTimer >= speed) {\n this.dropTimer = 0;\n this.moveDown();\n }\n }\n\n private moveDown(): boolean {\n if (!collides(this.state.grid, this.state.active, 1, 0)) {\n this.state.active.row++;\n if (this.softDropping) {\n this.state.score += 1; // soft drop bonus\n }\n return true;\n }\n return false;\n }\n\n private lock(): void {\n lockPiece(this.state.grid, this.state.active);\n const cleared = clearLines(this.state.grid);\n if (cleared > 0) {\n this.state.lines += cleared;\n this.state.score += LINE_SCORES[cleared] * (this.state.level + 1);\n this.state.level = Math.floor(this.state.lines / 10);\n }\n\n if (isTopOut(this.state.grid)) {\n this.state.gameOver = true;\n this.onStateChange?.();\n return;\n }\n\n // Spawn next piece\n this.state.active = this.spawnPiece(this.state.next);\n this.state.next = this.bag.next();\n this.dropTimer = 0;\n this.lockDelay = 0;\n this.lockMoves = 0;\n\n // If spawned piece immediately collides, game over\n if (collides(this.state.grid, this.state.active)) {\n this.state.gameOver = true;\n }\n\n this.onStateChange?.();\n }\n\n /* \u2500\u2500 Player actions \u2500\u2500 */\n\n moveLeft(): void {\n if (this.state.gameOver || this.state.paused) return;\n if (!collides(this.state.grid, this.state.active, 0, -1)) {\n this.state.active.col--;\n this.resetLockIfMoved();\n }\n }\n\n moveRight(): void {\n if (this.state.gameOver || this.state.paused) return;\n if (!collides(this.state.grid, this.state.active, 0, 1)) {\n this.state.active.col++;\n this.resetLockIfMoved();\n }\n }\n\n rotateCW(): void {\n this.tryRotate(1);\n }\n\n rotateCCW(): void {\n this.tryRotate(-1);\n }\n\n private tryRotate(dir: 1 | -1): void {\n if (this.state.gameOver || this.state.paused) return;\n const piece = this.state.active;\n const fromRot = piece.rotation;\n const toRot = (fromRot + dir + 4) % 4;\n const kicks = getKicks(piece.def.name, fromRot, toRot);\n\n for (const [kickRow, kickCol] of kicks) {\n const testPiece: ActivePiece = {\n ...piece,\n rotation: toRot,\n row: piece.row - kickRow, // SRS kick rows are inverted from our coordinate system\n col: piece.col + kickCol,\n };\n if (!collides(this.state.grid, testPiece)) {\n this.state.active = testPiece;\n this.resetLockIfMoved();\n return;\n }\n }\n }\n\n hardDrop(): void {\n if (this.state.gameOver || this.state.paused) return;\n let dropped = 0;\n while (!collides(this.state.grid, this.state.active, 1, 0)) {\n this.state.active.row++;\n dropped++;\n }\n this.state.score += dropped * 2; // hard drop bonus\n this.lock();\n }\n\n setSoftDrop(active: boolean): void {\n this.softDropping = active;\n }\n\n togglePause(): void {\n if (this.state.gameOver) return;\n this.state.paused = !this.state.paused;\n }\n\n restart(): void {\n this.bag = new BagRandomizer();\n const first = this.bag.next();\n const next = this.bag.next();\n this.state = {\n grid: createGrid(),\n active: this.spawnPiece(first),\n next,\n score: 0,\n lines: 0,\n level: 0,\n gameOver: false,\n paused: false,\n };\n this.dropTimer = 0;\n this.lastTime = 0;\n this.lockDelay = 0;\n this.lockMoves = 0;\n this.softDropping = false;\n }\n\n /** Get the ghost piece row (where the piece would land) */\n getGhostRow(): number {\n let offset = 0;\n while (!collides(this.state.grid, this.state.active, offset + 1, 0)) {\n offset++;\n }\n return this.state.active.row + offset;\n }\n\n private resetLockIfMoved(): void {\n if (collides(this.state.grid, this.state.active, 1, 0)) {\n this.lockDelay = 0;\n this.lockMoves++;\n }\n }\n}\n", "import { GameState, PieceDef } from \"./types\";\nimport { ROWS, COLS, HIDDEN_ROWS, TOTAL_ROWS } from \"./board\";\n\nconst CELL_SIZE = 30;\nconst BORDER = 1;\nconst BOARD_WIDTH = COLS * CELL_SIZE;\nconst BOARD_HEIGHT = ROWS * CELL_SIZE;\n\nconst COLORS = {\n bg: \"#111\",\n gridLine: \"#222\",\n ghost: \"rgba(255,255,255,0.15)\",\n locked: \"#333\",\n text: \"#eee\",\n textDim: \"#888\",\n panelBg: \"#1a1a1a\",\n border: \"#444\",\n};\n\nexport class Renderer {\n private canvas: HTMLCanvasElement;\n private ctx: CanvasRenderingContext2D;\n private previewCanvas: HTMLCanvasElement;\n private previewCtx: CanvasRenderingContext2D;\n\n constructor(canvas: HTMLCanvasElement, previewCanvas: HTMLCanvasElement) {\n this.canvas = canvas;\n this.ctx = canvas.getContext(\"2d\")!;\n this.previewCanvas = previewCanvas;\n this.previewCtx = previewCanvas.getContext(\"2d\")!;\n\n canvas.width = BOARD_WIDTH;\n canvas.height = BOARD_HEIGHT;\n previewCanvas.width = CELL_SIZE * 5;\n previewCanvas.height = CELL_SIZE * 5;\n }\n\n draw(state: GameState, ghostRow: number): void {\n const ctx = this.ctx;\n\n // Clear\n ctx.fillStyle = COLORS.bg;\n ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);\n\n // Draw grid lines\n ctx.strokeStyle = COLORS.gridLine;\n ctx.lineWidth = 0.5;\n for (let r = 0; r <= ROWS; r++) {\n ctx.beginPath();\n ctx.moveTo(0, r * CELL_SIZE);\n ctx.lineTo(BOARD_WIDTH, r * CELL_SIZE);\n ctx.stroke();\n }\n for (let c = 0; c <= COLS; c++) {\n ctx.beginPath();\n ctx.moveTo(c * CELL_SIZE, 0);\n ctx.lineTo(c * CELL_SIZE, BOARD_HEIGHT);\n ctx.stroke();\n }\n\n // Draw locked cells (only visible rows)\n for (let r = HIDDEN_ROWS; r < TOTAL_ROWS; r++) {\n for (let c = 0; c < COLS; c++) {\n const cell = state.grid[r][c];\n if (cell) {\n this.drawCell(ctx, r - HIDDEN_ROWS, c, cell);\n }\n }\n }\n\n // Draw ghost piece\n if (!state.gameOver && !state.paused) {\n const shape = state.active.def.shapes[state.active.rotation];\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const drawR = ghostRow + r - HIDDEN_ROWS;\n const drawC = state.active.col + c;\n if (drawR >= 0 && drawR < ROWS) {\n this.drawCell(ctx, drawR, drawC, COLORS.ghost, true);\n }\n }\n }\n }\n\n // Draw active piece\n if (!state.gameOver && !state.paused) {\n const shape = state.active.def.shapes[state.active.rotation];\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const drawR = state.active.row + r - HIDDEN_ROWS;\n const drawC = state.active.col + c;\n if (drawR >= 0 && drawR < ROWS) {\n this.drawCell(ctx, drawR, drawC, state.active.def.color);\n }\n }\n }\n }\n\n // Draw pause overlay\n if (state.paused) {\n ctx.fillStyle = \"rgba(0, 0, 0, 0.7)\";\n ctx.fillRect(0, 0, BOARD_WIDTH, BOARD_HEIGHT);\n ctx.fillStyle = COLORS.text;\n ctx.font = \"bold 28px monospace\";\n ctx.textAlign = \"center\";\n ctx.fillText(\"PAUSED\", BOARD_WIDTH / 2, BOARD_HEIGHT / 2);\n ctx.font = \"14px monospace\";\n ctx.fillStyle = COLORS.textDim;\n ctx.fillText(\"Press P to resume\", BOARD_WIDTH / 2, BOARD_HEIGHT / 2 + 30);\n }\n\n // Draw game over overlay\n if (state.gameOver) {\n ctx.fillStyle = \"rgba(0, 0, 0, 0.75)\";\n ctx.fillRect(0, 0, BOARD_WIDTH, BOARD_HEIGHT);\n ctx.fillStyle = \"#f44\";\n ctx.font = \"bold 32px monospace\";\n ctx.textAlign = \"center\";\n ctx.fillText(\"GAME OVER\", BOARD_WIDTH / 2, BOARD_HEIGHT / 2 - 10);\n ctx.fillStyle = COLORS.text;\n ctx.font = \"16px monospace\";\n ctx.fillText(`Score: ${state.score}`, BOARD_WIDTH / 2, BOARD_HEIGHT / 2 + 25);\n ctx.font = \"14px monospace\";\n ctx.fillStyle = COLORS.textDim;\n ctx.fillText(\"Press R to restart\", BOARD_WIDTH / 2, BOARD_HEIGHT / 2 + 55);\n }\n\n // Draw next piece preview\n this.drawPreview(state.next);\n\n // Update score display in DOM\n this.updateScoreboard(state);\n }\n\n private drawCell(\n ctx: CanvasRenderingContext2D,\n row: number,\n col: number,\n color: string,\n isGhost = false\n ): void {\n const x = col * CELL_SIZE;\n const y = row * CELL_SIZE;\n const inset = BORDER;\n\n if (isGhost) {\n ctx.fillStyle = color;\n ctx.fillRect(x + inset, y + inset, CELL_SIZE - inset * 2, CELL_SIZE - inset * 2);\n return;\n }\n\n // Main fill\n ctx.fillStyle = color;\n ctx.fillRect(x + inset, y + inset, CELL_SIZE - inset * 2, CELL_SIZE - inset * 2);\n\n // Highlight (top-left bevel)\n ctx.fillStyle = \"rgba(255,255,255,0.25)\";\n ctx.fillRect(x + inset, y + inset, CELL_SIZE - inset * 2, 3);\n ctx.fillRect(x + inset, y + inset, 3, CELL_SIZE - inset * 2);\n\n // Shadow (bottom-right bevel)\n ctx.fillStyle = \"rgba(0,0,0,0.3)\";\n ctx.fillRect(x + inset, y + CELL_SIZE - inset - 3, CELL_SIZE - inset * 2, 3);\n ctx.fillRect(x + CELL_SIZE - inset - 3, y + inset, 3, CELL_SIZE - inset * 2);\n }\n\n private drawPreview(piece: PieceDef): void {\n const ctx = this.previewCtx;\n const size = CELL_SIZE;\n ctx.fillStyle = COLORS.panelBg;\n ctx.fillRect(0, 0, this.previewCanvas.width, this.previewCanvas.height);\n\n const shape = piece.shapes[0];\n const shapeH = shape.length;\n const shapeW = shape[0].length;\n const offsetX = Math.floor((5 - shapeW) / 2);\n const offsetY = Math.floor((5 - shapeH) / 2);\n\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const x = (offsetX + c) * size;\n const y = (offsetY + r) * size;\n\n ctx.fillStyle = piece.color;\n ctx.fillRect(x + 1, y + 1, size - 2, size - 2);\n\n ctx.fillStyle = \"rgba(255,255,255,0.25)\";\n ctx.fillRect(x + 1, y + 1, size - 2, 3);\n ctx.fillRect(x + 1, y + 1, 3, size - 2);\n\n ctx.fillStyle = \"rgba(0,0,0,0.3)\";\n ctx.fillRect(x + 1, y + size - 4, size - 2, 3);\n ctx.fillRect(x + size - 4, y + 1, 3, size - 2);\n }\n }\n }\n\n private updateScoreboard(state: GameState): void {\n const scoreEl = document.getElementById(\"score-value\");\n const linesEl = document.getElementById(\"lines-value\");\n const levelEl = document.getElementById(\"level-value\");\n if (scoreEl) scoreEl.textContent = state.score.toString();\n if (linesEl) linesEl.textContent = state.lines.toString();\n if (levelEl) levelEl.textContent = state.level.toString();\n }\n}\n", "import { Game } from \"./game\";\nimport { Renderer } from \"./renderer\";\n\nfunction main(): void {\n const canvas = document.getElementById(\"game-canvas\") as HTMLCanvasElement;\n const previewCanvas = document.getElementById(\"preview-canvas\") as HTMLCanvasElement;\n\n if (!canvas || !previewCanvas) {\n throw new Error(\"Required canvas elements not found\");\n }\n\n const game = new Game();\n const renderer = new Renderer(canvas, previewCanvas);\n\n /* \u2500\u2500 Keyboard handling with DAS (Delayed Auto Shift) \u2500\u2500 */\n const DAS_DELAY = 170; // ms before auto-repeat starts\n const DAS_RATE = 50; // ms between auto-repeat moves\n\n const heldKeys = new Set<string>();\n const keyTimers = new Map<string, { delay: ReturnType<typeof setTimeout>; interval: ReturnType<typeof setInterval> }>();\n\n function executeAction(key: string): void {\n switch (key) {\n case \"ArrowLeft\":\n game.moveLeft();\n break;\n case \"ArrowRight\":\n game.moveRight();\n break;\n case \"ArrowDown\":\n // handled via setSoftDrop\n break;\n case \"ArrowUp\":\n game.rotateCW();\n break;\n case \"KeyZ\":\n case \"ControlLeft\":\n case \"ControlRight\":\n game.rotateCCW();\n break;\n case \"Space\":\n game.hardDrop();\n break;\n case \"KeyP\":\n case \"Escape\":\n game.togglePause();\n break;\n case \"KeyR\":\n if (game.state.gameOver) {\n game.restart();\n }\n break;\n }\n }\n\n function startAutoRepeat(key: string): void {\n // Only auto-repeat movement keys\n if (key !== \"ArrowLeft\" && key !== \"ArrowRight\") return;\n\n const delay = setTimeout(() => {\n const interval = setInterval(() => {\n executeAction(key);\n }, DAS_RATE);\n const entry = keyTimers.get(key);\n if (entry) entry.interval = interval;\n }, DAS_DELAY);\n\n keyTimers.set(key, { delay, interval: 0 as unknown as ReturnType<typeof setInterval> });\n }\n\n function stopAutoRepeat(key: string): void {\n const entry = keyTimers.get(key);\n if (entry) {\n clearTimeout(entry.delay);\n clearInterval(entry.interval);\n keyTimers.delete(key);\n }\n }\n\n document.addEventListener(\"keydown\", (e: KeyboardEvent) => {\n // Prevent default for game keys to avoid scrolling\n const gameKeys = [\n \"ArrowLeft\", \"ArrowRight\", \"ArrowUp\", \"ArrowDown\", \"Space\",\n \"KeyZ\", \"KeyP\", \"KeyR\", \"Escape\",\n ];\n\n const key = e.code;\n if (gameKeys.includes(key)) {\n e.preventDefault();\n }\n\n if (heldKeys.has(key)) return; // ignore key repeat\n heldKeys.add(key);\n\n if (key === \"ArrowDown\") {\n game.setSoftDrop(true);\n }\n\n executeAction(key);\n startAutoRepeat(key);\n });\n\n document.addEventListener(\"keyup\", (e: KeyboardEvent) => {\n const key = e.code;\n heldKeys.delete(key);\n stopAutoRepeat(key);\n\n if (key === \"ArrowDown\") {\n game.setSoftDrop(false);\n }\n });\n\n // Lose focus \u2192 release all keys\n window.addEventListener(\"blur\", () => {\n heldKeys.clear();\n keyTimers.forEach((entry) => {\n clearTimeout(entry.delay);\n clearInterval(entry.interval);\n });\n keyTimers.clear();\n game.setSoftDrop(false);\n });\n\n /* \u2500\u2500 Game loop \u2500\u2500 */\n function loop(timestamp: number): void {\n game.update(timestamp);\n renderer.draw(game.state, game.getGhostRow());\n requestAnimationFrame(loop);\n }\n\n requestAnimationFrame(loop);\n}\n\n// Start immediately when DOM is ready\nif (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", main);\n} else {\n main();\n}\n"], + "mappings": "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", + "names": [] +} diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run1/dist/tetris.js @@ -0,0 +1,613 @@ +"use strict"; +// ============================================================================= +// Tetris – TypeScript implementation +// ============================================================================= +// ─── Constants ──────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell on the main board +const PREV_BLOCK = 24; // px per cell in the preview window +const PREV_GRID = 4; // preview area is 4 × 4 cells +/** Colour for each piece type (index = type 1–7). */ +const COLORS = [ + '', // 0 – empty + '#00f0f0', // 1 – I (cyan) + '#f0f000', // 2 – O (yellow) + '#a000f0', // 3 – T (purple) + '#00f000', // 4 – S (green) + '#f00000', // 5 – Z (red) + '#1010f0', // 6 – J (blue) + '#f0a000', // 7 – L (orange) +]; +/** + * Base shapes for types 1–7 (index = type − 1). + * All cells use value 1; the piece type is tracked separately. + */ +const BASE_SHAPES = [ + // 1 – I + [[0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0]], + // 2 – O + [[1, 1], + [1, 1]], + // 3 – T + [[0, 1, 0], + [1, 1, 1], + [0, 0, 0]], + // 4 – S + [[0, 1, 1], + [1, 1, 0], + [0, 0, 0]], + // 5 – Z + [[1, 1, 0], + [0, 1, 1], + [0, 0, 0]], + // 6 – J + [[1, 0, 0], + [1, 1, 1], + [0, 0, 0]], + // 7 – L + [[0, 0, 1], + [1, 1, 1], + [0, 0, 0]], +]; +/** Points awarded for clearing 1–4 lines simultaneously (×level multiplier). */ +const LINE_POINTS = [0, 100, 300, 500, 800]; +// DAS (Delayed Auto-Shift) timings +const DAS_DELAY = 167; // ms before auto-repeat starts +const DAS_SPEED = 33; // ms between auto-repeat ticks +const SOFT_INTERVAL = 50; // ms between soft-drop ticks +/** Normal gravity interval in ms for a given level. */ +function dropInterval(level) { + return Math.max(50, 1000 - (level - 1) * 67); +} +function rotateCW(m) { + const R = m.length, C = m[0].length; + const out = Array.from({ length: C }, () => new Array(R).fill(0)); + for (let r = 0; r < R; r++) + for (let c = 0; c < C; c++) + out[c][R - 1 - r] = m[r][c]; + return out; +} +function rotateCCW(m) { + return rotateCW(rotateCW(rotateCW(m))); +} +function cloneMatrix(m) { + return m.map(row => row.slice()); +} +// ─── Game ───────────────────────────────────────────────────────────────────── +class TetrisGame { + // ── constructor ───────────────────────────────────────────────────────────── + constructor(boardCanvas, previewCanvas, holdCanvas) { + // state + this.board = []; + this.held = null; + this.bag = []; + this.canHold = true; + this.score = 0; + this.highScore = 0; + this.level = 1; + this.totalLines = 0; + this.paused = false; + this.gameOver = false; + // timing + this.lastTs = 0; + this.dropAcc = 0; + // lock-delay (gives a short grace window after landing) + this.onGround = false; + this.lockTimer = 0; + this.lockMoves = 0; + this.LOCK_DELAY = 500; // ms + this.LOCK_MOVES = 15; // max resets + // input + this.leftHeld = false; + this.rightHeld = false; + this.downHeld = false; + this.dasTimer = 0; + this.dasAcc = 0; + // line-clear flash animation + this.flashRows = []; + this.flashTimer = 0; + this.FLASH_DURATION = 120; // ms + this.boardCtx = boardCanvas.getContext('2d'); + this.previewCtx = previewCanvas.getContext('2d'); + this.holdCtx = holdCanvas.getContext('2d'); + this.elScore = document.getElementById('score'); + this.elHiScore = document.getElementById('hi-score'); + this.elLevel = document.getElementById('level'); + this.elLines = document.getElementById('lines'); + this.highScore = parseInt(localStorage.getItem('tetrisHiScore') ?? '0', 10); + this.elHiScore.textContent = this.highScore.toLocaleString(); + this.resetGame(); + this.setupKeys(); + requestAnimationFrame(ts => this.loop(ts)); + } + // ── initialisation ────────────────────────────────────────────────────────── + resetGame() { + this.board = Array.from({ length: ROWS }, () => new Array(COLS).fill(0)); + this.bag = []; + this.held = null; + this.canHold = true; + this.score = 0; + this.level = 1; + this.totalLines = 0; + this.paused = false; + this.gameOver = false; + this.dropAcc = 0; + this.lastTs = 0; + this.onGround = false; + this.lockTimer = 0; + this.lockMoves = 0; + this.leftHeld = false; + this.rightHeld = false; + this.downHeld = false; + this.dasTimer = 0; + this.dasAcc = 0; + this.flashRows = []; + this.flashTimer = 0; + this.next = this.newPiece(); + this.current = this.spawn(); + this.updateUI(); + this.renderHold(); + } + // ── 7-bag randomiser ──────────────────────────────────────────────────────── + refillBag() { + this.bag = [1, 2, 3, 4, 5, 6, 7]; + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + newPiece() { + if (this.bag.length === 0) + this.refillBag(); + const type = this.bag.pop(); + const shape = cloneMatrix(BASE_SHAPES[type - 1]); + return { shape, type, x: 0, y: 0 }; + } + spawn() { + const p = this.next; + this.next = this.newPiece(); + p.x = Math.floor((COLS - p.shape[0].length) / 2); + p.y = 0; + // Allow I-piece to enter from row -1 so spawn looks natural + if (!this.valid(p.shape, p.x, p.y) && !this.valid(p.shape, p.x, p.y - 1)) { + this.triggerGameOver(); + } + this.renderPreview(); + this.canHold = true; + return p; + } + // ── collision ──────────────────────────────────────────────────────────────── + valid(shape, x, y) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = x + c, ny = y + r; + if (nx < 0 || nx >= COLS) + return false; + if (ny >= ROWS) + return false; + if (ny >= 0 && this.board[ny][nx]) + return false; + } + } + return true; + } + isOnGround() { + return !this.valid(this.current.shape, this.current.x, this.current.y + 1); + } + // ── movement ───────────────────────────────────────────────────────────────── + move(dx, dy) { + if (this.valid(this.current.shape, this.current.x + dx, this.current.y + dy)) { + this.current.x += dx; + this.current.y += dy; + if (dy === 0) { + // horizontal move resets lock-delay + if (this.onGround && this.lockMoves < this.LOCK_MOVES) { + this.lockTimer = 0; + this.lockMoves++; + } + } + return true; + } + return false; + } + rotate(cw) { + const rotated = cw ? rotateCW(this.current.shape) : rotateCCW(this.current.shape); + // Wall-kick offsets: try 0, −1, +1, −2, +2 horizontal; also try −1 vertical for I + const kicks = [0, -1, 1, -2, 2]; + for (const kick of kicks) { + if (this.valid(rotated, this.current.x + kick, this.current.y)) { + this.current.shape = rotated; + this.current.x += kick; + if (this.onGround && this.lockMoves < this.LOCK_MOVES) { + this.lockTimer = 0; + this.lockMoves++; + } + return; + } + } + } + hardDrop() { + let dropped = 0; + while (this.move(0, 1)) + dropped++; + this.score += dropped * 2; + this.dropAcc = 0; + this.lockTimer = this.LOCK_DELAY; // force immediate lock + this.lock(); + } + holdPiece() { + if (!this.canHold) + return; + this.canHold = false; + if (this.held === null) { + this.held = { ...this.current, shape: cloneMatrix(BASE_SHAPES[this.current.type - 1]) }; + this.current = this.spawn(); + } + else { + const prev = this.held; + this.held = { ...this.current, shape: cloneMatrix(BASE_SHAPES[this.current.type - 1]) }; + prev.x = Math.floor((COLS - prev.shape[0].length) / 2); + prev.y = 0; + this.current = prev; + } + this.onGround = false; + this.lockTimer = 0; + this.lockMoves = 0; + this.dropAcc = 0; + this.renderHold(); + } + // ── lock & clear ───────────────────────────────────────────────────────────── + lock() { + const { shape, type, x, y } = this.current; + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c] && y + r >= 0) + this.board[y + r][x + c] = type; + this.onGround = false; + this.lockTimer = 0; + this.lockMoves = 0; + const fullRows = this.findFullRows(); + if (fullRows.length > 0) { + this.flashRows = fullRows; + this.flashTimer = 0; + // scoring happens after flash ends (see processFlash) + } + else { + this.current = this.spawn(); + } + this.updateUI(); + } + findFullRows() { + const full = []; + for (let r = 0; r < ROWS; r++) + if (this.board[r].every(v => v !== 0)) + full.push(r); + return full; + } + processFlash(dt) { + if (this.flashRows.length === 0) + return false; + this.flashTimer += dt; + if (this.flashTimer < this.FLASH_DURATION) + return true; // still flashing + // Flash done – commit the clears + const count = this.flashRows.length; + for (const r of [...this.flashRows].sort((a, b) => b - a)) { + this.board.splice(r, 1); + this.board.unshift(new Array(COLS).fill(0)); + } + this.flashRows = []; + this.flashTimer = 0; + this.score += LINE_POINTS[count] * this.level; + this.totalLines += count; + this.level = Math.floor(this.totalLines / 10) + 1; + this.updateUI(); + this.current = this.spawn(); + return false; + } + // ── ghost piece ────────────────────────────────────────────────────────────── + ghostY() { + let gy = this.current.y; + while (this.valid(this.current.shape, this.current.x, gy + 1)) + gy++; + return gy; + } + // ── game over ──────────────────────────────────────────────────────────────── + triggerGameOver() { + this.gameOver = true; + if (this.score > this.highScore) { + this.highScore = this.score; + localStorage.setItem('tetrisHiScore', String(this.highScore)); + } + this.updateUI(); + } + // ── input ──────────────────────────────────────────────────────────────────── + setupKeys() { + window.addEventListener('keydown', e => this.onKeyDown(e)); + window.addEventListener('keyup', e => this.onKeyUp(e)); + } + onKeyDown(e) { + if (e.code === 'KeyR') { + this.resetGame(); + return; + } + if (e.code === 'KeyP' || e.code === 'Escape') { + if (!this.gameOver) + this.paused = !this.paused; + return; + } + if (this.gameOver || this.paused || this.flashRows.length > 0) + return; + switch (e.code) { + case 'ArrowLeft': + e.preventDefault(); + if (!this.leftHeld) { + this.move(-1, 0); + this.leftHeld = true; + this.rightHeld = false; + this.dasTimer = 0; + this.dasAcc = 0; + } + break; + case 'ArrowRight': + e.preventDefault(); + if (!this.rightHeld) { + this.move(1, 0); + this.rightHeld = true; + this.leftHeld = false; + this.dasTimer = 0; + this.dasAcc = 0; + } + break; + case 'ArrowDown': + e.preventDefault(); + this.downHeld = true; + break; + case 'ArrowUp': + e.preventDefault(); + this.rotate(true); + break; + case 'KeyX': + e.preventDefault(); + this.rotate(true); + break; + case 'KeyZ': + e.preventDefault(); + this.rotate(false); + break; + case 'Space': + e.preventDefault(); + this.hardDrop(); + break; + case 'ShiftLeft': + case 'ShiftRight': + case 'KeyC': + e.preventDefault(); + this.holdPiece(); + break; + } + } + onKeyUp(e) { + switch (e.code) { + case 'ArrowLeft': + this.leftHeld = false; + if (!this.rightHeld) { + this.dasTimer = 0; + this.dasAcc = 0; + } + break; + case 'ArrowRight': + this.rightHeld = false; + if (!this.leftHeld) { + this.dasTimer = 0; + this.dasAcc = 0; + } + break; + case 'ArrowDown': + this.downHeld = false; + break; + } + } + // ── main loop ──────────────────────────────────────────────────────────────── + loop(ts) { + const dt = Math.min(ts - this.lastTs, 100); // cap to avoid spiral on tab-switch + this.lastTs = ts; + if (!this.gameOver && !this.paused) { + // line-clear flash takes priority – freeze everything else + if (!this.processFlash(dt)) { + this.processDAS(dt); + this.processGravity(dt); + } + } + this.renderBoard(); + requestAnimationFrame(ts2 => this.loop(ts2)); + } + processDAS(dt) { + if (!this.leftHeld && !this.rightHeld) + return; + this.dasTimer += dt; + if (this.dasTimer < DAS_DELAY) + return; + this.dasAcc += dt; + while (this.dasAcc >= DAS_SPEED) { + if (this.leftHeld) + this.move(-1, 0); + if (this.rightHeld) + this.move(1, 0); + this.dasAcc -= DAS_SPEED; + } + } + processGravity(dt) { + const interval = this.downHeld + ? Math.min(dropInterval(this.level), SOFT_INTERVAL) + : dropInterval(this.level); + const landed = this.isOnGround(); + if (!landed) { + // Normal / soft-drop gravity + this.onGround = false; + this.lockTimer = 0; + this.lockMoves = 0; + this.dropAcc += dt; + while (this.dropAcc >= interval) { + this.dropAcc -= interval; + if (!this.move(0, 1)) + break; + if (this.downHeld) { + this.score++; + } + } + } + else { + // Piece is on the ground – run lock-delay countdown + if (!this.onGround) { + this.onGround = true; + this.lockTimer = 0; + } + this.lockTimer += dt; + if (this.lockTimer >= this.LOCK_DELAY || this.lockMoves >= this.LOCK_MOVES) { + this.lock(); + } + } + } + // ── UI ─────────────────────────────────────────────────────────────────────── + updateUI() { + this.elScore.textContent = this.score.toLocaleString(); + this.elHiScore.textContent = this.highScore.toLocaleString(); + this.elLevel.textContent = String(this.level); + this.elLines.textContent = String(this.totalLines); + } + // ── rendering ──────────────────────────────────────────────────────────────── + renderBoard() { + const ctx = this.boardCtx; + const W = COLS * BLOCK; + const H = ROWS * BLOCK; + // Background + ctx.fillStyle = '#111827'; + ctx.fillRect(0, 0, W, H); + // Subtle grid + ctx.strokeStyle = 'rgba(255,255,255,0.045)'; + ctx.lineWidth = 1; + for (let c = 1; c < COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, H); + ctx.stroke(); + } + for (let r = 1; r < ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(W, r * BLOCK); + ctx.stroke(); + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + if (this.flashRows.includes(r)) + continue; // drawn separately below + for (let c = 0; c < COLS; c++) + if (this.board[r][c]) + this.drawBlock(ctx, c, r, this.board[r][c], BLOCK, 1); + } + // Flash animation for clearing lines + if (this.flashRows.length > 0) { + const progress = this.flashTimer / this.FLASH_DURATION; + const flashAlpha = 0.5 + 0.5 * Math.sin(progress * Math.PI * 3); + for (const r of this.flashRows) { + ctx.fillStyle = `rgba(255,255,255,${flashAlpha.toFixed(2)})`; + ctx.fillRect(0, r * BLOCK, W, BLOCK); + } + } + if (!this.gameOver && this.flashRows.length === 0) { + // Ghost piece + const gy = this.ghostY(); + if (gy > this.current.y) { + for (let r = 0; r < this.current.shape.length; r++) + for (let c = 0; c < this.current.shape[r].length; c++) + if (this.current.shape[r][c]) + this.drawBlock(ctx, this.current.x + c, gy + r, this.current.type, BLOCK, 0.18); + } + // Active piece + for (let r = 0; r < this.current.shape.length; r++) + for (let c = 0; c < this.current.shape[r].length; c++) + if (this.current.shape[r][c]) + this.drawBlock(ctx, this.current.x + c, this.current.y + r, this.current.type, BLOCK, 1); + } + // Pause overlay + if (this.paused) { + ctx.fillStyle = 'rgba(0,0,0,0.65)'; + ctx.fillRect(0, 0, W, H); + this.overlayText(ctx, W, H, 'PAUSED', '#ffffff', 30, 'P or Esc to resume', '#9ca3af', 14); + } + // Game-over overlay + if (this.gameOver) { + ctx.fillStyle = 'rgba(0,0,0,0.78)'; + ctx.fillRect(0, 0, W, H); + this.overlayText(ctx, W, H, 'GAME OVER', '#f87171', 30, `Score: ${this.score.toLocaleString()}\nR to restart`, '#e5e7eb', 15); + } + } + overlayText(ctx, W, H, title, titleCol, titleSz, sub, subCol, subSz) { + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = titleCol; + ctx.font = `bold ${titleSz}px monospace`; + ctx.fillText(title, W / 2, H / 2 - 24); + ctx.fillStyle = subCol; + ctx.font = `${subSz}px monospace`; + const lines = sub.split('\n'); + lines.forEach((line, i) => { + ctx.fillText(line, W / 2, H / 2 + 14 + i * (subSz + 6)); + }); + } + renderPreview() { + this.renderPieceCanvas(this.previewCtx, this.next, PREV_GRID * PREV_BLOCK, PREV_GRID * PREV_BLOCK, PREV_BLOCK); + } + renderHold() { + this.renderPieceCanvas(this.holdCtx, this.held, PREV_GRID * PREV_BLOCK, PREV_GRID * PREV_BLOCK, PREV_BLOCK); + } + renderPieceCanvas(ctx, piece, W, H, bs) { + ctx.fillStyle = '#111827'; + ctx.fillRect(0, 0, W, H); + if (!piece) + return; + const { shape, type } = piece; + const offC = Math.round((PREV_GRID - shape[0].length) / 2); + const offR = Math.round((PREV_GRID - shape.length) / 2); + for (let r = 0; r < shape.length; r++) + for (let c = 0; c < shape[r].length; c++) + if (shape[r][c]) + this.drawBlock(ctx, offC + c, offR + r, type, bs, 1); + } + drawBlock(ctx, col, row, type, size, alpha) { + const x = col * size; + const y = row * size; + const pad = 1; + const s = size - pad * 2; + ctx.globalAlpha = alpha; + // Main face + ctx.fillStyle = COLORS[type]; + ctx.fillRect(x + pad, y + pad, s, s); + // Top-left bevel (lighter) + ctx.fillStyle = 'rgba(255,255,255,0.32)'; + ctx.fillRect(x + pad, y + pad, s, 4); + ctx.fillRect(x + pad, y + pad, 4, s); + // Bottom-right bevel (darker) + ctx.fillStyle = 'rgba(0,0,0,0.28)'; + ctx.fillRect(x + pad, y + size - pad - 4, s, 4); + ctx.fillRect(x + size - pad - 4, y + pad, 4, s); + ctx.globalAlpha = 1; + } +} +// ============================================================================= +// Bootstrap +// ============================================================================= +document.addEventListener('DOMContentLoaded', () => { + const board = document.getElementById('board'); + const preview = document.getElementById('preview'); + const hold = document.getElementById('hold'); + new TetrisGame(board, preview, hold); +}); diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run2/dist/tetris.js @@ -0,0 +1,496 @@ +"use strict"; +// ─── Constants ─────────────────────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // pixels per cell on main board +const PREVIEW_BLOCK = 24; // pixels per cell on preview canvas +// Points awarded per number of lines cleared at once +const LINE_POINTS = [0, 100, 300, 500, 800]; +// Drop interval in ms per level (level 1-15, then clamp) +function dropInterval(level) { + return Math.max(100, 800 - (level - 1) * 55); +} +// Each piece defined with all 4 rotations (pre-computed for clarity) +const TETROMINOES = [ + // I + { + color: "#00f0f0", + shapes: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + }, + // O + { + color: "#f0f000", + shapes: [ + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + [[1, 1], [1, 1]], + ], + }, + // T + { + color: "#a000f0", + shapes: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + }, + // S + { + color: "#00f000", + shapes: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + }, + // Z + { + color: "#f00000", + shapes: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + }, + // J + { + color: "#0000f0", + shapes: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + }, + // L + { + color: "#f0a000", + shapes: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], + }, +]; +function pieceShape(p) { + return TETROMINOES[p.typeIndex].shapes[p.rotation]; +} +function pieceColor(p) { + return TETROMINOES[p.typeIndex].color; +} +function randomPiece() { + const typeIndex = Math.floor(Math.random() * TETROMINOES.length); + const shape = TETROMINOES[typeIndex].shapes[0]; + const x = Math.floor((COLS - shape[0].length) / 2); + return { typeIndex, rotation: 0, x, y: 0 }; +} +function createBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function isValid(board, p, dx = 0, dy = 0, dr = 0) { + const rotation = ((p.rotation + dr) % 4 + 4) % 4; + const shape = TETROMINOES[p.typeIndex].shapes[rotation]; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const nx = p.x + c + dx; + const ny = p.y + r + dy; + if (nx < 0 || nx >= COLS || ny >= ROWS) + return false; + if (ny >= 0 && board[ny][nx]) + return false; + } + } + return true; +} +function lockPiece(board, p) { + const shape = pieceShape(p); + const color = pieceColor(p); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const ny = p.y + r; + const nx = p.x + c; + if (ny >= 0) + board[ny][nx] = color; + } + } +} +// Returns number of lines cleared +function clearLines(board) { + let cleared = 0; + for (let r = ROWS - 1; r >= 0; r--) { + if (board[r].every(cell => cell !== null)) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + cleared++; + r++; // re-check the same row index after splice + } + } + return cleared; +} +// ─── Ghost Piece ───────────────────────────────────────────────────────────── +function ghostY(board, p) { + let dy = 0; + while (isValid(board, p, 0, dy + 1)) + dy++; + return p.y + dy; +} +// ─── Rendering ─────────────────────────────────────────────────────────────── +function drawBlock(ctx, x, y, color, size, alpha = 1) { + ctx.globalAlpha = alpha; + ctx.fillStyle = color; + ctx.fillRect(x * size + 1, y * size + 1, size - 2, size - 2); + // Highlight + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fillRect(x * size + 1, y * size + 1, size - 2, 4); + ctx.fillRect(x * size + 1, y * size + 1, 4, size - 2); + // Shadow + ctx.fillStyle = "rgba(0,0,0,0.3)"; + ctx.fillRect(x * size + 1, y * size + size - 5, size - 2, 4); + ctx.fillRect(x * size + size - 5, y * size + 1, 4, size - 2); + ctx.globalAlpha = 1; +} +function renderBoard(ctx, board) { + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (board[r][c]) { + drawBlock(ctx, c, r, board[r][c], BLOCK); + } + } + } +} +function renderPiece(ctx, p, offsetY = 0, alpha = 1, size = BLOCK) { + const shape = pieceShape(p); + const color = pieceColor(p); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + drawBlock(ctx, p.x + c, p.y + r + offsetY, color, size, alpha); + } + } +} +function renderGhost(ctx, board, p) { + const gy = ghostY(board, p); + const ghost = Object.assign(Object.assign({}, p), { y: gy }); + const shape = pieceShape(ghost); + const color = pieceColor(ghost); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const px = (ghost.x + c) * BLOCK + 1; + const py = (ghost.y + r) * BLOCK + 1; + ctx.strokeStyle = color; + ctx.lineWidth = 2; + ctx.strokeRect(px, py, BLOCK - 2, BLOCK - 2); + } + } +} +function renderPreview(ctx, p) { + ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); + const shape = pieceShape(p); + const color = pieceColor(p); + const cols = shape[0].length; + const rows = shape.length; + const offsetX = Math.floor((ctx.canvas.width / PREVIEW_BLOCK - cols) / 2); + const offsetY = Math.floor((ctx.canvas.height / PREVIEW_BLOCK - rows) / 2); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (!shape[r][c]) + continue; + drawBlock(ctx, offsetX + c, offsetY + r, color, PREVIEW_BLOCK); + } + } +} +function calcLevel(lines) { + return Math.floor(lines / 10) + 1; +} +function newGame() { + return { + board: createBoard(), + current: randomPiece(), + next: randomPiece(), + score: 0, + lines: 0, + level: 1, + phase: "playing", + lastDrop: performance.now(), + }; +} +const KEY_INITIAL_DELAY = 170; +const KEY_REPEAT_INTERVAL = 50; +// ─── Main ───────────────────────────────────────────────────────────────────── +(function main() { + // ── DOM Setup ── + const canvas = document.getElementById("board"); + const previewCanvas = document.getElementById("preview"); + const scoreEl = document.getElementById("score-value"); + const linesEl = document.getElementById("lines-value"); + const levelEl = document.getElementById("level-value"); + const overlay = document.getElementById("overlay"); + const overlayTitle = document.getElementById("overlay-title"); + const overlayMsg = document.getElementById("overlay-msg"); + const startBtn = document.getElementById("start-btn"); + canvas.width = COLS * BLOCK; + canvas.height = ROWS * BLOCK; + previewCanvas.width = 6 * PREVIEW_BLOCK; + previewCanvas.height = 5 * PREVIEW_BLOCK; + const ctx = canvas.getContext("2d"); + const previewCtx = previewCanvas.getContext("2d"); + let state = newGame(); + let rafId = null; + let animating = false; + // ── Key repeat helpers ── + const leftRepeat = { active: false, initialDelay: null, repeatInterval: null }; + const rightRepeat = { active: false, initialDelay: null, repeatInterval: null }; + const downRepeat = { active: false, initialDelay: null, repeatInterval: null }; + function clearRepeat(rep) { + rep.active = false; + if (rep.initialDelay !== null) { + clearTimeout(rep.initialDelay); + rep.initialDelay = null; + } + if (rep.repeatInterval !== null) { + clearInterval(rep.repeatInterval); + rep.repeatInterval = null; + } + } + function startRepeat(rep, action) { + clearRepeat(rep); + rep.active = true; + action(); + rep.initialDelay = setTimeout(() => { + if (!rep.active) + return; + rep.repeatInterval = setInterval(() => { + if (!rep.active) { + clearRepeat(rep); + return; + } + action(); + }, KEY_REPEAT_INTERVAL); + }, KEY_INITIAL_DELAY); + } + // ── Game actions ── + function tryMove(dx, dy) { + if (state.phase !== "playing") + return false; + if (isValid(state.board, state.current, dx, dy)) { + state.current.x += dx; + state.current.y += dy; + return true; + } + return false; + } + function tryRotate(dr) { + if (state.phase !== "playing") + return; + const rotation = ((state.current.rotation + dr) % 4 + 4) % 4; + // Wall kicks: try offsets in order + const kicks = [0, -1, 1, -2, 2]; + for (const kx of kicks) { + if (isValid(state.board, state.current, kx, 0, dr)) { + state.current.x += kx; + state.current.rotation = rotation; + return; + } + } + } + function hardDrop() { + if (state.phase !== "playing") + return; + const gy = ghostY(state.board, state.current); + const dropped = gy - state.current.y; + state.current.y = gy; + state.score += dropped * 2; + lockAndSpawn(); + } + function softDrop() { + if (!tryMove(0, 1)) { + lockAndSpawn(); + } + else { + state.score += 1; + } + } + function lockAndSpawn() { + lockPiece(state.board, state.current); + const cleared = clearLines(state.board); + state.lines += cleared; + state.level = calcLevel(state.lines); + state.score += LINE_POINTS[cleared] * state.level; + // Spawn next + state.current = state.next; + state.next = randomPiece(); + state.lastDrop = performance.now(); + // Check game over + if (!isValid(state.board, state.current)) { + state.phase = "gameover"; + showOverlay("GAME OVER", `Final score: ${state.score}`, "Play Again"); + } + } + // ── Render ── + function render(now) { + // Clear board canvas + ctx.clearRect(0, 0, canvas.width, canvas.height); + // Grid lines + ctx.strokeStyle = "rgba(255,255,255,0.04)"; + ctx.lineWidth = 1; + for (let r = 0; r <= ROWS; r++) { + ctx.beginPath(); + ctx.moveTo(0, r * BLOCK); + ctx.lineTo(COLS * BLOCK, r * BLOCK); + ctx.stroke(); + } + for (let c = 0; c <= COLS; c++) { + ctx.beginPath(); + ctx.moveTo(c * BLOCK, 0); + ctx.lineTo(c * BLOCK, ROWS * BLOCK); + ctx.stroke(); + } + renderBoard(ctx, state.board); + if (state.phase === "playing" || state.phase === "paused") { + renderGhost(ctx, state.board, state.current); + renderPiece(ctx, state.current); + } + // HUD + scoreEl.textContent = state.score.toString(); + linesEl.textContent = state.lines.toString(); + levelEl.textContent = state.level.toString(); + // Preview + renderPreview(previewCtx, state.next); + } + // ── Game loop ── + function loop(now) { + if (!animating) + return; + if (state.phase === "playing") { + const interval = dropInterval(state.level); + if (now - state.lastDrop >= interval) { + state.lastDrop = now; + if (!tryMove(0, 1)) { + lockAndSpawn(); + } + } + } + render(now); + rafId = requestAnimationFrame(loop); + } + function startLoop() { + if (animating) + return; + animating = true; + rafId = requestAnimationFrame(loop); + } + function stopLoop() { + animating = false; + if (rafId !== null) { + cancelAnimationFrame(rafId); + rafId = null; + } + } + // ── Overlay ── + function showOverlay(title, msg, btnLabel) { + overlayTitle.textContent = title; + overlayMsg.textContent = msg; + startBtn.textContent = btnLabel; + overlay.hidden = false; + startBtn.focus(); + } + function hideOverlay() { + overlay.hidden = true; + canvas.focus(); + } + // ── Start / Restart ── + function startGame() { + stopLoop(); + state = newGame(); + hideOverlay(); + startLoop(); + } + startBtn.addEventListener("click", () => startGame()); + // Initial overlay + showOverlay("TETRIS", "Use arrow keys to move and rotate", "Start Game"); + // Still render a blank board behind the overlay + startLoop(); + // ── Keyboard ── + document.addEventListener("keydown", (e) => { + // Don't intercept when overlay has focus and Enter/Space on button + if (!overlay.hidden && e.key === "Enter") { + startGame(); + return; + } + if (e.key === "p" || e.key === "P" || e.key === "Escape") { + if (state.phase === "playing") { + state.phase = "paused"; + showOverlay("PAUSED", "Press P or Esc to resume", "Resume"); + } + else if (state.phase === "paused") { + state.phase = "playing"; + state.lastDrop = performance.now(); + hideOverlay(); + } + return; + } + if (state.phase !== "playing") + return; + switch (e.key) { + case "ArrowLeft": + e.preventDefault(); + if (!leftRepeat.active) + startRepeat(leftRepeat, () => tryMove(-1, 0)); + break; + case "ArrowRight": + e.preventDefault(); + if (!rightRepeat.active) + startRepeat(rightRepeat, () => tryMove(1, 0)); + break; + case "ArrowDown": + e.preventDefault(); + if (!downRepeat.active) + startRepeat(downRepeat, () => softDrop()); + break; + case "ArrowUp": + e.preventDefault(); + tryRotate(1); + break; + case "z": + case "Z": + e.preventDefault(); + tryRotate(-1); + break; + case " ": + e.preventDefault(); + hardDrop(); + break; + } + }); + document.addEventListener("keyup", (e) => { + switch (e.key) { + case "ArrowLeft": + clearRepeat(leftRepeat); + break; + case "ArrowRight": + clearRepeat(rightRepeat); + break; + case "ArrowDown": + clearRepeat(downRepeat); + break; + } + }); +})(); diff --git a/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js b/artifacts/tetris_context_file=provided_effort=high_human_language=en_language=typescript_linter=on_max_budget=low_model=sonnet_playwright=on_prompt_style=simple_sub_agents=on_tool_edit=on_tool_glob=on_tool_grep=on_tool_read=on_tool_write=on_web_search=on_run3/dist/tetris.js @@ -0,0 +1,658 @@ +"use strict"; +// ============================================================ +// Tetris – complete implementation +// Board: 10 × 20 | SRS rotation + wall-kicks +// Ghost piece, Hold, Next-preview, Levels, Scoring +// ============================================================ +// ─── Constants ─────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const BLOCK = 30; // px per cell on main board +const PREVIEW_BLK = 22; // px per cell in side panels +// Points awarded per simultaneous line clears (×level) +const LINE_POINTS = [0, 100, 300, 500, 800]; +// Speed table: ms between automatic drops per level (1-indexed) +function dropInterval(level) { + return Math.max(80, 1000 - (level - 1) * 90); +} +// Each piece has 4 rotations stored as row arrays of 0/1 +// Rotations go: 0=spawn, 1=clockwise, 2=180, 3=counter-clockwise +const SHAPES = { + I: [ + [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], + [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]], + ], + O: [ + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + ], + T: [ + [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 1, 0]], + [[0, 1, 0], [1, 1, 0], [0, 1, 0]], + ], + S: [ + [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + [[0, 1, 0], [0, 1, 1], [0, 0, 1]], + [[0, 0, 0], [0, 1, 1], [1, 1, 0]], + [[1, 0, 0], [1, 1, 0], [0, 1, 0]], + ], + Z: [ + [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + [[0, 0, 1], [0, 1, 1], [0, 1, 0]], + [[0, 0, 0], [1, 1, 0], [0, 1, 1]], + [[0, 1, 0], [1, 1, 0], [1, 0, 0]], + ], + J: [ + [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + [[0, 1, 1], [0, 1, 0], [0, 1, 0]], + [[0, 0, 0], [1, 1, 1], [0, 0, 1]], + [[0, 1, 0], [0, 1, 0], [1, 1, 0]], + ], + L: [ + [[0, 0, 1], [1, 1, 1], [0, 0, 0]], + [[0, 1, 0], [0, 1, 0], [0, 1, 1]], + [[0, 0, 0], [1, 1, 1], [1, 0, 0]], + [[1, 1, 0], [0, 1, 0], [0, 1, 0]], + ], +}; +const COLORS = { + I: '#00CFCF', + O: '#CFCF00', + T: '#9F00CF', + S: '#00CF00', + Z: '#CF2020', + J: '#2020CF', + L: '#CF7F00', +}; +// SRS wall-kick offsets: [fromRotation][kickIndex] = [dx, dy] +// Separate tables for I vs everything else +const KICKS_JLSTZ = { + '0->1': [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + '1->0': [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + '1->2': [[0, 0], [1, 0], [1, -1], [0, 2], [1, 2]], + '2->1': [[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]], + '2->3': [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], + '3->2': [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + '3->0': [[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]], + '0->3': [[0, 0], [1, 0], [1, 1], [0, -2], [1, -2]], +}; +const KICKS_I = { + '0->1': [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + '1->0': [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + '1->2': [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], + '2->1': [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + '2->3': [[0, 0], [2, 0], [-1, 0], [2, 1], [-1, -2]], + '3->2': [[0, 0], [-2, 0], [1, 0], [-2, -1], [1, 2]], + '3->0': [[0, 0], [1, 0], [-2, 0], [1, -2], [-2, 1]], + '0->3': [[0, 0], [-1, 0], [2, 0], [-1, 2], [2, -1]], +}; +// ─── Utility helpers ───────────────────────────────────────── +const ALL_KEYS = ['I', 'O', 'T', 'S', 'Z', 'J', 'L']; +// 7-bag randomiser keeps distribution fair +class Bag { + constructor() { + this.bag = []; + } + next() { + if (this.bag.length === 0) { + this.bag = [...ALL_KEYS].sort(() => Math.random() - 0.5); + } + return this.bag.pop(); + } +} +function emptyBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +function getShape(p) { + return SHAPES[p.key][p.rot]; +} +/** All filled [row, col] cells of a piece */ +function cells(p) { + const shape = getShape(p); + const result = []; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) + result.push([p.y + r, p.x + c]); + } + } + return result; +} +function isValid(board, p) { + for (const [r, c] of cells(p)) { + if (c < 0 || c >= COLS || r >= ROWS) + return false; + if (r >= 0 && board[r][c] !== null) + return false; + } + return true; +} +function spawnPiece(key) { + // Spawn centred, 1 row above visible area + return { key, rot: 0, x: Math.floor((COLS - 4) / 2), y: -1 }; +} +// ─── Tetris Engine ─────────────────────────────────────────── +class TetrisGame { + constructor(renderer) { + this.board = emptyBoard(); + this.current = null; + this.ghost = null; + this.held = null; + this.canHold = true; + this.next = []; // show 3 upcoming + this.bag = new Bag(); + this.score = 0; + this.lines = 0; + this.level = 1; + this.state = 'idle'; + this.dropTimer = 0; + this.lastTime = 0; + this.rafId = 0; + this.lockDelay = 500; // ms before locking after grounding + // ── Locking & line clears ──────────────────────────────── + this.lockDelayClock = 0; + this.renderer = renderer; + this.fillQueue(); + } + fillQueue() { + while (this.next.length < 3) + this.next.push(this.bag.next()); + } + popNext() { + const key = this.next.shift(); + this.next.push(this.bag.next()); + return key; + } + start() { + this.board = emptyBoard(); + this.held = null; + this.canHold = true; + this.score = 0; + this.lines = 0; + this.level = 1; + this.bag = new Bag(); + this.next = []; + this.fillQueue(); + this.state = 'playing'; + this.spawnNext(); + this.lastTime = performance.now(); + cancelAnimationFrame(this.rafId); + this.rafId = requestAnimationFrame(this.loop.bind(this)); + } + spawnNext() { + const key = this.popNext(); + this.current = spawnPiece(key); + this.canHold = true; + this.updateGhost(); + if (!isValid(this.board, this.current)) { + this.gameOver(); + } + } + updateGhost() { + if (!this.current) { + this.ghost = null; + return; + } + let g = Object.assign({}, this.current); + while (isValid(this.board, Object.assign(Object.assign({}, g), { y: g.y + 1 }))) + g = Object.assign(Object.assign({}, g), { y: g.y + 1 }); + this.ghost = g; + } + // ── Piece movement ─────────────────────────────────────── + moveLeft() { this.shift(-1); } + moveRight() { this.shift(1); } + shift(dx) { + if (!this.current || this.state !== 'playing') + return; + const moved = Object.assign(Object.assign({}, this.current), { x: this.current.x + dx }); + if (isValid(this.board, moved)) { + this.current = moved; + this.updateGhost(); + this.resetLockTimer(); + } + } + softDrop() { + if (!this.current || this.state !== 'playing') + return; + const dropped = Object.assign(Object.assign({}, this.current), { y: this.current.y + 1 }); + if (isValid(this.board, dropped)) { + this.current = dropped; + this.updateGhost(); + this.dropTimer = 0; + this.score += 1; + } + else { + this.lockPiece(); + } + } + hardDrop() { + if (!this.current || this.state !== 'playing') + return; + let count = 0; + while (isValid(this.board, Object.assign(Object.assign({}, this.current), { y: this.current.y + 1 }))) { + this.current = Object.assign(Object.assign({}, this.current), { y: this.current.y + 1 }); + count++; + } + this.score += count * 2; + this.lockPiece(); + } + // ── Rotation (SRS) ─────────────────────────────────────── + rotateCW() { this.rotate(1); } + rotateCCW() { this.rotate(-1); } + rotate(dir) { + var _a; + if (!this.current || this.state !== 'playing') + return; + const from = this.current.rot; + const to = ((from + dir) + 4) % 4; + const rotated = Object.assign(Object.assign({}, this.current), { rot: to }); + const table = (this.current.key === 'I') ? KICKS_I : KICKS_JLSTZ; + const key = `${from}->${to}`; + const kicks = (_a = table[key]) !== null && _a !== void 0 ? _a : [[0, 0]]; + for (const [kx, ky] of kicks) { + const candidate = Object.assign(Object.assign({}, rotated), { x: rotated.x + kx, y: rotated.y - ky }); + if (isValid(this.board, candidate)) { + this.current = candidate; + this.updateGhost(); + this.resetLockTimer(); + return; + } + } + } + // ── Hold ───────────────────────────────────────────────── + holdPiece() { + if (!this.current || !this.canHold || this.state !== 'playing') + return; + const key = this.current.key; + if (this.held !== null) { + this.current = spawnPiece(this.held); + } + else { + this.spawnNext(); + } + this.held = key; + this.canHold = false; + this.updateGhost(); + if (!isValid(this.board, this.current)) + this.gameOver(); + } + onGround() { + if (!this.current) + return false; + return !isValid(this.board, Object.assign(Object.assign({}, this.current), { y: this.current.y + 1 })); + } + resetLockTimer() { this.lockDelayClock = 0; } + lockPiece() { + if (!this.current) + return; + for (const [r, c] of cells(this.current)) { + if (r >= 0) + this.board[r][c] = this.current.key; + } + this.current = null; + this.ghost = null; + this.clearLines(); + this.spawnNext(); + this.dropTimer = 0; + this.lockDelayClock = 0; + } + clearLines() { + const full = this.board.reduce((acc, row, i) => { + if (row.every(c => c !== null)) + acc.push(i); + return acc; + }, []); + if (full.length === 0) + return; + for (const r of full) { + this.board.splice(r, 1); + this.board.unshift(Array(COLS).fill(null)); + } + this.lines += full.length; + this.level = Math.floor(this.lines / 10) + 1; + this.score += LINE_POINTS[full.length] * this.level; + this.renderer.flashLines(full.length); + } + // ── Pause / resume ──────────────────────────────────────── + togglePause() { + if (this.state === 'playing') { + this.state = 'paused'; + } + else if (this.state === 'paused') { + this.state = 'playing'; + this.lastTime = performance.now(); + } + } + gameOver() { + this.state = 'gameover'; + } + // ── Main game loop ──────────────────────────────────────── + loop(timestamp) { + const dt = timestamp - this.lastTime; + this.lastTime = timestamp; + if (this.state === 'playing' && this.current) { + const interval = dropInterval(this.level); + this.dropTimer += dt; + if (this.dropTimer >= interval) { + this.dropTimer -= interval; // preserve leftover to avoid drift + const dropped = Object.assign(Object.assign({}, this.current), { y: this.current.y + 1 }); + if (isValid(this.board, dropped)) { + this.current = dropped; + this.updateGhost(); + this.lockDelayClock = 0; // piece moved down – reset lock clock + } + // if already on ground, fall through to lock-delay block below + } + // Lock delay: accumulate time spent touching the floor + if (this.onGround()) { + this.lockDelayClock += dt; + if (this.lockDelayClock >= this.lockDelay) { + this.lockPiece(); + } + } + else { + this.lockDelayClock = 0; + } + } + this.renderer.render(this); + this.rafId = requestAnimationFrame(this.loop.bind(this)); + } +} +// ─── Renderer ──────────────────────────────────────────────── +class TetrisRenderer { + constructor() { + this.flashCount = 0; + this.flashTimer = 0; + this.canvas = document.getElementById('board'); + this.ctx = this.canvas.getContext('2d'); + this.nextCanvas = document.getElementById('next-canvas'); + this.nextCtx = this.nextCanvas.getContext('2d'); + this.holdCanvas = document.getElementById('hold-canvas'); + this.holdCtx = this.holdCanvas.getContext('2d'); + this.scoreEl = document.getElementById('score'); + this.linesEl = document.getElementById('lines'); + this.levelEl = document.getElementById('level'); + this.overlayEl = document.getElementById('overlay'); + } + flashLines(count) { + this.flashCount = count; + this.flashTimer = 300; + } + render(game) { + this.renderBoard(game); + this.renderNext(game.next); + this.renderHold(game.held, game.canHold); + this.scoreEl.textContent = game.score.toLocaleString(); + this.linesEl.textContent = String(game.lines); + this.levelEl.textContent = String(game.level); + this.renderOverlay(game.state); + } + renderBoard(game) { + const { ctx } = this; + ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + // Background grid + ctx.fillStyle = '#111'; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + ctx.strokeStyle = '#222'; + ctx.lineWidth = 0.5; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + ctx.strokeRect(c * BLOCK, r * BLOCK, BLOCK, BLOCK); + } + } + // Locked cells + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const key = game.board[r][c]; + if (key) + this.drawBlock(ctx, c, r, COLORS[key], BLOCK); + } + } + // Ghost piece + if (game.ghost && game.current) { + const color = COLORS[game.ghost.key]; + for (const [r, c] of cells(game.ghost)) { + if (r >= 0) + this.drawGhostBlock(ctx, c, r, color, BLOCK); + } + } + // Active piece + if (game.current) { + const color = COLORS[game.current.key]; + for (const [r, c] of cells(game.current)) { + if (r >= 0) + this.drawBlock(ctx, c, r, color, BLOCK); + } + } + // Flash on line clear + if (this.flashTimer > 0) { + this.flashTimer -= 16; + const alpha = Math.min(0.45, this.flashTimer / 300 * 0.6); + ctx.fillStyle = `rgba(255,255,255,${alpha})`; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + } + } + drawBlock(ctx, col, row, color, size) { + const x = col * size, y = row * size; + const pad = 1; + ctx.fillStyle = color; + ctx.fillRect(x + pad, y + pad, size - pad * 2, size - pad * 2); + // Highlight (top-left shine) + ctx.fillStyle = 'rgba(255,255,255,0.25)'; + ctx.fillRect(x + pad, y + pad, size - pad * 2, 4); + ctx.fillRect(x + pad, y + pad, 4, size - pad * 2); + // Shadow (bottom-right) + ctx.fillStyle = 'rgba(0,0,0,0.30)'; + ctx.fillRect(x + pad, y + size - pad - 4, size - pad * 2, 4); + ctx.fillRect(x + size - pad - 4, y + pad, 4, size - pad * 2); + } + drawGhostBlock(ctx, col, row, color, size) { + const x = col * size + 1, y = row * size + 1; + const s = size - 2; + ctx.strokeStyle = color; + ctx.lineWidth = 2; + ctx.globalAlpha = 0.35; + ctx.strokeRect(x, y, s, s); + ctx.globalAlpha = 1; + } + renderPieceInBox(ctx, canvas, key, faded = false) { + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = '#0a0a0a'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + if (!key) + return; + const shape = SHAPES[key][0]; + const rows = shape.length; + const cols = shape[0].length; + const bSize = PREVIEW_BLK; + const offX = Math.floor((canvas.width - cols * bSize) / 2); + const offY = Math.floor((canvas.height - rows * bSize) / 2); + ctx.globalAlpha = faded ? 0.35 : 1; + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (shape[r][c]) { + const px = offX / bSize + c; + const py = offY / bSize + r; + this.drawBlock(ctx, px, py, COLORS[key], bSize); + } + } + } + ctx.globalAlpha = 1; + } + renderNext(queue) { + const ctx = this.nextCtx; + const canvas = this.nextCanvas; + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = '#0a0a0a'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + const slotH = Math.floor(canvas.height / 3); + for (let i = 0; i < Math.min(3, queue.length); i++) { + const key = queue[i]; + const shape = SHAPES[key][0]; + const rows = shape.length; + const cols = shape[0].length; + const bSize = PREVIEW_BLK; + const offX = Math.floor((canvas.width - cols * bSize) / 2); + const offY = i * slotH + Math.floor((slotH - rows * bSize) / 2); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (shape[r][c]) { + const px = offX / bSize + c; + const py = offY / bSize + r; + this.drawBlock(ctx, px, py, COLORS[key], bSize); + } + } + } + // Divider + if (i < 2) { + ctx.strokeStyle = '#333'; + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.moveTo(4, (i + 1) * slotH); + ctx.lineTo(canvas.width - 4, (i + 1) * slotH); + ctx.stroke(); + } + } + } + renderHold(key, canHold) { + this.renderPieceInBox(this.holdCtx, this.holdCanvas, key, !canHold); + } + renderOverlay(state) { + const el = this.overlayEl; + if (state === 'idle') { + el.innerHTML = ` + <h2>TETRIS</h2> + <p>Press <kbd>Enter</kbd> to start</p> + <div class="controls-hint"> + <p>← → Move &nbsp; ↑ Rotate CW &nbsp; Z Rotate CCW</p> + <p>↓ Soft drop &nbsp; Space Hard drop &nbsp; C Hold</p> + <p>P Pause</p> + </div>`; + el.classList.remove('hidden'); + } + else if (state === 'paused') { + el.innerHTML = `<h2>PAUSED</h2><p>Press <kbd>P</kbd> to resume</p>`; + el.classList.remove('hidden'); + } + else if (state === 'gameover') { + el.innerHTML = `<h2>GAME OVER</h2><p>Press <kbd>Enter</kbd> to play again</p>`; + el.classList.remove('hidden'); + } + else { + el.classList.add('hidden'); + } + } +} +// ─── Input handling ────────────────────────────────────────── +class InputHandler { + constructor(game) { + this.held = new Set(); + this.repeatTimers = new Map(); + // DAS (Delayed Auto Shift) settings + this.DAS = 170; // ms before repeat starts + this.ARR = 50; // ms between repeats + this.game = game; + window.addEventListener('keydown', this.onKeyDown.bind(this)); + window.addEventListener('keyup', this.onKeyUp.bind(this)); + } + onKeyDown(e) { + if (e.repeat) + return; + const key = e.code; + this.held.add(key); + // Always intercept space/arrows to prevent page scroll + if (['Space', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowUp'].includes(key)) { + e.preventDefault(); + } + const g = this.game; + if (key === 'Enter') { + if (g.state === 'idle' || g.state === 'gameover') + g.start(); + return; + } + if (key === 'KeyP' || key === 'Escape') { + if (g.state === 'playing' || g.state === 'paused') + g.togglePause(); + return; + } + if (g.state !== 'playing') + return; + switch (key) { + case 'ArrowLeft': + g.moveLeft(); + this.startRepeat(key, () => g.moveLeft()); + break; + case 'ArrowRight': + g.moveRight(); + this.startRepeat(key, () => g.moveRight()); + break; + case 'ArrowDown': + g.softDrop(); + this.startRepeat(key, () => g.softDrop()); + break; + case 'ArrowUp': + g.rotateCW(); + break; + case 'KeyX': + g.rotateCW(); + break; + case 'KeyZ': + g.rotateCCW(); + break; + case 'Space': + g.hardDrop(); + break; + case 'KeyC': + case 'ShiftLeft': + case 'ShiftRight': + g.holdPiece(); + break; + } + } + onKeyUp(e) { + const key = e.code; + this.held.delete(key); + this.stopRepeat(key); + } + startRepeat(key, action) { + this.stopRepeat(key); + const dasTimer = window.setTimeout(() => { + const arrTimer = window.setInterval(() => { + if (!this.held.has(key)) { + this.stopRepeat(key); + return; + } + if (this.game.state === 'playing') + action(); + }, this.ARR); + this.repeatTimers.set(key + '_arr', arrTimer); + }, this.DAS); + this.repeatTimers.set(key, dasTimer); + } + stopRepeat(key) { + const t = this.repeatTimers.get(key); + if (t !== undefined) { + clearTimeout(t); + this.repeatTimers.delete(key); + } + const t2 = this.repeatTimers.get(key + '_arr'); + if (t2 !== undefined) { + clearInterval(t2); + this.repeatTimers.delete(key + '_arr'); + } + } +} +// ─── Bootstrap ─────────────────────────────────────────────── +window.addEventListener('DOMContentLoaded', () => { + const renderer = new TetrisRenderer(); + const game = new TetrisGame(renderer); + new InputHandler(game); + renderer.renderOverlay('idle'); + renderer.render(game); +});

Impressum · Datenschutz