Purpose of this post

This post publishes all the source code used in the tile sliding puzzle AI experiments. The code is loaded only when you open a file.

Models used

  • DQN: Stable-Baselines3. The observation is the 4×4 tile numbers, the actions are the four moves of the empty cell (up, down, left, right), and the reward is the negative sum of each tile's remaining Manhattan distance to its place. The endless repetition in post 1 came from this reward.
  • Imitation learning (BC): the DQN policy was first trained on records solved by a person and on solutions generated by a C++ teacher (A*)
  • Planner and Executor: two PyTorch CNNs (convolutions with 32→64 channels). The Planner picks the next tile to place, and the Executor picks the single move that moves that tile. The data was augmented with DAgger, which relabels positions where the policy was wrong with the teacher's answer.
  • World model: simulates upcoming moves with the C++ engine and picks moves by the score of a ValueNet that predicts the board's progress (0 to 1).
  • VLM: Qwen2.5-VL-3B-Instruct from Hugging Face. We gave it the puzzle board image and the list of possible moves and received the next move as JSON.

Supporting pieces

  • C++ teacher (PuzzleTeacher, Planner, Executor): demo generation and the grading reference. In research mode, it does not overwrite the moves made by the agent.
  • agent_loop_guard: a safeguard that, when DQN or the VLM repeats the same board, escapes with a move that reduces the Manhattan distance
  • AI solver in the web game: not a trained model but a weighted A* search running in the browser (Manhattan distance + linear conflict)

Results of running them again

Even after 40 iterations, imitation learning stalled at 71.1% of moves matching the teacher.

Imitation learning accuracy. Teacher (A*) solutions 71.1%, Executor solutions 63.1%
Imitation learning accuracy. Teacher (A*) solutions 71.1%, Executor solutions 63.1%

We ran boards shuffled by 80 moves again under the same conditions. None of the trained models finished a single board; only the C++ Executor, which has the loop rule written in code, solved them all.

Share of 80-move shuffled boards solved to the end. DQN, Manhattan and random 0/50, Planner/Executor networks 0/10, C++ Executor 50/50
Share of 80-move shuffled boards solved to the end. DQN, Manhattan and random 0/50, Planner/Executor networks 0/10, C++ Executor 50/50

The Planner/Executor networks matched the teacher 83% of the time when picking the next tile and 40% when picking a single move, and could not even finish the first row. The world model solved all 10 boards, but the move sequence was identical even with the ValueNet switched off. What solved the boards was not the ValueNet but the C++ Executor running inside it.

We gave Qwen2.5-VL-3B the board picture and the possible moves and asked it directly at every move. It could not solve even boards shuffled by only 4 moves. In all 20 games it either went back and forth between two cells or kept rotating a 2×2 block of four cells forever. It knows how to turn a loop but not when to stop.

Qwen2.5-VL-3B repetition patterns. 4-move shuffles: back-and-forth 4, rotating 6; 10-move shuffles: back-and-forth 2, rotating 8; solved 0
Qwen2.5-VL-3B repetition patterns. 4-move shuffles: back-and-forth 4, rotating 6; 10-move shuffles: back-and-forth 2, rotating 8; solved 0

Folder layout

  • src: Qt6/C++ puzzle engine, C API for Python, Planner/Executor/Teacher, Qt screen and TCP training server
  • .py files at the root: Gymnasium environment, demo generation, DQN/BC/Planner-Executor/world model training, Qt connection client, evaluation simulations
  • web: Next.js web puzzle screen

Server deployment settings, monitoring and automation scripts, training data and model weights, and the puzzle picture files are excluded from the release. Web operation code and configuration such as ads, and debugging tools are also left out, so some imports and the scripts paths in the README point to unpublished files.

Full source

73 files · 19,290 lines — open a folder and click a file to load its code.

Project root41 files
agent_loop_guard.pypython · 275 lines · 9KB

Loading code…

CMakeLists.txttext · 64 lines · 2KB

Loading code…

dqn_sim.pypython · 257 lines · 9KB

Loading code…

engine_world_model.pypython · 256 lines · 8KB

Loading code…

generate_executor_demos.pypython · 128 lines · 4KB

Loading code…

generate_pe_recovery_demos.pypython · 199 lines · 6KB

Loading code…

generate_planner_demos.pypython · 77 lines · 2KB

Loading code…

generate_teacher_demos.pypython · 207 lines · 6KB

Loading code…

generate_wm_labels.pypython · 101 lines · 3KB

Loading code…

local_puzzle_env.pypython · 223 lines · 8KB

Loading code…

pe_dagger_collect.pypython · 217 lines · 8KB

Loading code…

pe_nets.pypython · 145 lines · 5KB

Loading code…

pe_segment_sim.pypython · 159 lines · 5KB

Loading code…

pe_sim.pypython · 243 lines · 8KB

Loading code…

pe_targets.pypython · 71 lines · 2KB

Loading code…

plan_agent.pypython · 310 lines · 11KB

Loading code…

plan_obs.pypython · 18 lines · 661B

Loading code…

plan_puzzle_env.pypython · 101 lines · 4KB

Loading code…

plan_sim.pypython · 262 lines · 8KB

Loading code…

planner_obs.pypython · 17 lines · 556B

Loading code…

PROJECT_PURPOSE.mdmarkdown · 149 lines · 7KB

Loading code…

puzzle_c_bindings.pypython · 193 lines · 7KB

Loading code…

qt_dqn_sim.pypython · 293 lines · 10KB

Loading code…

qt_pe_client.pypython · 738 lines · 23KB

Loading code…

qt_rl_client.pypython · 198 lines · 7KB

Loading code…

qt_vlm_client.pypython · 494 lines · 18KB

Loading code…

qt_vlm_sim.pypython · 324 lines · 11KB

Loading code…

qt_wm_client.pypython · 200 lines · 7KB

Loading code…

README.mdmarkdown · 139 lines · 5KB

Loading code…

requirements-vlm.txttext · 8 lines · 153B

Loading code…

requirements.txttext · 4 lines · 40B

Loading code…

segment_plan_ko.pypython · 42 lines · 2KB

Loading code…

train_bc_from_demos.pypython · 145 lines · 5KB

Loading code…

train_pe.pypython · 327 lines · 11KB

Loading code…

train_plan_bc.pypython · 152 lines · 5KB

Loading code…

train_puzzle_rl.pypython · 358 lines · 13KB

Loading code…

train_world_model.pypython · 135 lines · 5KB

Loading code…

wm_nets.pypython · 54 lines · 2KB

Loading code…

world_model_agent.pypython · 183 lines · 7KB

Loading code…

world_model_sim.pypython · 135 lines · 4KB

Loading code…

world_obs.pypython · 38 lines · 1KB

Loading code…

src/19 files
src/demo_sim.cppc++ · 540 lines · 18KB

Loading code…

src/main_window.cppc++ · 2,089 lines · 66KB

Loading code…

src/main_window.hc++ · 196 lines · 7KB

Loading code…

src/main.cppc++ · 68 lines · 2KB

Loading code…

src/puzzle_c_api.cppc++ · 400 lines · 12KB

Loading code…

src/puzzle_engine.cppc++ · 546 lines · 15KB

Loading code…

src/puzzle_engine.hc++ · 110 lines · 4KB

Loading code…

src/puzzle_executor.cppc++ · 519 lines · 19KB

Loading code…

src/puzzle_executor.hc++ · 53 lines · 2KB

Loading code…

src/puzzle_plan_log.hc++ · 24 lines · 547B

Loading code…

src/puzzle_planner.cppc++ · 4,414 lines · 152KB

Loading code…

src/puzzle_planner.hc++ · 53 lines · 2KB

Loading code…

src/puzzle_solve_waves.cppc++ · 110 lines · 3KB

Loading code…

src/puzzle_solve_waves.hc++ · 33 lines · 1KB

Loading code…

src/puzzle_teacher.cppc++ · 748 lines · 22KB

Loading code…

src/puzzle_teacher.hc++ · 31 lines · 940B

Loading code…

src/puzzle_tile_action.hc++ · 95 lines · 3KB

Loading code…

src/puzzle_widget.cppc++ · 148 lines · 4KB

Loading code…

src/puzzle_widget.hc++ · 47 lines · 1KB

Loading code…

web/13 files
web/app/globals.csscss · 50 lines · 912B

Loading code…

web/app/layout.tsxtsx · 33 lines · 969B

Loading code…

web/app/page.module.csscss · 173 lines · 3KB

Loading code…

web/app/page.tsxtsx · 95 lines · 3KB

Loading code…

web/app/play/page.tsxtsx · 338 lines · 9KB

Loading code…

web/app/play/play.module.csscss · 152 lines · 2KB

Loading code…

web/components/PuzzleBoard.module.csscss · 27 lines · 396B

Loading code…

web/components/PuzzleBoard.tsxtsx · 37 lines · 1KB

Loading code…

web/lib/levels.tstypescript · 134 lines · 4KB

Loading code…

web/lib/progress.tstypescript · 37 lines · 1KB

Loading code…

web/lib/puzzle.tstypescript · 145 lines · 4KB

Loading code…

web/lib/solver.tstypescript · 181 lines · 5KB

Loading code…

web/package.jsonjson · 25 lines · 557B

Loading code…