chess_lab/variants/standard.rs
1use crate::{
2 core::{Color, GameStatus, Move, Piece, Position, Variant, VariantBuilder},
3 errors::{FenError, MoveError, PGNError},
4 logic::Game,
5 parsing::{
6 fen::get_minified_fen,
7 pgn::{parse_multiple_pgn, parse_pgn},
8 },
9 utils::os::{read_file, write_file},
10};
11
12/// Standard Chess [Variant]
13/// This [Variant] is the most common chess variant played worldwide
14/// It is played on an 8x8 board with the following pieces for each player:
15/// - 8 Pawns
16/// - 2 Rooks
17/// - 2 Knights
18/// - 2 Bishops
19/// - 1 Queen
20/// - 1 King
21///
22/// The game is won by checkmating the opponent's king
23/// The game is drawn by stalemate, threefold repetition, the fifty-move rule, or agreement
24/// The game is lost by resigning or losing on time
25///
26/// # Attributes
27/// * `game` - The game struct that holds the state of the game
28///
29#[derive(Debug, Clone)]
30pub struct StandardChess {
31 game: Game,
32}
33
34impl Default for StandardChess {
35 /// Creates a new instance of the [StandardChess] [Variant] with default values
36 ///
37 /// # Returns
38 /// A new instance of the [StandardChess] [Variant]
39 ///
40 /// # Examples
41 /// ```
42 /// # use chess_lab::variants::StandardChess;
43 /// let game = StandardChess::default();
44 /// ```
45 ///
46 fn default() -> StandardChess {
47 StandardChess {
48 game: Game::default(),
49 }
50 }
51}
52
53impl VariantBuilder for StandardChess {
54 /// Returns the name of the [Variant]
55 ///
56 /// # Returns
57 /// The name of the [Variant]
58 ///
59 /// # Examples
60 /// ```
61 /// # use chess_lab::core::VariantBuilder;
62 /// # use chess_lab::variants::StandardChess;
63 /// let name = StandardChess::name();
64 /// assert_eq!(name, "Standard");
65 /// ```
66 ///
67 fn name() -> &'static str {
68 "Standard"
69 }
70
71 /// Creates a new instance of the [StandardChess] [Variant]
72 ///
73 /// # Returns
74 /// A new instance of the [StandardChess] [Variant]
75 ///
76 /// # Examples
77 /// ```
78 /// # use chess_lab::core::VariantBuilder;
79 /// # use chess_lab::variants::StandardChess;
80 /// use chess_lab::logic::Game;
81 ///
82 /// let game = StandardChess::new(Game::default());
83 /// ```
84 ///
85 fn new(game: Game) -> StandardChess {
86 StandardChess { game }
87 }
88
89 /// Creates a new instance of the [StandardChess] [Variant] from a FEN string
90 ///
91 /// # Arguments
92 /// * `fen` - A FEN string
93 ///
94 /// # Returns
95 /// * `Ok(StandardChess)` - A new instance of the [StandardChess] [Variant]
96 /// * `Err(FenError)` - An error occurred while parsing the FEN string
97 ///
98 /// # Examples
99 /// ```
100 /// # use chess_lab::core::VariantBuilder;
101 /// # use chess_lab::variants::StandardChess;
102 /// let fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
103 /// let game = StandardChess::from_fen(fen).unwrap();
104 /// ```
105 ///
106 fn from_fen(fen: &str) -> Result<StandardChess, FenError> {
107 Ok(StandardChess {
108 game: Game::from_fen(fen)?,
109 })
110 }
111
112 /// Creates a new instance of the [StandardChess] [Variant] from a PGN string
113 ///
114 /// # Arguments
115 /// * `pgn` - A PGN string
116 ///
117 /// # Returns
118 /// A `Result<StandardChess, PGNError>` object
119 /// * `Ok(StandardChess)` - A new instance of the [StandardChess] [Variant]
120 /// * `Err(PgnError)` - An error occurred while parsing the PGN string
121 ///
122 /// # Examples
123 /// ```
124 /// # use chess_lab::core::VariantBuilder;
125 /// # use chess_lab::variants::StandardChess;
126 /// let pgn = "1. e4 e5 2. Nf3 Nc6 3. Bb5 a6";
127 ///
128 /// let game = StandardChess::from_pgn(pgn).unwrap();
129 /// ```
130 ///
131 fn from_pgn(pgn: &str) -> Result<StandardChess, PGNError> {
132 parse_pgn(pgn)
133 }
134
135 /// Loads the [Game] from a file
136 ///
137 /// # Arguments
138 /// * `path` - The path to the file
139 ///
140 /// # Returns
141 /// A `Result<StandardChess, PGNError>` object
142 /// * `Ok(StandardChess)` - The [Game] was loaded successfully
143 /// * `Err(PgnError)` - An error occurred while loading the [Game]
144 ///
145 /// # Examples
146 /// ```
147 /// # use chess_lab::core::VariantBuilder;
148 /// # use chess_lab::variants::StandardChess;
149 ///
150 /// let path = "data/standard/ex1.pgn";
151 /// let game = StandardChess::load(path).unwrap();
152 /// ```
153 ///
154 fn load(path: &str) -> Result<StandardChess, PGNError> {
155 let pgn = read_file(path)?;
156 StandardChess::from_pgn(&pgn)
157 }
158
159 /// Loads multiple [Games](Game) from a file
160 ///
161 /// # Arguments
162 /// * `path` - The path to the file
163 ///
164 /// # Returns
165 /// A `Result<Vec<StandardChess>, PGNError>` object
166 /// * `Ok(Vec<StandardChess>)` - The games were loaded successfully
167 /// * `Err(PgnError)` - An error occurred while loading the games
168 ///
169 /// # Examples
170 /// ```
171 /// # use chess_lab::core::VariantBuilder;
172 /// # use chess_lab::variants::StandardChess;
173 /// let path = "data/standard/ex3.pgn";
174 /// let games = StandardChess::load_all(path).unwrap();
175 /// ```
176 ///
177 fn load_all(path: &str) -> Result<Vec<Self>, PGNError> {
178 let pgn = read_file(path)?;
179 parse_multiple_pgn(&pgn)
180 }
181}
182
183impl Variant for StandardChess {
184 /// Moves a [Piece] on the [crate::logic::Board]
185 ///
186 /// # Arguments
187 /// * `move_str` - A move string in algebraic notation.
188 ///
189 /// # Returns
190 /// A `Result<GameStatus, MoveError>` object
191 /// * `Ok(GameStatus)` - The status of the game after the move.
192 /// * `Err(MoveError)` - An error occurred while moving the piece.
193 ///
194 /// # Examples
195 /// ```
196 /// # use chess_lab::core::{Variant, GameStatus};
197 /// # use chess_lab::variants::StandardChess;
198 /// let mut game = StandardChess::default();
199 /// let status = game.move_piece("e4");
200 ///
201 /// assert_eq!(status, Ok(GameStatus::InProgress));
202 /// ```
203 ///
204 fn move_piece(&mut self, move_str: &str) -> Result<GameStatus, MoveError> {
205 self.game.move_piece(move_str)
206 }
207
208 /// Undoes the last [Move]
209 ///
210 /// # Examples
211 /// ```
212 /// # use chess_lab::core::Variant;
213 /// # use chess_lab::variants::StandardChess;
214 /// let mut game = StandardChess::default();
215 /// game.move_piece("e4").unwrap();
216 /// game.undo();
217 ///
218 /// assert_eq!(game.fen(), "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
219 /// ```
220 ///
221 fn undo(&mut self) {
222 self.game.undo()
223 }
224
225 /// Redoes the last undone [Move]
226 ///
227 /// # Examples
228 /// ```
229 /// # use chess_lab::core::Variant;
230 /// # use chess_lab::variants::StandardChess;
231 /// let mut game = StandardChess::default();
232 /// game.move_piece("e4").unwrap();
233 /// game.undo();
234 /// game.redo();
235 ///
236 /// assert_eq!(game.fen(), "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1");
237 /// ```
238 ///
239 fn redo(&mut self) {
240 self.game.redo()
241 }
242
243 /// Returns the PGN string of the [Game]
244 ///
245 /// # Returns
246 /// The PGN string of the [Game]
247 ///
248 /// # Examples
249 /// ```
250 /// # use chess_lab::core::Variant;
251 /// # use chess_lab::variants::StandardChess;
252 /// let mut game = StandardChess::default();
253 /// game.move_piece("e4").unwrap();
254 /// game.move_piece("e5").unwrap();
255 /// let pgn = game.pgn();
256 ///
257 /// assert!(pgn.contains("1. e4 e5"));
258 /// ```
259 ///
260 fn pgn(&self) -> String {
261 self.game.pgn()
262 }
263
264 /// Returns the FEN string of the game
265 ///
266 /// # Returns
267 /// The FEN string of the game
268 ///
269 /// # Examples
270 /// ```
271 /// # use chess_lab::core::Variant;
272 /// # use chess_lab::variants::StandardChess;
273 /// let game = StandardChess::default();
274 /// let fen = game.fen();
275 ///
276 /// assert_eq!(fen, "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
277 /// ```
278 ///
279 fn fen(&self) -> String {
280 self.game.fen()
281 }
282
283 /// Returns the piece at a given position
284 ///
285 /// # Arguments
286 /// * `pos` - The position to get the piece from
287 ///
288 /// # Returns
289 /// The piece at the given position, if there is one
290 ///
291 /// # Example
292 /// ```
293 /// # use chess_lab::core::Variant;
294 /// # use chess_lab::variants::StandardChess;
295 /// use chess_lab::core::Position;
296 ///
297 /// let game = StandardChess::default();
298 /// let piece = game.get_piece_at(Position::from_string("e2").unwrap());
299 /// assert!(piece.is_some());
300 /// assert_eq!(piece.unwrap().to_string(), "P");
301 /// ```
302 ///
303 fn get_piece_at(&self, pos: Position) -> Option<Piece> {
304 self.game.get_piece_at(pos)
305 }
306
307 /// Returns the legal moves of a piece at a given position
308 ///
309 /// # Arguments
310 /// * `pos` - The position to get the legal moves for
311 ///
312 /// # Returns
313 /// A vector of legal moves for the piece at the given position
314 ///
315 /// # Example
316 /// ```
317 /// # use chess_lab::core::Variant;
318 /// # use chess_lab::variants::StandardChess;
319 /// use chess_lab::core::Position;
320 ///
321 /// let game = StandardChess::default();
322 /// let legal_moves = game.get_legal_moves(Position::from_string("e2").unwrap());
323 /// assert!(legal_moves.iter().any(|m| m.to_string() == "e4"));
324 /// ```
325 ///
326 fn get_legal_moves(&self, pos: Position) -> Vec<Move> {
327 self.game.get_legal_moves(pos)
328 }
329
330 /// Saves the [Game] to a file
331 ///
332 /// # Arguments
333 /// * `path` - The path to the file
334 /// * `overwrite` - Whether to overwrite the file if it already exists
335 ///
336 /// # Returns
337 /// A `Result<(), std::io::Error>` object
338 /// * `Ok(())` - The game was saved successfully
339 /// * `Err(std::io::Error)` - An error occurred while saving the game
340 ///
341 /// # Examples
342 /// ```
343 /// # use chess_lab::core::Variant;
344 /// # use chess_lab::variants::StandardChess;
345 /// let game = StandardChess::default();
346 /// let path = "data/standard/ex.pgn";
347 ///
348 /// game.save(path, true).unwrap();
349 /// ```
350 ///
351 fn save(&self, path: &str, overwrite: bool) -> Result<(), std::io::Error> {
352 write_file(path, self.pgn().as_str(), !overwrite)?;
353 Ok(())
354 }
355
356 /// Resigns the [Game] for a player
357 ///
358 /// # Arguments
359 /// * `color` - The [Color] of the player who resigns
360 ///
361 /// # Examples
362 /// ```
363 /// # use chess_lab::core::Variant;
364 /// # use chess_lab::variants::StandardChess;
365 /// use chess_lab::core::Color;
366 /// let mut game = StandardChess::default();
367 /// game.resign(Color::White);
368 /// ```
369 ///
370 fn resign(&mut self, color: Color) {
371 self.game.resign(color)
372 }
373
374 /// Sets the [Game] as a draw by agreement
375 ///
376 /// # Examples
377 /// ```
378 /// # use chess_lab::core::Variant;
379 /// # use chess_lab::variants::StandardChess;
380 /// let mut game = StandardChess::default();
381 /// game.draw();
382 /// ```
383 ///
384 fn draw(&mut self) {
385 self.game.draw_by_agreement()
386 }
387
388 /// Sets the [Game] as lost in time for a player
389 ///
390 /// # Arguments
391 /// * `color` - The [Color] of the player who lost in time
392 ///
393 /// # Examples
394 /// ```
395 /// # use chess_lab::core::Variant;
396 /// # use chess_lab::variants::StandardChess;
397 /// use chess_lab::core::Color;
398 ///
399 /// let mut game = StandardChess::default();
400 /// game.lost_on_time(Color::Black);
401 /// ```
402 ///
403 fn lost_on_time(&mut self, color: Color) {
404 self.game.lost_on_time(color)
405 }
406
407 /// Returns the minified FEN string of the [Game]
408 ///
409 /// # Returns
410 /// The minified FEN string of the [Game]
411 ///
412 /// # Examples
413 /// ```
414 /// # use chess_lab::core::Variant;
415 /// # use chess_lab::variants::StandardChess;
416 /// let game = StandardChess::default();
417 /// let minified_fen = game.get_minified_fen();
418 /// ```
419 ///
420 fn get_minified_fen(&self) -> String {
421 get_minified_fen(&self.fen())
422 }
423
424 /// Returns the last [Move] of the [Game]
425 ///
426 /// # Returns
427 /// The last [Move] of the [Game], if there is one
428 ///
429 /// # Examples
430 /// ```
431 /// # use chess_lab::core::Variant;
432 /// # use chess_lab::variants::StandardChess;
433 /// let mut game = StandardChess::default();
434 /// game.move_piece("e4").unwrap();
435 /// let last_move = game.get_last_move();
436 /// assert_eq!(last_move.unwrap().to_string(), "e4");
437 /// ```
438 ///
439 fn get_last_move(&self) -> Option<crate::core::Move> {
440 self.game.get_last_move()
441 }
442
443 /// Returns whether it is white's turn to [Move]
444 ///
445 /// # Returns
446 /// Whether it is white's turn to [Move]
447 ///
448 /// # Examples
449 /// ```
450 /// # use chess_lab::core::Variant;
451 /// # use chess_lab::variants::StandardChess;
452 /// let game = StandardChess::default();
453 /// let color = game.is_white_turn();
454 /// ```
455 ///
456 fn is_white_turn(&self) -> bool {
457 self.game.is_white_turn
458 }
459
460 /// Returns the halfmove clock of the [Game]
461 ///
462 /// # Returns
463 /// The halfmove clock of the [Game]
464 ///
465 /// # Examples
466 /// ```
467 /// # use chess_lab::core::Variant;
468 /// # use chess_lab::variants::StandardChess;
469 /// let game = StandardChess::default();
470 /// let halfmove_clock = game.get_halfmove_clock();
471 /// ```
472 ///
473 fn get_halfmove_clock(&self) -> u32 {
474 self.game.halfmove_clock
475 }
476
477 /// Returns the fullmove number of the [Game]
478 ///
479 /// # Returns
480 /// The fullmove number of the [Game]
481 ///
482 /// # Examples
483 /// ```
484 /// # use chess_lab::core::Variant;
485 /// # use chess_lab::variants::StandardChess;
486 /// let game = StandardChess::default();
487 /// let fullmove_number = game.get_fullmove_number();
488 /// ```
489 ///
490 fn get_fullmove_number(&self) -> u32 {
491 self.game.fullmove_number
492 }
493
494 /// Returns the castling rights of the [Game]
495 ///
496 /// # Returns
497 /// The castling rights of the [Game]
498 ///
499 /// # Examples
500 /// ```
501 /// # use chess_lab::core::Variant;
502 /// # use chess_lab::variants::StandardChess;
503 /// let game = StandardChess::default();
504 /// let castling_rights = game.get_castling_rights();
505 /// ```
506 ///
507 fn get_castling_rights(&self) -> String {
508 let mut castling_rights = String::new();
509
510 if self.game.castling_rights == 0 {
511 castling_rights.push('-');
512 } else {
513 if self.game.castling_rights & 0b1000 != 0 {
514 castling_rights.push('K');
515 }
516 if self.game.castling_rights & 0b0100 != 0 {
517 castling_rights.push('Q');
518 }
519 if self.game.castling_rights & 0b0010 != 0 {
520 castling_rights.push('k');
521 }
522 if self.game.castling_rights & 0b0001 != 0 {
523 castling_rights.push('q');
524 }
525 }
526 castling_rights
527 }
528
529 /// Returns the en passant square of the [Game]
530 ///
531 /// # Returns
532 /// The en passant square of the [Game]
533 ///
534 /// # Examples
535 /// ```
536 /// # use chess_lab::core::Variant;
537 /// # use chess_lab::variants::StandardChess;
538 /// let game = StandardChess::default();
539 /// let en_passant = game.get_en_passant();
540 /// ```
541 ///
542 fn get_en_passant(&self) -> Option<Position> {
543 self.game.en_passant
544 }
545
546 /// Returns the starting FEN of the [Game]
547 ///
548 /// # Returns
549 /// A copy of the starting FEN of the [Game]
550 ///
551 /// # Examples
552 /// ```
553 /// # use chess_lab::core::Variant;
554 /// # use chess_lab::variants::StandardChess;
555 /// let game = StandardChess::default();
556 /// let starting_fen = game.get_starting_fen();
557 /// ```
558 ///
559 fn get_starting_fen(&self) -> String {
560 self.game.starting_fen.clone()
561 }
562
563 /// Returns the status of the [Game]
564 ///
565 /// # Returns
566 /// The status of the [Game]
567 ///
568 /// # Examples
569 /// ```
570 /// # use chess_lab::core::{Variant, GameStatus};
571 /// # use chess_lab::variants::StandardChess;
572 /// let game = StandardChess::default();
573 /// let status = game.get_status();
574 /// ```
575 ///
576 fn get_status(&self) -> GameStatus {
577 self.game.status
578 }
579}
580
581#[cfg(test)]
582mod tests {
583 use crate::core::WinReason;
584
585 use super::*;
586
587 #[test]
588 fn test_standard_chess_name() {
589 assert_eq!(StandardChess::name(), "Standard");
590 }
591
592 #[test]
593 fn test_default() {
594 let variant = StandardChess::default();
595 assert_eq!(
596 variant.fen(),
597 "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
598 );
599 }
600
601 #[test]
602 fn test_new() {
603 let game = Game::default();
604 let variant = StandardChess::new(game.clone());
605 assert_eq!(variant.fen(), game.fen());
606 }
607
608 #[test]
609 fn test_from_fen() {
610 let fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
611 let variant = StandardChess::from_fen(fen).unwrap();
612 assert_eq!(variant.fen(), fen);
613 }
614
615 #[test]
616 fn test_from_pgn() {
617 let pgn = "1. e4 e5 2. Nf3 Nc6 3. Bb5 a6";
618 let variant = StandardChess::from_pgn(pgn).unwrap();
619 assert!(variant.pgn().contains("1. e4 e5 2. Nf3 Nc6 3. Bb5 a6"));
620 }
621
622 #[test]
623 fn test_load() {
624 let path = "data/standard/ex1.pgn";
625 let variant = StandardChess::load(path).unwrap();
626 assert!(variant.pgn().contains("1. e4 c6 2. d4 d5 3. exd5 cxd5"));
627 }
628
629 #[test]
630 fn test_load_all() {
631 let path = "data/standard/ex3.pgn";
632 let variants = StandardChess::load_all(path).unwrap();
633 assert_eq!(variants.len(), 20);
634 }
635
636 #[test]
637 fn test_move_piece() {
638 let mut variant = StandardChess::default();
639 let status = variant.move_piece("e4").unwrap();
640 assert_eq!(status, GameStatus::InProgress);
641 assert_eq!(
642 variant.fen(),
643 "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1"
644 );
645 }
646
647 #[test]
648 fn test_get_piece_at() {
649 let variant = StandardChess::default();
650 let piece = variant.get_piece_at(Position::from_string("e2").unwrap());
651 assert!(piece.is_some());
652 assert_eq!(piece.unwrap().to_string(), "P");
653 }
654
655 #[test]
656 fn test_get_legal_moves() {
657 let variant = StandardChess::default();
658 let legal_moves = variant.get_legal_moves(Position::from_string("e2").unwrap());
659 assert!(legal_moves.iter().any(|m| m.to_string() == "e4"));
660 assert!(legal_moves.iter().any(|m| m.to_string() == "e3"));
661 }
662
663 #[test]
664 fn test_undo_redo() {
665 let mut variant = StandardChess::default();
666 variant.move_piece("e4").unwrap();
667 variant.undo();
668 assert_eq!(
669 variant.fen(),
670 "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
671 );
672 variant.redo();
673 assert_eq!(
674 variant.fen(),
675 "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1"
676 );
677 }
678
679 #[test]
680 fn test_save() {
681 let mut variant = StandardChess::default();
682 let path = "data/standard/test_save.pgn";
683
684 variant.move_piece("e4").unwrap();
685 variant.save(path, true).unwrap();
686
687 let loaded_variant = StandardChess::load(path).unwrap();
688 assert_eq!(variant.fen(), loaded_variant.fen());
689
690 // Clean up
691 std::fs::remove_file(path).unwrap();
692 }
693
694 #[test]
695 fn test_resign() {
696 let mut variant = StandardChess::default();
697
698 variant.resign(Color::White);
699 assert_eq!(
700 variant.get_status(),
701 GameStatus::BlackWins(WinReason::Resignation)
702 );
703 }
704
705 #[test]
706 fn test_draw() {
707 let mut variant = StandardChess::default();
708
709 variant.draw();
710 assert_eq!(
711 variant.get_status(),
712 GameStatus::Draw(crate::core::DrawReason::Agreement)
713 );
714 }
715
716 #[test]
717 fn test_lost_on_time() {
718 let mut variant = StandardChess::default();
719
720 variant.lost_on_time(Color::Black);
721 assert_eq!(variant.get_status(), GameStatus::WhiteWins(WinReason::Time));
722 }
723
724 #[test]
725 fn test_minified_fen() {
726 let variant = StandardChess::default();
727 let minified_fen = variant.get_minified_fen();
728 assert_eq!(minified_fen, "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR");
729 }
730
731 #[test]
732 fn test_get_last_move() {
733 let mut variant = StandardChess::default();
734 assert_eq!(variant.get_last_move(), None);
735
736 variant.move_piece("e4").unwrap();
737 let last_move = variant.get_last_move();
738 assert!(last_move.is_some());
739 assert_eq!(last_move.unwrap().to_string(), "e4");
740 }
741
742 #[test]
743 fn test_is_white_turn() {
744 let mut variant = StandardChess::default();
745 assert!(variant.is_white_turn());
746
747 variant.move_piece("e4").unwrap();
748 assert!(!variant.is_white_turn());
749 }
750
751 #[test]
752 fn test_get_castling_rights() {
753 let mut variant = StandardChess::default();
754 let castling_rights = variant.get_castling_rights();
755 assert_eq!(castling_rights, "KQkq");
756
757 variant = StandardChess::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - - 0 1")
758 .unwrap();
759 let castling_rights = variant.get_castling_rights();
760 assert_eq!(castling_rights, "-");
761 }
762
763 #[test]
764 fn test_get_en_passant() {
765 let mut variant = StandardChess::default();
766 assert_eq!(variant.get_en_passant(), None);
767
768 variant.move_piece("e4").unwrap();
769 variant.move_piece("d5").unwrap();
770 variant.move_piece("e5").unwrap();
771 variant.move_piece("f5").unwrap();
772 assert_eq!(
773 variant.get_en_passant().unwrap(),
774 Position::new(5, 5).unwrap()
775 );
776 }
777
778 #[test]
779 fn test_get_halfmove_clock() {
780 let variant = StandardChess::default();
781 assert_eq!(variant.get_halfmove_clock(), 0);
782 }
783
784 #[test]
785 fn test_get_fullmove_number() {
786 let variant = StandardChess::default();
787 assert_eq!(variant.get_fullmove_number(), 1);
788 }
789
790 #[test]
791 fn test_get_starting_fen() {
792 let variant = StandardChess::default();
793 let starting_fen = variant.get_starting_fen();
794
795 assert_eq!(
796 starting_fen,
797 "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
798 );
799 }
800
801 #[test]
802 fn test_get_status() {
803 let variant = StandardChess::default();
804 assert_eq!(variant.get_status(), GameStatus::InProgress);
805 }
806}