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

            
42
#[test]
43
3
fn monte_carlo() {
44
3
    let mut tree = Tree::new(Game::new_game(BoardSize::_11, None));
45
3
    let depth = 80;
46
3
    let (loops, _plays) = tree.monte_carlo_tree_search(Duration::from_secs(1), depth);
47
3
    println!("{loops}");
48
3
}
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
3
fn flood_fill_1() -> anyhow::Result<()> {
61
3
    let board_1 = [
62
3
        "...........",
63
3
        ".........X.",
64
3
        "...........",
65
3
        "...........",
66
3
        "...........",
67
3
        "...........",
68
3
        "...........",
69
3
        ".....O.....",
70
3
        "....O.O....",
71
3
        "....O.O....",
72
3
        "....OKO....",
73
3
    ];
74

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

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

            
84
3
    Ok(())
85
3
}
86

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

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

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

            
112
3
    Ok(())
113
3
}
114

            
115
// One
116

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

            
122
3
    Ok(())
123
3
}
124

            
125
// Two
126

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

            
133
// Three
134

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

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

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

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

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

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

            
173
3
    Ok(())
174
3
}
175

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

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

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

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

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

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

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

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

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

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

            
243
3
    Ok(())
244
3
}
245

            
246
// Four
247

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

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

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

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

            
286
3
    Ok(())
287
3
}
288

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

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

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

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

            
327
3
    Ok(())
328
3
}
329

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

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

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

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

            
368
3
    Ok(())
369
3
}
370

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

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

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

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

            
410
3
    Ok(())
411
3
}
412

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

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

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

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

            
452
3
    Ok(())
453
3
}
454

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

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

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

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

            
493
3
    Ok(())
494
3
}
495

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

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

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

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

            
534
3
    Ok(())
535
3
}
536

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

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

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

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

            
575
3
    Ok(())
576
3
}
577

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

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

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

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

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

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

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

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

            
654
3
    Ok(())
655
3
}
656

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

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

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

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

            
700
3
    Ok(())
701
3
}
702

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

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

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

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

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

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

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

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

            
779
3
    Ok(())
780
3
}
781

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

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

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

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

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

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

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

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

            
856
3
    Ok(())
857
3
}
858

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

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

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

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

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

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

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

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

            
933
3
    Ok(())
934
3
}
935

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

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

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

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

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

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