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.

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.

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.

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 root
agent_loop_guard.py
Loading code…
CMakeLists.txt
Loading code…
dqn_sim.py
Loading code…
engine_world_model.py
Loading code…
generate_executor_demos.py
Loading code…
generate_pe_recovery_demos.py
Loading code…
generate_planner_demos.py
Loading code…
generate_teacher_demos.py
Loading code…
generate_wm_labels.py
Loading code…
local_puzzle_env.py
Loading code…
pe_dagger_collect.py
Loading code…
pe_nets.py
Loading code…
pe_segment_sim.py
Loading code…
pe_sim.py
Loading code…
pe_targets.py
Loading code…
plan_agent.py
Loading code…
plan_obs.py
Loading code…
plan_puzzle_env.py
Loading code…
plan_sim.py
Loading code…
planner_obs.py
Loading code…
PROJECT_PURPOSE.md
Loading code…
puzzle_c_bindings.py
Loading code…
qt_dqn_sim.py
Loading code…
qt_pe_client.py
Loading code…
qt_rl_client.py
Loading code…
qt_vlm_client.py
Loading code…
qt_vlm_sim.py
Loading code…
qt_wm_client.py
Loading code…
README.md
Loading code…
requirements-vlm.txt
Loading code…
requirements.txt
Loading code…
segment_plan_ko.py
Loading code…
train_bc_from_demos.py
Loading code…
train_pe.py
Loading code…
train_plan_bc.py
Loading code…
train_puzzle_rl.py
Loading code…
train_world_model.py
Loading code…
wm_nets.py
Loading code…
world_model_agent.py
Loading code…
world_model_sim.py
Loading code…
world_obs.py
Loading code…
src/
src/demo_sim.cpp
Loading code…
src/main_window.cpp
Loading code…
src/main_window.h
Loading code…
src/main.cpp
Loading code…
src/puzzle_c_api.cpp
Loading code…
src/puzzle_engine.cpp
Loading code…
src/puzzle_engine.h
Loading code…
src/puzzle_executor.cpp
Loading code…
src/puzzle_executor.h
Loading code…
src/puzzle_plan_log.h
Loading code…
src/puzzle_planner.cpp
Loading code…
src/puzzle_planner.h
Loading code…
src/puzzle_solve_waves.cpp
Loading code…
src/puzzle_solve_waves.h
Loading code…
src/puzzle_teacher.cpp
Loading code…
src/puzzle_teacher.h
Loading code…
src/puzzle_tile_action.h
Loading code…
src/puzzle_widget.cpp
Loading code…
src/puzzle_widget.h
Loading code…
web/
web/app/globals.css
Loading code…
web/app/layout.tsx
Loading code…
web/app/page.module.css
Loading code…
web/app/page.tsx
Loading code…
web/app/play/page.tsx
Loading code…
web/app/play/play.module.css
Loading code…
web/components/PuzzleBoard.module.css
Loading code…
web/components/PuzzleBoard.tsx
Loading code…
web/lib/levels.ts
Loading code…
web/lib/progress.ts
Loading code…
web/lib/puzzle.ts
Loading code…
web/lib/solver.ts
Loading code…
web/package.json
Loading code…
COMMENTS · CHAPTER 04
The full source code and the models used 0 comments
No comments yet. Leave a question or anything you would like to add.
To post a comment, continue with Google and register a nickname and email address.
Continue with Google