@@ -32,6 +32,11 @@ struct FenStrings {
3232pub enum GameFromFenError {
3333 NotAscii ,
3434 WrongFieldCount ,
35+ MalformedBoard ( BoardFromFenError ) ,
36+ MalformedPlayer ( InvalidPlayer ) ,
37+ MalformedEnPassantTarget ( SquareFromFenError ) ,
38+ MalformedFiftyRuleClock ( core:: num:: ParseIntError ) ,
39+ MalformedMoveCount ( core:: num:: ParseIntError ) ,
3540}
3641impl GameStateCore {
3742 pub fn try_from_fen ( fen : & str ) -> Result < Self , GameFromFenError > {
@@ -56,18 +61,23 @@ impl GameStateCore {
5661 full_move_number : fen_parts[ 5 ] . clone ( ) ,
5762 } ;
5863
59- let board = Board :: try_from_fen_repr ( fen. piece_placements . as_slice ( ) ) . unwrap ( ) ;
64+ let board = Board :: try_from_fen_repr ( fen. piece_placements . as_slice ( ) )
65+ . map_err ( GameFromFenError :: MalformedBoard ) ?;
6066
6167 let fifty_move_rule_clock =
62- FiftyMoveRuleClock :: try_from_fen_repr ( fen. half_move_clock . as_slice ( ) ) . unwrap ( ) ;
68+ FiftyMoveRuleClock :: try_from_fen_repr ( fen. half_move_clock . as_slice ( ) )
69+ . map_err ( GameFromFenError :: MalformedFiftyRuleClock ) ?;
6370
6471 let castling_rights = CastlingRights :: from_fen_repr ( & fen. castling_availability ) ;
6572
66- let active_player = PlayerKind :: try_from_fen_repr ( fen. active_player . as_slice ( ) ) . unwrap ( ) ;
67- let en_passant_target =
68- Square :: try_from_fen_repr ( fen. en_passant_target_square . as_slice ( ) ) . unwrap ( ) ;
69- let full_move_count =
70- FullMoveCount :: try_from_fen_repr ( fen. full_move_number . as_slice ( ) ) . unwrap ( ) ;
73+ let active_player = PlayerKind :: try_from_fen_repr ( fen. active_player . as_slice ( ) )
74+ . map_err ( GameFromFenError :: MalformedPlayer ) ?;
75+
76+ let en_passant_target = Square :: try_from_fen_repr ( fen. en_passant_target_square . as_slice ( ) )
77+ . map_err ( GameFromFenError :: MalformedEnPassantTarget ) ?;
78+
79+ let full_move_count = FullMoveCount :: try_from_fen_repr ( fen. full_move_number . as_slice ( ) )
80+ . map_err ( GameFromFenError :: MalformedMoveCount ) ?;
7181
7282 Ok ( Self {
7383 board,
@@ -161,7 +171,11 @@ impl FullMoveCount {
161171 }
162172
163173 fn to_fen_repr ( self ) -> Vec < AsciiChar > {
164- self . 0 . to_string ( ) . as_ascii ( ) . unwrap ( ) . to_owned ( )
174+ self . 0
175+ . to_string ( )
176+ . as_ascii ( )
177+ . expect ( "digits are ascii" )
178+ . to_owned ( )
165179 }
166180}
167181
@@ -171,7 +185,11 @@ impl FiftyMoveRuleClock {
171185 }
172186
173187 fn to_fen_repr ( self ) -> Vec < AsciiChar > {
174- self . 0 . to_string ( ) . as_ascii ( ) . unwrap ( ) . to_owned ( )
188+ self . 0
189+ . to_string ( )
190+ . as_ascii ( )
191+ . expect ( "digits are ascii" )
192+ . to_owned ( )
175193 }
176194}
177195
@@ -269,24 +287,20 @@ pub enum BoardFromFenError {
269287
270288impl Board {
271289 fn try_from_fen_repr ( value : & [ AsciiChar ] ) -> Result < Self , BoardFromFenError > {
272- fn ascii_char_digit_to_int ( char : AsciiChar ) -> usize {
273- match char as u8 {
274- ..=b'0' => panic ! ( "{char} is an unexpectedly low digit / ascii char" ) ,
275- b'1' ..=b'8' => usize:: from ( u8:: from ( char) - b'0' ) ,
276- b'9' .. => panic ! ( "{char} is an unexpectedly high digit / ascii char" ) ,
277- }
278- }
279290 fn fen_row_to_board_row (
280291 row : & [ AsciiChar ] ,
281292 ) -> Result < [ Option < Piece > ; 8 ] , BoardFromFenError > {
282293 let mut out_row: Vec < Option < Piece > > = vec ! [ ] ;
283294
284295 for c in row {
285296 match * c as u8 {
286- b'1' ..=b'8' => out_row. extend ( vec ! [ None ; ascii_char_digit_to_int ( * c ) ] ) ,
297+ b'1' ..=b'8' => out_row. extend ( vec ! [ None ; usize :: from ( u8 :: from ( * c ) - b'0' ) ] ) ,
287298 b'P' | b'N' | b'B' | b'R' | b'Q' | b'K' | b'p' | b'n' | b'b' | b'r' | b'q'
288299 | b'k' => {
289- out_row. push ( Some ( Piece :: try_from_fen_repr ( * c) . unwrap ( ) ) ) ;
300+ out_row. push ( Some (
301+ Piece :: try_from_fen_repr ( * c)
302+ . expect ( "these chars are valid Piece reprs" ) ,
303+ ) ) ;
290304 }
291305
292306 _ => return Err ( BoardFromFenError :: IllegalCharacter ( * c) ) ,
@@ -311,8 +325,9 @@ impl Board {
311325 //TODO: un-fuck this
312326 for square in Square :: ALL {
313327 new_board[ Square {
314- col : Col :: try_from ( u8:: from ( square. row ) ) . unwrap ( ) ,
315- row : Row :: try_from ( 9 - u8:: from ( square. col ) ) . unwrap ( ) ,
328+ col : Col :: try_from ( u8:: from ( square. row ) )
329+ . expect ( "valid row numbers are valid col numbers" ) ,
330+ row : Row :: try_from ( 9 - u8:: from ( square. col ) ) . expect ( "9 - 1..=8 is in range 1..=8" ) ,
316331 } ] = piece_placements_chunked[ square] ;
317332 }
318333
@@ -332,7 +347,7 @@ impl Board {
332347 running_square_count
333348 . to_string ( )
334349 . as_ascii ( )
335- . unwrap ( )
350+ . expect ( "digits are ascii" )
336351 . to_owned ( ) ,
337352 ) ; //as the running count should never exceed 8, this should always be a single digit
338353 }
@@ -346,7 +361,7 @@ impl Board {
346361 running_square_count
347362 . to_string ( )
348363 . as_ascii ( )
349- . unwrap ( )
364+ . expect ( "digits are ascii" )
350365 . to_owned ( ) ,
351366 ) ; //as the running count should never exceed 8, this should always be a single digit
352367 }
@@ -366,7 +381,7 @@ impl Col {
366381 }
367382 #[ must_use]
368383 pub ( crate ) const fn to_fen_repr ( self ) -> AsciiChar {
369- AsciiChar :: from_u8 ( u8:: from ( self ) + b'a' - 1 ) . unwrap ( )
384+ AsciiChar :: from_u8 ( u8:: from ( self ) + b'a' - 1 ) . expect ( "a..=h are ascii" )
370385 }
371386}
372387impl Row {
@@ -375,7 +390,7 @@ impl Row {
375390 }
376391 #[ must_use]
377392 pub ( crate ) const fn to_fen_repr ( self ) -> AsciiChar {
378- AsciiChar :: from_u8 ( u8:: from ( self ) + b'0' ) . unwrap ( )
393+ AsciiChar :: from_u8 ( u8:: from ( self ) + b'0' ) . expect ( "0..=8 are ascii" )
379394 }
380395}
381396
@@ -467,7 +482,7 @@ mod tests {
467482
468483 #[ test]
469484 fn test_player_kind_fens_round_trip ( ) {
470- for player_kind in [ PlayerKind :: White , PlayerKind :: Black ] {
485+ for player_kind in PlayerKind :: ALL {
471486 println ! (
472487 "{player_kind:?}: {}" ,
473488 PlayerKind :: to_fen_repr( player_kind) . as_str( )
0 commit comments