Skip to main content

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}