1
// This file is part of hnefatafl-copenhagen.
2
//
3
// hnefatafl-copenhagen is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU Affero General Public License as published by
5
// the Free Software Foundation, either version 3 of the License, or
6
// (at your option) any later version.
7
//
8
// hnefatafl-copenhagen is distributed in the hope that it will be useful,
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
// GNU Affero General Public License for more details.
12
//
13
// You should have received a copy of the GNU Affero General Public License
14
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
15
//
16
// SPDX-License-Identifier: AGPL-3.0-or-later
17
// SPDX-FileCopyrightText: 2025 David Campbell <david@hnefatafl.org>
18

            
19
#![cfg(test)]
20

            
21
use std::{fmt, str::FromStr, time::Duration};
22

            
23
use crate::{
24
    ai::{AI, AiBanal},
25
    board::BoardSize,
26
    game_tree::Tree,
27
};
28

            
29
use super::*;
30
use board::{Board, STARTING_POSITION_11X11};
31
use game::Game;
32
use play::Vertex;
33
use role::Role;
34
use status::Status;
35

            
36
38
fn assert_error_str<T: fmt::Debug>(result: anyhow::Result<T>, string: &str) {
37
38
    if let Err(error) = result {
38
38
        assert_eq!(error.to_string(), string);
39
    }
40
38
}
41

            
42
#[test]
43
2
fn monte_carlo() {
44
2
    let mut tree = Tree::new(Game::new_game(BoardSize::_11, None));
45
2
    let depth = 80;
46
2
    let (loops, _plays) = tree.monte_carlo_tree_search(Duration::from_secs(1), depth);
47
2
    println!("{loops}");
48
2
}
49

            
50
#[ignore = "takes too long"]
51
#[test]
52
fn monte_carlo_long() {
53
    let mut tree = Tree::new(Game::new_game(BoardSize::_11, None));
54
    let depth = 40;
55
    let (loops, _plays) = tree.monte_carlo_tree_search(Duration::from_secs(10), depth);
56
    println!("{loops}");
57
}
58

            
59
#[test]
60
2
fn flood_fill_1() -> anyhow::Result<()> {
61
2
    let board_1 = [
62
2
        "...........",
63
2
        ".........X.",
64
2
        "...........",
65
2
        "...........",
66
2
        "...........",
67
2
        "...........",
68
2
        "...........",
69
2
        ".....O.....",
70
2
        "....O.O....",
71
2
        "....O.O....",
72
2
        "....OKO....",
73
2
    ];
74

            
75
2
    let game = game::Game {
76
2
        board: board_1.try_into()?,
77
2
        turn: Role::Defender,
78
2
        ..Default::default()
79
    };
80

            
81
2
    let vertex = Vertex::from_str("f1")?;
82
2
    assert!(game.board.flood_fill_defender_wins(&vertex));
83

            
84
2
    Ok(())
85
2
}
86

            
87
#[test]
88
2
fn flood_fill_2() -> anyhow::Result<()> {
89
2
    let board_1 = [
90
2
        "...........",
91
2
        ".........X.",
92
2
        "...........",
93
2
        "...........",
94
2
        "...........",
95
2
        "...........",
96
2
        "...........",
97
2
        "....OO.....",
98
2
        "....O......",
99
2
        "....O.O....",
100
2
        "....OKO....",
101
2
    ];
102

            
103
2
    let game = game::Game {
104
2
        board: board_1.try_into()?,
105
2
        turn: Role::Defender,
106
2
        ..Default::default()
107
    };
108

            
109
2
    let vertex = Vertex::from_str("f1")?;
110
2
    assert!(!game.board.flood_fill_defender_wins(&vertex));
111

            
112
2
    Ok(())
113
2
}
114

            
115
// One
116

            
117
#[test]
118
2
fn starting_position() -> anyhow::Result<()> {
119
2
    let game = Game::default();
120
2
    assert_eq!(game.board, STARTING_POSITION_11X11.try_into()?);
121

            
122
2
    Ok(())
123
2
}
124

            
125
// Two
126

            
127
#[test]
128
2
fn first_turn() {
129
2
    let game = Game::default();
130
2
    assert_eq!(game.turn, Role::Attacker);
131
2
}
132

            
133
// Three
134

            
135
#[test]
136
2
fn move_orthogonally_1() -> anyhow::Result<()> {
137
2
    let board = [
138
2
        "...X.......",
139
2
        "...........",
140
2
        "...........",
141
2
        "...........",
142
2
        "...........",
143
2
        "...........",
144
2
        "...........",
145
2
        "X..O......X",
146
2
        "...........",
147
2
        "...........",
148
2
        "...X.......",
149
2
    ];
150

            
151
2
    let mut game = game::Game {
152
2
        board: board.try_into()?,
153
2
        turn: Role::Defender,
154
2
        ..Default::default()
155
    };
156

            
157
2
    let mut result = game.read_line("play defender d4 d1");
158
2
    assert!(result.is_err());
159
2
    assert_error_str(result, "play: you have to play through empty locations");
160

            
161
2
    result = game.read_line("play defender d4 d11");
162
2
    assert!(result.is_err());
163
2
    assert_error_str(result, "play: you have to play through empty locations");
164

            
165
2
    result = game.read_line("play defender d4 a4");
166
2
    assert!(result.is_err());
167
2
    assert_error_str(result, "play: you have to play through empty locations");
168

            
169
2
    result = game.read_line("play defender d4 k4");
170
2
    assert!(result.is_err());
171
2
    assert_error_str(result, "play: you have to play through empty locations");
172

            
173
2
    Ok(())
174
2
}
175

            
176
#[test]
177
2
fn move_orthogonally_2() -> anyhow::Result<()> {
178
2
    let board = [
179
2
        "...........",
180
2
        "...........",
181
2
        "...........",
182
2
        "...........",
183
2
        "...........",
184
2
        "...........",
185
2
        "...........",
186
2
        "...O.......",
187
2
        "...........",
188
2
        "...........",
189
2
        "...........",
190
2
    ];
191

            
192
2
    let mut game = game::Game {
193
2
        board: board.try_into()?,
194
2
        turn: Role::Defender,
195
2
        ..Default::default()
196
    };
197

            
198
    // Play a junk move:
199
2
    let mut result = game.read_line("play defender junk d1");
200
2
    assert!(result.is_err());
201
2
    assert_error_str(result, "invalid digit found in string");
202

            
203
2
    result = game.read_line("play defender d4 junk");
204
2
    assert!(result.is_err());
205
2
    assert_error_str(result, "invalid digit found in string");
206

            
207
    // Diagonal play:
208
2
    result = game.read_line("play defender d4 a3");
209
2
    assert!(result.is_err());
210
2
    assert_error_str(result, "play: you can only play in a straight line");
211

            
212
    // Play out of bounds:
213
2
    result = game.read_line("play defender d4 m4");
214
2
    assert!(result.is_err());
215
2
    assert_error_str(result, "play: the first letter is not a legal char");
216

            
217
2
    result = game.read_line("play defender d4 d12");
218
2
    assert!(result.is_err());
219
2
    assert_error_str(result, "play: invalid coordinate");
220

            
221
2
    result = game.read_line("play defender d4 d0");
222
2
    assert!(result.is_err());
223
2
    assert_error_str(result, "play: invalid coordinate");
224

            
225
    // Don't move:
226
2
    result = game.read_line("play defender d4 d4");
227
2
    assert!(result.is_err());
228
2
    assert_error_str(result, "play: you have to change location");
229

            
230
    // Move all the way to the right:
231
2
    let mut game_1 = game.clone();
232
2
    game_1.read_line("play defender d4 a4")?;
233
    // Move all the way to the left:
234
2
    let mut game_2 = game.clone();
235
2
    game_2.read_line("play defender d4 k4")?;
236
    // Move all the way up:
237
2
    let mut game_3 = game.clone();
238
2
    game_3.read_line("play defender d4 d11")?;
239
    // Move all the way down:
240
2
    let mut game_4 = game.clone();
241
2
    game_4.read_line("play defender d4 d1")?;
242

            
243
2
    Ok(())
244
2
}
245

            
246
// Four
247

            
248
#[test]
249
2
fn sandwich_capture_1() -> anyhow::Result<()> {
250
2
    let board_1 = [
251
2
        "...........",
252
2
        "...........",
253
2
        "...........",
254
2
        "...........",
255
2
        "...........",
256
2
        "...X.......",
257
2
        "...O.......",
258
2
        ".XO.OX.....",
259
2
        "...........",
260
2
        "...X.......",
261
2
        "...........",
262
2
    ];
263

            
264
2
    let board_2 = [
265
2
        "...........",
266
2
        "...........",
267
2
        "...........",
268
2
        "...........",
269
2
        "...........",
270
2
        "...X.......",
271
2
        "...........",
272
2
        ".X.X.X.....",
273
2
        "...........",
274
2
        "...........",
275
2
        "...........",
276
2
    ];
277

            
278
2
    let mut game = game::Game {
279
2
        board: board_1.try_into()?,
280
2
        ..Default::default()
281
    };
282

            
283
2
    game.read_line("play attacker d2 d4")?;
284
2
    assert_eq!(game.board, board_2.try_into()?);
285

            
286
2
    Ok(())
287
2
}
288

            
289
#[test]
290
2
fn sandwich_capture_2() -> anyhow::Result<()> {
291
2
    let board_1 = [
292
2
        "...........",
293
2
        "...........",
294
2
        "...........",
295
2
        "...........",
296
2
        "...........",
297
2
        "...X.......",
298
2
        "...K.......",
299
2
        ".XO.OX.....",
300
2
        "...........",
301
2
        "...X.......",
302
2
        "...........",
303
2
    ];
304

            
305
2
    let board_2 = [
306
2
        "...........",
307
2
        "...........",
308
2
        "...........",
309
2
        "...........",
310
2
        "...........",
311
2
        "...X.......",
312
2
        "...K.......",
313
2
        ".X.X.X.....",
314
2
        "...........",
315
2
        "...........",
316
2
        "...........",
317
2
    ];
318

            
319
2
    let mut game = game::Game {
320
2
        board: board_1.try_into()?,
321
2
        ..Default::default()
322
    };
323

            
324
2
    game.read_line("play attacker d2 d4")?;
325
2
    assert_eq!(game.board, board_2.try_into()?);
326

            
327
2
    Ok(())
328
2
}
329

            
330
#[test]
331
2
fn sandwich_capture_3() -> anyhow::Result<()> {
332
2
    let board_1 = [
333
2
        "...........",
334
2
        "...........",
335
2
        "...........",
336
2
        "...........",
337
2
        "...........",
338
2
        "...........",
339
2
        ".....O.....",
340
2
        ".X.........",
341
2
        "...........",
342
2
        "...........",
343
2
        "...........",
344
2
    ];
345

            
346
2
    let board_2 = [
347
2
        "...........",
348
2
        "...........",
349
2
        "...........",
350
2
        "...........",
351
2
        "...........",
352
2
        "...........",
353
2
        "...........",
354
2
        ".....X.....",
355
2
        "...........",
356
2
        "...........",
357
2
        "...........",
358
2
    ];
359

            
360
2
    let mut game = game::Game {
361
2
        board: board_1.try_into()?,
362
2
        ..Default::default()
363
    };
364

            
365
2
    game.read_line("play attacker b4 f4")?;
366
2
    assert_eq!(game.board, board_2.try_into()?);
367

            
368
2
    Ok(())
369
2
}
370

            
371
#[test]
372
2
fn sandwich_capture_4() -> anyhow::Result<()> {
373
2
    let board_1 = [
374
2
        "...........",
375
2
        "...........",
376
2
        "...........",
377
2
        "...........",
378
2
        "...........",
379
2
        "..K........",
380
2
        "...........",
381
2
        "...........",
382
2
        "..X........",
383
2
        "..O........",
384
2
        "...........",
385
2
    ];
386

            
387
2
    let board_2 = [
388
2
        "...........",
389
2
        "...........",
390
2
        "...........",
391
2
        "...........",
392
2
        "...........",
393
2
        "...........",
394
2
        "...........",
395
2
        "..K........",
396
2
        "...........",
397
2
        "..O........",
398
2
        "...........",
399
2
    ];
400

            
401
2
    let mut game = game::Game {
402
2
        board: board_1.try_into()?,
403
2
        turn: Role::Defender,
404
2
        ..Default::default()
405
    };
406

            
407
2
    game.read_line("play defender c6 c4")?;
408
2
    assert_eq!(game.board, board_2.try_into()?);
409

            
410
2
    Ok(())
411
2
}
412

            
413
#[test]
414
2
fn sandwich_capture_5() -> anyhow::Result<()> {
415
2
    let board_1 = [
416
2
        "...........",
417
2
        "...........",
418
2
        "...........",
419
2
        "...........",
420
2
        "...........",
421
2
        ".....K.....",
422
2
        ".....X.....",
423
2
        ".O.........",
424
2
        "...........",
425
2
        "...........",
426
2
        "...........",
427
2
    ];
428

            
429
2
    let board_2 = [
430
2
        "...........",
431
2
        "...........",
432
2
        "...........",
433
2
        "...........",
434
2
        "...........",
435
2
        ".....K.....",
436
2
        "...........",
437
2
        ".....O.....",
438
2
        "...........",
439
2
        "...........",
440
2
        "...........",
441
2
    ];
442

            
443
2
    let mut game = game::Game {
444
2
        board: board_1.try_into()?,
445
2
        turn: Role::Defender,
446
2
        ..Default::default()
447
    };
448

            
449
2
    game.read_line("play defender b4 f4")?;
450
2
    assert_eq!(game.board, board_2.try_into()?);
451

            
452
2
    Ok(())
453
2
}
454

            
455
#[test]
456
2
fn sandwich_capture_6() -> anyhow::Result<()> {
457
2
    let board_1 = [
458
2
        ".O.........",
459
2
        "...........",
460
2
        "..X........",
461
2
        "...........",
462
2
        "...........",
463
2
        "...........",
464
2
        "...........",
465
2
        "...........",
466
2
        "...........",
467
2
        "...........",
468
2
        "...........",
469
2
    ];
470

            
471
2
    let board_2 = [
472
2
        "..X........",
473
2
        "...........",
474
2
        "...........",
475
2
        "...........",
476
2
        "...........",
477
2
        "...........",
478
2
        "...........",
479
2
        "...........",
480
2
        "...........",
481
2
        "...........",
482
2
        "...........",
483
2
    ];
484

            
485
2
    let mut game = game::Game {
486
2
        board: board_1.try_into()?,
487
2
        ..Default::default()
488
    };
489

            
490
2
    game.read_line("play attacker c9 c11")?;
491
2
    assert_eq!(game.board, board_2.try_into()?);
492

            
493
2
    Ok(())
494
2
}
495

            
496
#[test]
497
2
fn sandwich_capture_7() -> anyhow::Result<()> {
498
2
    let board_1 = [
499
2
        "...........",
500
2
        "...........",
501
2
        "...........",
502
2
        "...........",
503
2
        "...........",
504
2
        ".....K.....",
505
2
        ".....O.....",
506
2
        ".X.........",
507
2
        "...........",
508
2
        "...........",
509
2
        "...........",
510
2
    ];
511

            
512
2
    let board_2 = [
513
2
        "...........",
514
2
        "...........",
515
2
        "...........",
516
2
        "...........",
517
2
        "...........",
518
2
        ".....K.....",
519
2
        ".....O.....",
520
2
        ".....X.....",
521
2
        "...........",
522
2
        "...........",
523
2
        "...........",
524
2
    ];
525

            
526
2
    let mut game = game::Game {
527
2
        board: board_1.try_into()?,
528
2
        ..Default::default()
529
    };
530

            
531
2
    game.read_line("play attacker b4 f4")?;
532
2
    assert_eq!(game.board, board_2.try_into()?);
533

            
534
2
    Ok(())
535
2
}
536

            
537
#[test]
538
2
fn sandwich_capture_8() -> anyhow::Result<()> {
539
2
    let board_1 = [
540
2
        "...........",
541
2
        "...........",
542
2
        "...........",
543
2
        "...........",
544
2
        "...........",
545
2
        "...........",
546
2
        ".O.O.......",
547
2
        "...........",
548
2
        "..X........",
549
2
        "...........",
550
2
        "...........",
551
2
    ];
552

            
553
2
    let board_2 = [
554
2
        "...........",
555
2
        "...........",
556
2
        "...........",
557
2
        "...........",
558
2
        "...........",
559
2
        "...........",
560
2
        ".OXO.......",
561
2
        "...........",
562
2
        "...........",
563
2
        "...........",
564
2
        "...........",
565
2
    ];
566

            
567
2
    let mut game = game::Game {
568
2
        board: board_1.try_into()?,
569
2
        ..Default::default()
570
    };
571

            
572
2
    game.read_line("play attacker c3 c5")?;
573
2
    assert_eq!(game.board, board_2.try_into()?);
574

            
575
2
    Ok(())
576
2
}
577

            
578
#[test]
579
2
fn shield_wall_1() -> anyhow::Result<()> {
580
2
    let board_1 = [
581
2
        "...........",
582
2
        "...........",
583
2
        "...........",
584
2
        "...........",
585
2
        "...........",
586
2
        "...........",
587
2
        "...........",
588
2
        "...........",
589
2
        "..O........",
590
2
        "...OOO.....",
591
2
        "...XXXO....",
592
2
    ];
593

            
594
2
    let board_2 = [
595
2
        "...........",
596
2
        "...........",
597
2
        "...........",
598
2
        "...........",
599
2
        "...........",
600
2
        "...........",
601
2
        "...........",
602
2
        "...........",
603
2
        "...........",
604
2
        "...OOO.....",
605
2
        "..O...O....",
606
2
    ];
607

            
608
2
    let mut game_1 = game::Game {
609
2
        board: board_1.try_into()?,
610
2
        turn: Role::Defender,
611
2
        ..Default::default()
612
    };
613

            
614
2
    game_1.read_line("play defender c3 c1")?;
615
2
    assert_eq!(game_1.board, board_2.try_into()?);
616

            
617
2
    let board_3 = [
618
2
        "...XXXO....",
619
2
        "...OOO.....",
620
2
        "..O........",
621
2
        "...........",
622
2
        "...........",
623
2
        "...........",
624
2
        "...........",
625
2
        "...........",
626
2
        "...........",
627
2
        "...........",
628
2
        "...........",
629
2
    ];
630

            
631
2
    let board_4 = [
632
2
        "..O...O....",
633
2
        "...OOO.....",
634
2
        "...........",
635
2
        "...........",
636
2
        "...........",
637
2
        "...........",
638
2
        "...........",
639
2
        "...........",
640
2
        "...........",
641
2
        "...........",
642
2
        "...........",
643
2
    ];
644

            
645
2
    let mut game_2 = game::Game {
646
2
        board: board_3.try_into()?,
647
2
        turn: Role::Defender,
648
2
        ..Default::default()
649
    };
650

            
651
2
    game_2.read_line("play defender c9 c11")?;
652
2
    assert_eq!(game_2.board, board_4.try_into()?);
653

            
654
2
    Ok(())
655
2
}
656

            
657
#[test]
658
2
fn shield_wall_1_13() -> anyhow::Result<()> {
659
2
    let board_1 = [
660
2
        "...XXXO......",
661
2
        "...OOO.......",
662
2
        "..O..........",
663
2
        ".............",
664
2
        ".............",
665
2
        ".............",
666
2
        ".............",
667
2
        ".............",
668
2
        ".............",
669
2
        ".............",
670
2
        ".............",
671
2
        ".............",
672
2
        ".............",
673
2
    ];
674

            
675
2
    let board_2 = [
676
2
        "..O...O......",
677
2
        "...OOO.......",
678
2
        ".............",
679
2
        ".............",
680
2
        ".............",
681
2
        ".............",
682
2
        ".............",
683
2
        ".............",
684
2
        ".............",
685
2
        ".............",
686
2
        ".............",
687
2
        ".............",
688
2
        ".............",
689
2
    ];
690

            
691
2
    let mut game_1 = game::Game {
692
2
        board: board_1.try_into()?,
693
2
        turn: Role::Defender,
694
2
        ..Default::default()
695
    };
696

            
697
2
    game_1.read_line("play defender C11 C13")?;
698
2
    assert_eq!(game_1.board, board_2.try_into()?);
699

            
700
2
    Ok(())
701
2
}
702

            
703
#[test]
704
2
fn shield_wall_2() -> anyhow::Result<()> {
705
2
    let board_1 = [
706
2
        "...........",
707
2
        "...........",
708
2
        "...........",
709
2
        "...........",
710
2
        "..O........",
711
2
        "XO.........",
712
2
        "XO.........",
713
2
        "XO.........",
714
2
        "O..........",
715
2
        "...........",
716
2
        "...........",
717
2
    ];
718

            
719
2
    let board_2 = [
720
2
        "...........",
721
2
        "...........",
722
2
        "...........",
723
2
        "...........",
724
2
        "O..........",
725
2
        ".O.........",
726
2
        ".O.........",
727
2
        ".O.........",
728
2
        "O..........",
729
2
        "...........",
730
2
        "...........",
731
2
    ];
732

            
733
2
    let mut game_1 = game::Game {
734
2
        board: board_1.try_into()?,
735
2
        turn: Role::Defender,
736
2
        ..Default::default()
737
    };
738

            
739
2
    game_1.read_line("play defender c7 a7")?;
740
2
    assert_eq!(game_1.board, board_2.try_into()?);
741

            
742
2
    let board_3 = [
743
2
        "...........",
744
2
        "...........",
745
2
        "...........",
746
2
        "...........",
747
2
        "........O..",
748
2
        ".........OX",
749
2
        ".........OX",
750
2
        ".........OX",
751
2
        "..........O",
752
2
        "...........",
753
2
        "...........",
754
2
    ];
755

            
756
2
    let board_4 = [
757
2
        "...........",
758
2
        "...........",
759
2
        "...........",
760
2
        "...........",
761
2
        "..........O",
762
2
        ".........O.",
763
2
        ".........O.",
764
2
        ".........O.",
765
2
        "..........O",
766
2
        "...........",
767
2
        "...........",
768
2
    ];
769

            
770
2
    let mut game_2 = game::Game {
771
2
        board: board_3.try_into()?,
772
2
        turn: Role::Defender,
773
2
        ..Default::default()
774
    };
775

            
776
2
    game_2.read_line("play defender i7 k7")?;
777
2
    assert_eq!(game_2.board, board_4.try_into()?);
778

            
779
2
    Ok(())
780
2
}
781

            
782
#[test]
783
2
fn shield_wall_3() -> anyhow::Result<()> {
784
2
    let board_1 = [
785
2
        "...........",
786
2
        "...........",
787
2
        "...........",
788
2
        "...........",
789
2
        "...........",
790
2
        "...........",
791
2
        "...........",
792
2
        "...........",
793
2
        "...........",
794
2
        "........XX.",
795
2
        ".....X..OK.",
796
2
    ];
797

            
798
2
    let board_2 = [
799
2
        "...........",
800
2
        "...........",
801
2
        "...........",
802
2
        "...........",
803
2
        "...........",
804
2
        "...........",
805
2
        "...........",
806
2
        "...........",
807
2
        "...........",
808
2
        "........XX.",
809
2
        ".......X.K.",
810
2
    ];
811

            
812
2
    let mut game_1 = game::Game {
813
2
        board: board_1.try_into()?,
814
2
        ..Default::default()
815
    };
816

            
817
2
    game_1.read_line("play attacker f1 h1")?;
818
2
    assert_eq!(game_1.board, board_2.try_into()?);
819

            
820
2
    let board_3 = [
821
2
        "...........",
822
2
        "...........",
823
2
        "...........",
824
2
        "...........",
825
2
        "...........",
826
2
        "...........",
827
2
        "...........",
828
2
        "...........",
829
2
        "...........",
830
2
        ".XX........",
831
2
        ".KO..X.....",
832
2
    ];
833

            
834
2
    let board_4 = [
835
2
        "...........",
836
2
        "...........",
837
2
        "...........",
838
2
        "...........",
839
2
        "...........",
840
2
        "...........",
841
2
        "...........",
842
2
        "...........",
843
2
        "...........",
844
2
        ".XX........",
845
2
        ".K.X.......",
846
2
    ];
847

            
848
2
    let mut game_2 = game::Game {
849
2
        board: board_3.try_into()?,
850
2
        ..Default::default()
851
    };
852

            
853
2
    game_2.read_line("play attacker f1 d1")?;
854
2
    assert_eq!(game_2.board, board_4.try_into()?);
855

            
856
2
    Ok(())
857
2
}
858

            
859
#[test]
860
2
fn shield_wall_4() -> anyhow::Result<()> {
861
2
    let board_1 = [
862
2
        ".....X..OK.",
863
2
        "........XX.",
864
2
        "...........",
865
2
        "...........",
866
2
        "...........",
867
2
        "...........",
868
2
        "...........",
869
2
        "...........",
870
2
        "...........",
871
2
        "...........",
872
2
        "...........",
873
2
    ];
874

            
875
2
    let board_2 = [
876
2
        ".......X.K.",
877
2
        "........XX.",
878
2
        "...........",
879
2
        "...........",
880
2
        "...........",
881
2
        "...........",
882
2
        "...........",
883
2
        "...........",
884
2
        "...........",
885
2
        "...........",
886
2
        "...........",
887
2
    ];
888

            
889
2
    let mut game_1 = game::Game {
890
2
        board: board_1.try_into()?,
891
2
        ..Default::default()
892
    };
893

            
894
2
    game_1.read_line("play attacker f11 h11")?;
895
2
    assert_eq!(game_1.board, board_2.try_into()?);
896

            
897
2
    let board_3 = [
898
2
        ".KO..X.....",
899
2
        ".XX........",
900
2
        "...........",
901
2
        "...........",
902
2
        "...........",
903
2
        "...........",
904
2
        "...........",
905
2
        "...........",
906
2
        "...........",
907
2
        "...........",
908
2
        "...........",
909
2
    ];
910

            
911
2
    let board_4 = [
912
2
        ".K.X.......",
913
2
        ".XX........",
914
2
        "...........",
915
2
        "...........",
916
2
        "...........",
917
2
        "...........",
918
2
        "...........",
919
2
        "...........",
920
2
        "...........",
921
2
        "...........",
922
2
        "...........",
923
2
    ];
924

            
925
2
    let mut game_2 = game::Game {
926
2
        board: board_3.try_into()?,
927
2
        ..Default::default()
928
    };
929

            
930
2
    game_2.read_line("play attacker f11 d11")?;
931
2
    assert_eq!(game_2.board, board_4.try_into()?);
932

            
933
2
    Ok(())
934
2
}
935

            
936
#[test]
937
2
fn shield_wall_5() -> anyhow::Result<()> {
938
2
    let board_1 = [
939
2
        "...........",
940
2
        "...........",
941
2
        "...........",
942
2
        "...........",
943
2
        "...........",
944
2
        "X..........",
945
2
        "...........",
946
2
        "...........",
947
2
        "OX.........",
948
2
        "KX.........",
949
2
        "...........",
950
2
    ];
951

            
952
2
    let board_2 = [
953
2
        "...........",
954
2
        "...........",
955
2
        "...........",
956
2
        "...........",
957
2
        "...........",
958
2
        "...........",
959
2
        "...........",
960
2
        "X..........",
961
2
        ".X.........",
962
2
        "KX.........",
963
2
        "...........",
964
2
    ];
965

            
966
2
    let mut game_1 = game::Game {
967
2
        board: board_1.try_into()?,
968
2
        ..Default::default()
969
    };
970

            
971
2
    game_1.read_line("play attacker a6 a4")?;
972
2
    assert_eq!(game_1.board, board_2.try_into()?);
973

            
974
2
    let board_3 = [
975
2
        "...........",
976
2
        "KX.........",
977
2
        "OX.........",
978
2
        "...........",
979
2
        "...........",
980
2
        "X..........",
981
2
        "...........",
982
2
        "...........",
983
2
        "...........",
984
2
        "...........",
985
2
        "...........",
986
2
    ];
987

            
988
2
    let board_4 = [
989
2
        "...........",
990
2
        "KX.........",
991
2
        ".X.........",
992
2
        "X..........",
993
2
        "...........",
994
2
        "...........",
995
2
        "...........",
996
2
        "...........",
997
2
        "...........",
998
2
        "...........",
999
2
        "...........",
2
    ];
2
    let mut game_2 = game::Game {
2
        board: board_3.try_into()?,
2
        ..Default::default()
    };
2
    game_2.read_line("play attacker a6 a8")?;
2
    assert_eq!(game_2.board, board_4.try_into()?);
2
    Ok(())
2
}
#[test]
2
fn shield_wall_6() -> anyhow::Result<()> {
2
    let board_1 = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "..........X",
2
        "...........",
2
        "...........",
2
        ".........XO",
2
        ".........XK",
2
        "...........",
2
    ];
2
    let board_2 = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "..........X",
2
        ".........X.",
2
        ".........XK",
2
        "...........",
2
    ];
2
    let mut game_1 = game::Game {
2
        board: board_1.try_into()?,
2
        ..Default::default()
    };
2
    game_1.read_line("play attacker k6 k4")?;
2
    assert_eq!(game_1.board, board_2.try_into()?);
2
    let board_3 = [
2
        "...........",
2
        ".........XK",
2
        ".........XO",
2
        "...........",
2
        "...........",
2
        "..........X",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let board_4 = [
2
        "...........",
2
        ".........XK",
2
        ".........X.",
2
        "..........X",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let mut game_2 = game::Game {
2
        board: board_3.try_into()?,
2
        ..Default::default()
    };
2
    game_2.read_line("play attacker k6 k8")?;
2
    assert_eq!(game_2.board, board_4.try_into()?);
2
    Ok(())
2
}
#[test]
2
fn shield_wall_7() -> anyhow::Result<()> {
2
    let board_1 = [
2
        "...........",
2
        "........X.O",
2
        "..........X",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let board_2 = [
2
        "...........",
2
        ".........XO",
2
        "..........X",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let mut game = game::Game {
2
        board: board_1.try_into()?,
2
        ..Default::default()
    };
2
    game.read_line("play attacker i10 j10")?;
2
    assert_eq!(game.board, board_2.try_into()?);
2
    let board_3 = [
2
        "...........",
2
        "..........X",
2
        "........X.O",
2
        "..........X",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let board_4 = [
2
        "...........",
2
        "..........X",
2
        ".........XO",
2
        "..........X",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let mut game = game::Game {
2
        board: board_3.try_into()?,
2
        ..Default::default()
    };
2
    game.read_line("play attacker i9 j9")?;
2
    assert_eq!(game.board, board_4.try_into()?);
2
    Ok(())
2
}
#[test]
2
fn shield_wall_nope() -> anyhow::Result<()> {
2
    let board_1 = [
2
        "...........",
2
        "........X.O",
2
        ".........XO",
2
        "..........X",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let board_2 = [
2
        "...........",
2
        ".........XO",
2
        ".........XO",
2
        "..........X",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let mut game = game::Game {
2
        board: board_1.try_into()?,
2
        ..Default::default()
    };
2
    game.read_line("play attacker i10 j10")?;
2
    assert_eq!(game.board, board_2.try_into()?);
2
    Ok(())
2
}
// Five
#[test]
2
fn kings_1() {
2
    let board = [
2
        "KK.........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let result: anyhow::Result<Board> = board.try_into();
2
    assert!(result.is_err());
2
    assert_error_str(result, "You can only have one king!");
2
}
#[test]
2
fn kings_2() -> anyhow::Result<()> {
2
    let board = [
2
        ".X.........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        ..Default::default()
    };
2
    let result = game.read_line("play attacker b11 a11");
2
    assert!(result.is_err());
2
    assert_error_str(
2
        result,
2
        "play: only the king may move to a restricted square",
    );
2
    Ok(())
2
}
#[test]
2
fn kings_3() -> anyhow::Result<()> {
2
    let board_1 = [
2
        "K..........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let _board: Board = board_1.try_into()?;
2
    let board_2 = [
2
        "X..........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let result: anyhow::Result<Board> = board_2.try_into();
2
    assert!(result.is_err());
2
    assert_error_str(result, "Only the king is allowed on restricted squares!");
2
    Ok(())
2
}
#[test]
2
fn kings_4() -> anyhow::Result<()> {
2
    let board_1 = [
2
        "..........K",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let _board: Board = board_1.try_into()?;
2
    let board_2 = [
2
        "..........X",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let result: anyhow::Result<Board> = board_2.try_into();
2
    assert!(result.is_err());
2
    assert_error_str(result, "Only the king is allowed on restricted squares!");
2
    Ok(())
2
}
#[test]
2
fn kings_5() -> anyhow::Result<()> {
2
    let board_1 = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        ".....K.....",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let _board: Board = board_1.try_into()?;
2
    let board_2 = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        ".....X.....",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let result: anyhow::Result<Board> = board_2.try_into();
2
    assert!(result.is_err());
2
    assert_error_str(result, "Only the king is allowed on restricted squares!");
2
    Ok(())
2
}
#[test]
2
fn kings_6() -> anyhow::Result<()> {
2
    let board_1 = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "K..........",
2
    ];
2
    let _board: Board = board_1.try_into()?;
2
    let board_2 = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "X..........",
2
    ];
2
    let result: anyhow::Result<Board> = board_2.try_into();
2
    assert!(result.is_err());
2
    assert_error_str(result, "Only the king is allowed on restricted squares!");
2
    Ok(())
2
}
#[test]
2
fn kings_7() -> anyhow::Result<()> {
2
    let board_1 = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "..........K",
2
    ];
2
    let _board: Board = board_1.try_into()?;
2
    let board_2 = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "..........X",
2
    ];
2
    let result: anyhow::Result<Board> = board_2.try_into();
2
    assert!(result.is_err());
2
    assert_error_str(result, "Only the king is allowed on restricted squares!");
2
    Ok(())
2
}
// Six
#[test]
2
fn defender_wins_exit() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        ".....K.....",
2
    ];
2
    let mut game_1 = game::Game {
2
        board: board.try_into()?,
2
        turn: Role::Defender,
2
        ..Default::default()
    };
2
    let mut game_2 = game_1.clone();
2
    game_1.read_line("play defender f1 k1")?;
2
    assert_eq!(game_1.status, Status::DefenderWins);
2
    game_2.read_line("play defender f1 a1")?;
2
    assert_eq!(game_2.status, Status::DefenderWins);
2
    let board = [
2
        ".....K.....",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let mut game_1 = game::Game {
2
        board: board.try_into()?,
2
        turn: Role::Defender,
2
        ..Default::default()
    };
2
    let mut game_2 = game_1.clone();
2
    game_1.read_line("play defender f11 k11")?;
2
    assert_eq!(game_1.status, Status::DefenderWins);
2
    game_2.read_line("play defender f11 a11")?;
2
    assert_eq!(game_2.status, Status::DefenderWins);
2
    Ok(())
2
}
#[test]
2
fn defender_wins_escape_fort_1() -> anyhow::Result<()> {
2
    let board = [
2
        "....O.O....",
2
        "....OKO....",
2
        "....OO.....",
2
        "....XX.....",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        turn: Role::Defender,
2
        ..Default::default()
    };
2
    game.read_line("play defender f10 f11")?;
2
    assert_eq!(game.status, Status::DefenderWins);
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "....XX.....",
2
        "....OO.....",
2
        "....OKO....",
2
        "....O.O....",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        turn: Role::Defender,
2
        ..Default::default()
    };
2
    game.read_line("play defender f2 f1")?;
2
    assert_eq!(game.status, Status::DefenderWins);
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "OOOX.......",
2
        ".KOX.......",
2
        "OO.........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        turn: Role::Defender,
2
        ..Default::default()
    };
2
    game.read_line("play defender b6 a6")?;
2
    assert_eq!(game.status, Status::DefenderWins);
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        ".......XOOO",
2
        ".......XOK.",
2
        ".........OO",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        turn: Role::Defender,
2
        ..Default::default()
    };
2
    game.read_line("play defender j6 k6")?;
2
    assert_eq!(game.status, Status::DefenderWins);
2
    Ok(())
2
}
#[test]
2
fn defender_wins_escape_fort_1_13() -> anyhow::Result<()> {
2
    let board = [
2
        "....OKO......",
2
        "....O........",
2
        "....OOO......",
2
        "....XX.......",
2
        ".............",
2
        ".............",
2
        ".............",
2
        ".............",
2
        ".............",
2
        ".............",
2
        ".............",
2
        ".............",
2
        ".............",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        turn: Role::Defender,
2
        ..Default::default()
    };
2
    game.read_line("play defender G11 G12")?;
2
    assert_eq!(game.status, Status::DefenderWins);
2
    Ok(())
2
}
#[test]
2
fn defender_wins_escape_fort_2() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "........XOO",
2
        "........OK.",
2
        ".......X.OO",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        turn: Role::Defender,
2
        ..Default::default()
    };
2
    game.read_line("play defender j6 k6")?;
2
    assert_eq!(game.status, Status::Ongoing);
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "........XOO",
2
        "........OK.",
2
        ".........OO",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        turn: Role::Defender,
2
        ..Default::default()
    };
2
    game.read_line("play defender j6 k6")?;
2
    assert_eq!(game.status, Status::DefenderWins);
2
    Ok(())
2
}
#[test]
2
fn defender_wins_escape_fort_3() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "........X.O",
2
        ".........O.",
2
        ".......X.OK",
2
        "..........O",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        turn: Role::Defender,
2
        ..Default::default()
    };
2
    game.read_line("play defender k5 k6")?;
2
    assert_eq!(game.status, Status::DefenderWins);
2
    Ok(())
2
}
// Seven
#[test]
2
fn kings_not_captured() -> anyhow::Result<()> {
2
    let board_1 = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        ".....X.....",
2
        "...........",
2
        ".....KX....",
2
        ".....X.....",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let board_2 = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        ".....X.....",
2
        ".....KX....",
2
        ".....X.....",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ]
2
    .try_into()?;
2
    let mut game = game::Game {
2
        board: board_1.try_into()?,
2
        ..Default::default()
    };
2
    game.read_line("play attacker f8 f7")?;
2
    assert_eq!(game.board, board_2);
2
    Ok(())
2
}
#[test]
2
fn kings_captured_1() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        ".....X.....",
2
        "...........",
2
        "....XKX....",
2
        ".....X.....",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        ..Default::default()
    };
2
    game.read_line("play attacker f8 f7")?;
2
    assert_eq!(game.status, Status::AttackerWins);
2
    Ok(())
2
}
#[test]
2
fn kings_captured_2() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "....XKX....",
2
        "...........",
2
        ".....X.....",
2
        "...........",
2
        "...........",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        ..Default::default()
    };
2
    game.read_line("play attacker f3 f4")?;
2
    assert_eq!(game.status, Status::AttackerWins);
2
    Ok(())
2
}
#[test]
2
fn kings_captured_3() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "....X......",
2
        "...XKX.....",
2
        "...........",
2
        "....X......",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        ..Default::default()
    };
2
    game.read_line("play attacker e1 e2")?;
2
    assert_eq!(game.status, Status::AttackerWins);
2
    Ok(())
2
}
#[test]
2
fn kings_captured_4() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        ".O.........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "X..........",
2
        "K.X........",
2
        "X..........",
2
        "...........",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        ..Default::default()
    };
2
    game.read_line("play attacker c3 b3")?;
2
    assert_eq!(game.status, Status::Ongoing);
2
    Ok(())
2
}
#[test]
2
fn kings_captured_5() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "X..........",
2
        "K.X........",
2
        "...........",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        ..Default::default()
    };
2
    game.read_line("play attacker c2 b2")?;
2
    assert_eq!(game.status, Status::Ongoing);
2
    Ok(())
2
}
#[test]
2
fn kings_captured_surround_1() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        ".....XXX...",
2
        "....X...XX.",
2
        ".X...O....X",
2
        "..X.......X",
2
        ".X.O...O..X",
2
        ".X..OK...X.",
2
        "..X...O.X..",
2
        "...XXX.X...",
2
        "......X....",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        ..Default::default()
    };
2
    game.read_line("play attacker b7 c7")?;
2
    assert_eq!(game.status, Status::Ongoing);
2
    game.read_line("play defender f7 g7")?;
2
    assert_eq!(game.status, Status::Ongoing);
2
    game.read_line("play attacker c7 d7")?;
2
    assert_eq!(game.status, Status::AttackerWins);
2
    Ok(())
2
}
#[test]
2
fn kings_captured_surround_2() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...O.......",
2
        ".....XXX...",
2
        "....X...XX.",
2
        "..X..O....X",
2
        "..X.......X",
2
        ".X.O...O..X",
2
        ".X..OK...X.",
2
        "..X...O.X..",
2
        "...XXX.X...",
2
        "......X....",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        ..Default::default()
    };
2
    game.read_line("play attacker c7 d7")?;
2
    assert_eq!(game.status, Status::Ongoing);
2
    Ok(())
2
}
// Eight
#[test]
2
fn can_not_repeat_moves() -> anyhow::Result<()> {
2
    let mut game = Game::default();
2
    game.read_line("play attacker f2 f3")?;
2
    game.read_line("play defender f4 g4")?;
2
    game.read_line("play attacker f3 f2")?;
2
    let result = game.read_line("play defender g4 f4");
2
    assert!(result.is_err());
2
    assert_error_str(result, "play: you already reached that position");
2
    Ok(())
2
}
// Nine
#[test]
2
fn attacker_automatically_loses() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        ".....K.....",
2
        ".....X.....",
2
        "...........",
2
        ".....O.....",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        turn: Role::Defender,
2
        ..Default::default()
    };
2
    game.read_line("play defender f1 f2")?;
2
    assert_eq!(game.status, Status::DefenderWins);
2
    Ok(())
2
}
#[test]
2
fn defender_automatically_loses_1() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        ".....X.....",
2
        ".X..XKX....",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        ..Default::default()
    };
2
    game.read_line("play attacker b1 b2")?;
2
    assert_eq!(game.status, Status::AttackerWins);
2
    Ok(())
2
}
#[test]
2
fn defender_automatically_loses_2() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        ".....X.....",
2
        ".X..X.X....",
2
        "....XKX....",
2
    ];
2
    let mut game = game::Game {
2
        board: board.try_into()?,
2
        ..Default::default()
    };
2
    game.read_line("play attacker b2 b1")?;
2
    game.read_line("play defender f1 f2")?;
2
    game.read_line("play attacker b1 b2")?;
2
    game.read_line("play defender f2 f1")?;
2
    game.read_line("play attacker b2 b1")?;
2
    assert_eq!(game.status, Status::AttackerWins);
2
    Ok(())
2
}
#[test]
2
fn exit_one_1() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        ".X...K...X.",
2
    ];
2
    let game = game::Game {
2
        board: board.try_into()?,
2
        turn: Role::Defender,
2
        ..Default::default()
    };
2
    assert!(!game.exit_one());
2
    Ok(())
2
}
#[test]
2
fn exit_one_2() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        ".....K.....",
2
    ];
2
    let game = game::Game {
2
        board: board.try_into()?,
2
        turn: Role::Defender,
2
        ..Default::default()
    };
2
    assert!(game.exit_one());
2
    Ok(())
2
}
#[test]
2
fn exit_one_3() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        ".....K.....",
2
        "...........",
2
    ];
2
    let game = game::Game {
2
        board: board.try_into()?,
2
        turn: Role::Defender,
2
        ..Default::default()
    };
2
    assert!(!game.exit_one());
2
    Ok(())
2
}
#[test]
2
fn exit_one_4() -> anyhow::Result<()> {
2
    let board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        ".....K.....",
2
    ];
2
    let game = game::Game {
2
        board: board.try_into()?,
2
        ..Default::default()
    };
2
    assert!(!game.exit_one());
2
    Ok(())
2
}
#[test]
2
fn closed_off_exits() -> anyhow::Result<()> {
2
    let board: Board = [
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "X..........",
2
        ".X.........",
2
        "..X..K.....",
2
    ]
2
    .try_into()?;
2
    assert_eq!(board.closed_off_exits(), 1);
2
    let board: Board = [
2
        "..X....X...",
2
        ".X......X..",
2
        "X........X.",
2
        "X.........X",
2
        "X..........",
2
        "X..........",
2
        "X..........",
2
        "X..........",
2
        "X.........X",
2
        ".X.......X.",
2
        "..X..K..X..",
2
    ]
2
    .try_into()?;
2
    assert_eq!(board.closed_off_exits(), 4);
2
    let board: Board = [
2
        ".XX.....XX.",
2
        "X.........X",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "X.........X",
2
        ".XX..K..XX.",
2
    ]
2
    .try_into()?;
2
    assert_eq!(board.closed_off_exits(), 0);
2
    let board: Board = [
2
        ".X.......X.",
2
        "X.........X",
2
        "X.........X",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "X.........X",
2
        "X.........X",
2
        ".X...K...X.",
2
    ]
2
    .try_into()?;
2
    assert_eq!(board.closed_off_exits(), 0);
2
    let board: Board = [
2
        ".XX.....XX.",
2
        "X.........X",
2
        "X.........X",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "...........",
2
        "X.........X",
2
        "X.........X",
2
        ".XX..K..XX.",
2
    ]
2
    .try_into()?;
2
    assert_eq!(board.closed_off_exits(), 4);
2
    Ok(())
2
}
#[test]
2
fn someone_wins() {
2
    let mut game = Game::default();
2
    let mut ai: Box<dyn AI> = Box::new(AiBanal);
    loop {
        // Do nothing but play.
244
        if ai.generate_move(&mut game).is_err() {
2
            break;
242
        }
    }
2
    assert!(game.status == Status::AttackerWins || game.status == Status::DefenderWins);
2
}