33//! This module provides functions to format the Sudoku board and its solve path
44//! in various ways.
55
6- use crate :: core:: { Board , Solution , SolvePath , TechniqueFlags } ;
6+ use crate :: core:: { Board , Solution , SolvePath , SolveStep , TechniqueFlags } ;
77use std:: fmt;
88
99/// Formats the solution into a human-readable string representation.
1010impl fmt:: Display for Solution {
1111 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
1212 writeln ! ( f, "{}" , self . board) ?;
13- writeln ! ( f, "{}" , self . solve_path) ?;
13+ write ! ( f, "\n {}" , self . solve_path) ?;
1414 Ok ( ( ) )
1515 }
1616}
@@ -19,7 +19,7 @@ impl fmt::Display for Solution {
1919impl fmt:: Display for Board {
2020 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
2121 writeln ! ( f, "{}" , format_grid( & self . cells) . join( "\n " ) ) ?;
22- writeln ! ( f, "Line format: {}" , format_line( & self . cells) ) ?;
22+ write ! ( f, "Line format: {}" , format_line( & self . cells) ) ?;
2323 Ok ( ( ) )
2424 }
2525}
@@ -59,6 +59,7 @@ impl fmt::Display for TechniqueFlags {
5959 }
6060}
6161
62+ /// Formats the solve path into a human-readable string representation.
6263impl fmt:: Display for SolvePath {
6364 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
6465 let path: Vec < ( usize , usize , u8 , TechniqueFlags , & str ) > = self
@@ -85,6 +86,38 @@ impl fmt::Display for SolvePath {
8586 }
8687}
8788
89+ /// Formats the solve step into a human-readable string representation
90+ impl fmt:: Display for SolveStep {
91+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
92+ match self {
93+ SolveStep :: Placement {
94+ row,
95+ col,
96+ value,
97+ flags,
98+ } => {
99+ write ! (
100+ f,
101+ "Value {} is placed on R{}C{} by {}" ,
102+ value, row, col, flags
103+ )
104+ }
105+ SolveStep :: CandidateElimination {
106+ row,
107+ col,
108+ value,
109+ flags,
110+ } => {
111+ write ! (
112+ f,
113+ "Value {} is eliminated from R{}C{} by {}" ,
114+ value, row, col, flags
115+ )
116+ }
117+ }
118+ }
119+ }
120+
88121/// Formats the Sudoku board into a grid representation.
89122///
90123/// This function takes a 9x9 Sudoku board and formats it into a grid with
@@ -179,6 +212,7 @@ pub fn format_solve_path(
179212#[ cfg( test) ]
180213mod tests {
181214 use super :: * ;
215+ use crate :: core:: TechniqueFlags ;
182216
183217 #[ test]
184218 fn test_format_grid ( ) {
@@ -291,4 +325,55 @@ mod tests {
291325 "Naked Singles, Locked Candidates, X-Wing"
292326 ) ;
293327 }
328+
329+ #[ test]
330+ fn test_empty_path ( ) {
331+ let path: Vec < ( usize , usize , u8 , TechniqueFlags , & str ) > = Vec :: new ( ) ;
332+ let expected = vec ! [ "(No moves recorded)" . to_string( ) ] ;
333+ assert_eq ! ( format_solve_path( & path, 5 ) , expected) ;
334+ }
335+
336+ #[ test]
337+ fn test_single_technique_multiple_moves_with_chunking ( ) {
338+ let path = vec ! [
339+ ( 0 , 0 , 1 , TechniqueFlags :: NAKED_SINGLES , "plac" ) ,
340+ ( 0 , 1 , 2 , TechniqueFlags :: NAKED_SINGLES , "plac" ) ,
341+ ( 0 , 2 , 3 , TechniqueFlags :: NAKED_SINGLES , "plac" ) ,
342+ ( 0 , 3 , 4 , TechniqueFlags :: NAKED_SINGLES , "plac" ) ,
343+ ( 0 , 4 , 5 , TechniqueFlags :: NAKED_SINGLES , "plac" ) ,
344+ ( 0 , 5 , 6 , TechniqueFlags :: NAKED_SINGLES , "plac" ) ,
345+ ] ;
346+ let chunk_size = 2 ; // Each line will have 2 moves
347+
348+ let expected = vec ! [
349+ "Naked Singles:" . to_string( ) ,
350+ " R1C1=1,A=plac R1C2=2,A=plac" . to_string( ) ,
351+ " R1C3=3,A=plac R1C4=4,A=plac" . to_string( ) ,
352+ " R1C5=5,A=plac R1C6=6,A=plac" . to_string( ) ,
353+ ] ;
354+ assert_eq ! ( format_solve_path( & path, chunk_size) , expected) ;
355+ }
356+
357+ #[ test]
358+ fn test_multiple_techniques_and_mixed_chunking ( ) {
359+ let path = vec ! [
360+ ( 0 , 0 , 1 , TechniqueFlags :: NAKED_SINGLES , "plac" ) ,
361+ ( 0 , 1 , 2 , TechniqueFlags :: NAKED_SINGLES , "plac" ) ,
362+ ( 1 , 0 , 3 , TechniqueFlags :: HIDDEN_SINGLES , "plac" ) ,
363+ ( 1 , 1 , 4 , TechniqueFlags :: HIDDEN_SINGLES , "plac" ) ,
364+ ( 1 , 2 , 5 , TechniqueFlags :: HIDDEN_SINGLES , "plac" ) ,
365+ ( 2 , 0 , 6 , TechniqueFlags :: HIDDEN_PAIRS , "elim" ) ,
366+ ] ;
367+ let chunk_size = 3 ; // Each line will have 3 moves
368+
369+ let expected: Vec < String > = vec ! [
370+ "Naked Singles:" . to_string( ) ,
371+ " R1C1=1,A=plac R1C2=2,A=plac" . to_string( ) ,
372+ "Hidden Singles:" . to_string( ) ,
373+ " R2C1=3,A=plac R2C2=4,A=plac R2C3=5,A=plac" . to_string( ) ,
374+ "Hidden Pairs:" . to_string( ) ,
375+ " R3C1=6,A=elim" . to_string( ) ,
376+ ] ;
377+ assert_eq ! ( format_solve_path( & path, chunk_size) , expected) ;
378+ }
294379}
0 commit comments