<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: William Cozza Pereira</title>
    <description>The latest articles on DEV Community by William Cozza Pereira (@wozzp).</description>
    <link>https://dev.to/wozzp</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4024243%2F73205524-31f1-4e7b-899b-1f289fb42e31.jpg</url>
      <title>DEV Community: William Cozza Pereira</title>
      <link>https://dev.to/wozzp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wozzp"/>
    <language>en</language>
    <item>
      <title>I Built a Rubik’s Cube Solver That Verifies Every Solution by Replaying It</title>
      <dc:creator>William Cozza Pereira</dc:creator>
      <pubDate>Fri, 10 Jul 2026 15:37:03 +0000</pubDate>
      <link>https://dev.to/wozzp/i-built-a-rubiks-cube-solver-that-verifies-every-solution-by-replaying-it-44f0</link>
      <guid>https://dev.to/wozzp/i-built-a-rubiks-cube-solver-that-verifies-every-solution-by-replaying-it-44f0</guid>
      <description>&lt;p&gt;Recently, I shared &lt;strong&gt;SpeedCube&lt;/strong&gt; on Hacker News.&lt;/p&gt;

&lt;p&gt;I expected a few technical comments and some feedback. Instead, my analytics showed around &lt;strong&gt;15,000 views&lt;/strong&gt; on the site after the post.&lt;/p&gt;

&lt;p&gt;The traffic was exciting, but it also pushed me to explain more clearly what the project actually is — and which guarantees it does and does not make.&lt;/p&gt;

&lt;p&gt;SpeedCube is an MIT-licensed, open-source platform for solving and practicing twisty puzzles.&lt;/p&gt;

&lt;p&gt;You can try it here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://speedcube.com.br/en/solve/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=showdev" rel="noopener noreferrer"&gt;https://speedcube.com.br/en/solve/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=showdev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source code:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/williamisnotdefined" rel="noopener noreferrer"&gt;
        williamisnotdefined
      &lt;/a&gt; / &lt;a href="https://github.com/williamisnotdefined/rubiks-cube-solver" rel="noopener noreferrer"&gt;
        rubiks-cube-solver
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Rubik's Cube Solver&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Rust-first puzzle solver with a native HTTP API, React web UI, replay verification, and optional YOLO-based camera scanner.&lt;/p&gt;
&lt;p&gt;The product goal is a web interface where a user can input a valid puzzle state and receive the shortest practical replay-verified solution found within explicit limits.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Current Status&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;crates/cube-engine&lt;/code&gt; owns state, moves, notation, validation, search, heuristics, pruning tables, solver strategies, and replay verification.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;crates/api&lt;/code&gt; exposes the Rust engine through Axum HTTP endpoints.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apps/web&lt;/code&gt; provides puzzle-aware solve flows, visualization, playback, and locale resources.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scanner&lt;/code&gt; is Python-only and YOLO-only for camera analysis, training helpers, and ONNX export.&lt;/li&gt;
&lt;li&gt;AI routing is generated from canonical files under &lt;code&gt;ai/&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Project Docs&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;docs/project-plan.md&lt;/code&gt;: current technical direction, implementation rules, and puzzle boundaries.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/runtime.md&lt;/code&gt;: local, Docker, production, tunnel, and training runtime commands.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scanner/training/SCANNER_YOLO_RUNBOOK.md&lt;/code&gt;: scanner dataset, training, export, and artifact workflow.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scanner/runtime/README.md&lt;/code&gt;: scanner runtime service details.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Prerequisites&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Node.js 24 and npm 10.9+…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/williamisnotdefined/rubiks-cube-solver" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  What SpeedCube includes today
&lt;/h2&gt;

&lt;p&gt;The current application includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A stable 3×3 Rubik’s Cube solver&lt;/li&gt;
&lt;li&gt;An experimental 2×2 solver&lt;/li&gt;
&lt;li&gt;Notation and facelet input&lt;/li&gt;
&lt;li&gt;An optional camera-scanning workflow&lt;/li&gt;
&lt;li&gt;Interactive cube visualization and solution playback&lt;/li&gt;
&lt;li&gt;A speedcubing timer with event-specific scramble generation&lt;/li&gt;
&lt;li&gt;Algorithm reference pages&lt;/li&gt;
&lt;li&gt;Puzzle notation guides&lt;/li&gt;
&lt;li&gt;World-record and public WCA-data views&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One important distinction is that &lt;strong&gt;appearing in the timer or puzzle catalog does not necessarily mean that a puzzle has a working solver&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At the moment, the 3×3 solver is the stable product path. The 2×2 solver is experimental. Other puzzles such as Pyraminx, Clock, Skewb, Square-1, and Megaminx are represented in parts of the platform, but they are not yet supported solver targets.&lt;/p&gt;

&lt;p&gt;I would rather expose that distinction honestly than make the project appear more complete than it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Rust-first architecture
&lt;/h2&gt;

&lt;p&gt;The main architecture looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;React + TypeScript web UI
        ↓
Axum HTTP API
        ↓
Rust cube engine
        ↓
Puzzle-specific state validation
        ↓
Bounded solver strategy
        ↓
Replay verification
        ↓
Visual solution playback
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Rust engine owns the parts that determine correctness:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Puzzle state&lt;/li&gt;
&lt;li&gt;Moves and notation&lt;/li&gt;
&lt;li&gt;State validation&lt;/li&gt;
&lt;li&gt;Search algorithms&lt;/li&gt;
&lt;li&gt;Heuristics&lt;/li&gt;
&lt;li&gt;Pruning tables and pattern databases&lt;/li&gt;
&lt;li&gt;Solver strategies&lt;/li&gt;
&lt;li&gt;Replay verification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API is responsible for HTTP contracts, request limits, puzzle routing, artifact loading, and response mapping.&lt;/p&gt;

&lt;p&gt;The frontend collects input, sends solve requests, displays results, and plays the returned moves. It does not implement the actual solver logic.&lt;/p&gt;

&lt;p&gt;This separation is useful because a visual interface should not silently become a second, inconsistent implementation of the puzzle rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  The most important invariant: replay verification
&lt;/h2&gt;

&lt;p&gt;Search algorithms can fail.&lt;/p&gt;

&lt;p&gt;They can hit a depth limit, exhaust a node budget, depend on a missing pruning-table artifact, or produce an invalid candidate because of an implementation error.&lt;/p&gt;

&lt;p&gt;For this project, returning an incorrect move sequence as a successful solution is worse than returning no solution.&lt;/p&gt;

&lt;p&gt;The main invariant is therefore:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A candidate solution is not exposed as successful unless replaying every returned move from the requested state reaches the solved state.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every successful solve is checked again by the Rust engine before the API returns it.&lt;/p&gt;

&lt;p&gt;If replay fails, the result is treated as an error — not as a successful response with a warning.&lt;/p&gt;

&lt;p&gt;That design also influences the UI. The frontend can display whether a result was replay verified, what strategy was used, and which limits were applied.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solver strategies without false promises
&lt;/h2&gt;

&lt;p&gt;The 3×3 engine currently exposes several computational strategies, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bounded IDA*&lt;/li&gt;
&lt;li&gt;A generated two-phase solver&lt;/li&gt;
&lt;li&gt;A quality-oriented two-phase variant&lt;/li&gt;
&lt;li&gt;An experimental multiprobe variant&lt;/li&gt;
&lt;li&gt;Bounded searches using pattern databases&lt;/li&gt;
&lt;li&gt;A portfolio that tries short-solution approaches before falling back to two-phase search&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The default stable 3×3 path uses a generated two-phase strategy.&lt;/p&gt;

&lt;p&gt;The experimental 2×2 implementation has puzzle-specific bounded IDA* and pattern-database-based strategies.&lt;/p&gt;

&lt;p&gt;These strategies are not presented as a universal optimal solver.&lt;/p&gt;

&lt;p&gt;The project does not promise that every solution will be mathematically optimal. It also does not claim that every scramble will be solved in 20 moves or fewer.&lt;/p&gt;

&lt;p&gt;Instead, the goal is to find a practical, replay-verified solution within explicit depth, node, time, and artifact limits.&lt;/p&gt;

&lt;p&gt;If a search cannot produce a verified result within those limits, the application should report that honestly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Camera scanning is evidence, not truth
&lt;/h2&gt;

&lt;p&gt;The optional scanner uses a separate pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser camera
        ↓
Rust API
        ↓
Python/FastAPI scanner service
        ↓
Optional YOLO/ONNX tile detector
        ↓
Reviewed sticker state
        ↓
Rust validation and solving
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scanner service can analyze a camera frame and produce tile evidence and confidence information.&lt;/p&gt;

&lt;p&gt;However, the model output is not allowed to bypass puzzle validation.&lt;/p&gt;

&lt;p&gt;The user can review the detected stickers, and the resulting state is then validated by the Rust engine before solving.&lt;/p&gt;

&lt;p&gt;This matters because a visually plausible scan may still describe an impossible cube.&lt;/p&gt;

&lt;p&gt;Lighting, reflections, occlusion, camera angle, and model mistakes can all produce incorrect evidence. The solver should not turn uncertain visual output into a confident but invalid solution.&lt;/p&gt;

&lt;p&gt;The current runtime is intentionally focused: it uses an optional YOLO detector exported to ONNX rather than maintaining several competing detector and color-classifier fallbacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The frontend is more than a solve form
&lt;/h2&gt;

&lt;p&gt;The web application is built with React, TypeScript, and Vite.&lt;/p&gt;

&lt;p&gt;It contains puzzle-aware solve and scan flows, cube visualization, move playback, a timer, algorithm-reference pages, notation guides, and localized routes.&lt;/p&gt;

&lt;p&gt;The visualization code lives in a separate private workspace package. It is not the source of truth for solving; it renders states and replays moves received from the validated product flow.&lt;/p&gt;

&lt;p&gt;The timer has its own event catalog and scramble generation pipeline, covering several WCA events.&lt;/p&gt;

&lt;p&gt;The algorithm pages currently include reference sets for puzzles such as 2×2, 3×3, and 4×4, including OLL, PLL, COLL, CLL, EG-1, and related subsets.&lt;/p&gt;

&lt;p&gt;Those educational resources are separate from the computational strategies used by the Rust solver.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why puzzle support is deliberately puzzle-specific
&lt;/h2&gt;

&lt;p&gt;It is tempting to create one generic &lt;code&gt;Puzzle&lt;/code&gt;, &lt;code&gt;State&lt;/code&gt;, or &lt;code&gt;Move&lt;/code&gt; abstraction and force every puzzle into it.&lt;/p&gt;

&lt;p&gt;I decided against that direction.&lt;/p&gt;

&lt;p&gt;Every supported puzzle needs to own its own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State representation&lt;/li&gt;
&lt;li&gt;Move model&lt;/li&gt;
&lt;li&gt;Notation parser&lt;/li&gt;
&lt;li&gt;Legal move generator&lt;/li&gt;
&lt;li&gt;Validator&lt;/li&gt;
&lt;li&gt;Solver strategy&lt;/li&gt;
&lt;li&gt;Replay verifier&lt;/li&gt;
&lt;li&gt;Heuristics and coordinates&lt;/li&gt;
&lt;li&gt;Artifact compatibility rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Shared code is limited to genuinely puzzle-neutral concerns such as metadata, request budgets, result shapes, and frontend selection.&lt;/p&gt;

&lt;p&gt;That creates more explicit code, but it also makes it harder to accidentally treat Square-1, Clock, Pyraminx, and a standard cube as if they shared the same physical rules.&lt;/p&gt;

&lt;p&gt;Adding a puzzle to a catalog is easy. Supporting it correctly requires the complete path from input to validation, solving, replay, visualization, and tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned while building it
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Correctness needs an explicit owner
&lt;/h3&gt;

&lt;p&gt;When puzzle rules are split between the frontend, backend, scanner, and visualizer, the implementations can disagree.&lt;/p&gt;

&lt;p&gt;Making Rust responsible for validation, solving, and verification gives the application a clear correctness boundary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Failure is a valid product result
&lt;/h3&gt;

&lt;p&gt;A bounded solver should be able to say that it did not find a solution within the configured limits.&lt;/p&gt;

&lt;p&gt;Returning an honest failure is better than hiding fallback behavior or implying guarantees the implementation does not provide.&lt;/p&gt;

&lt;h3&gt;
  
  
  Capability metadata matters
&lt;/h3&gt;

&lt;p&gt;“Stable,” “experimental,” and “planned” are not cosmetic labels.&lt;/p&gt;

&lt;p&gt;They prevent a catalog entry, timer scramble, or visualization from being mistaken for complete solver support.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visual correctness is functional correctness
&lt;/h3&gt;

&lt;p&gt;A replay animation is not merely decoration.&lt;/p&gt;

&lt;p&gt;If the displayed moves do not match the state transitions used by the engine, users cannot trust the result. The renderer and engine therefore need consistent notation and state adapters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shipping creates better questions
&lt;/h3&gt;

&lt;p&gt;Developing alone makes it easy to optimize for assumptions that real users do not share.&lt;/p&gt;

&lt;p&gt;Publishing the project exposed questions about solution quality, limits, scanning reliability, mobile usability, notation, and puzzle support that are difficult to discover in isolation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is next
&lt;/h2&gt;

&lt;p&gt;The main areas I want to continue improving are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Solution quality without weakening replay verification&lt;/li&gt;
&lt;li&gt;Scanner training, evaluation, and model reliability&lt;/li&gt;
&lt;li&gt;Better error messages for impossible or incorrectly scanned states&lt;/li&gt;
&lt;li&gt;Stabilizing the 2×2 product path&lt;/li&gt;
&lt;li&gt;Mobile usability&lt;/li&gt;
&lt;li&gt;Timer and training features&lt;/li&gt;
&lt;li&gt;Additional puzzles with complete puzzle-specific validation and tests&lt;/li&gt;
&lt;li&gt;More solver-quality reports using real and generated scrambles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am particularly interested in feedback from people working with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rust search algorithms and heuristics&lt;/li&gt;
&lt;li&gt;IDA* and pattern databases&lt;/li&gt;
&lt;li&gt;YOLO and ONNX deployment&lt;/li&gt;
&lt;li&gt;React visualization and animation&lt;/li&gt;
&lt;li&gt;Puzzle-state modeling&lt;/li&gt;
&lt;li&gt;Speedcubing tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can try SpeedCube here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://speedcube.com.br/en/solve/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=showdev" rel="noopener noreferrer"&gt;https://speedcube.com.br/en/solve/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=showdev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the complete source code is available here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/williamisnotdefined/rubiks-cube-solver" rel="noopener noreferrer"&gt;https://github.com/williamisnotdefined/rubiks-cube-solver&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback, bug reports, and contributions are welcome.&lt;/p&gt;

</description>
      <category>react</category>
      <category>rust</category>
      <category>opensource</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
