Initial commit: terminal Minesweeper in C# for .NET 10
A playable console Minesweeper (arrow keys, chording, flags, question marks, pause, difficulty presets) plus a deduction-and-guess solver that can play the game headlessly. Game logic lives in src/Minesweeper/Game and has no console dependencies, so it is covered by 65 unit tests. Includes publishing helpers for self-contained, trimmed single-file binaries (publish.sh) and an .editorconfig that the sources conform to: UTF-8 BOM and 4-space indents for C#, 2-space indents for project files, LF endings and 2-space indents for shell scripts, System-first usings, no redundant `this.`, and s_/ _ prefixed private static and instance fields.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
using Minesweeper.Game;
|
||||
using Xunit;
|
||||
|
||||
namespace Minesweeper.Tests;
|
||||
|
||||
public class SolverTests
|
||||
{
|
||||
[Fact]
|
||||
public void AnEmptyMinefieldIsClearedInOneGo()
|
||||
{
|
||||
var game = new MinesweeperGame(new Board(5, 5, 0), new Random(1));
|
||||
var result = new Solver(game, new Random(2)).Run();
|
||||
|
||||
Assert.Equal(GameStatus.Won, result.Status);
|
||||
Assert.Equal(25, game.RevealedCount);
|
||||
Assert.Equal(0, result.Guesses);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TheStepBudgetStopsTheSearch()
|
||||
{
|
||||
var game = new MinesweeperGame(new Board(16, 16, 40), new Random(3));
|
||||
var result = new Solver(game, new Random(4), maxSteps: 1).Run();
|
||||
|
||||
Assert.Equal(1, result.Steps);
|
||||
Assert.Equal(GameStatus.Playing, game.Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TheSameSeedPlaysTheSameGame()
|
||||
{
|
||||
var first = Play(21, out var firstGame);
|
||||
var second = Play(21, out var secondGame);
|
||||
|
||||
Assert.Equal(first.Status, second.Status);
|
||||
Assert.Equal(firstGame.RevealedCount, secondGame.RevealedCount);
|
||||
Assert.Equal(first.Guesses, second.Guesses);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeductionsClearMostBeginnerBoards()
|
||||
{
|
||||
var wins = 0;
|
||||
for (var seed = 1; seed <= 10; seed++)
|
||||
{
|
||||
if (Play(seed, out _).Status == GameStatus.Won)
|
||||
wins++;
|
||||
}
|
||||
|
||||
Assert.True(wins >= 8, $"expected the solver to win at least 8 of 10 beginner boards, won {wins}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SolverNeverLeavesAHiddenSafeSquareBehind()
|
||||
{
|
||||
for (var seed = 1; seed <= 5; seed++)
|
||||
{
|
||||
Play(seed, out var game);
|
||||
if (game.Status != GameStatus.Won)
|
||||
continue;
|
||||
|
||||
Assert.Equal(game.TotalSafeCells, game.RevealedCount);
|
||||
}
|
||||
}
|
||||
|
||||
private static SolverResult Play(int seed, out MinesweeperGame game)
|
||||
{
|
||||
var random = new Random(seed);
|
||||
game = new MinesweeperGame(new Board(9, 9, 10), random) { ReserveSafeZone = true };
|
||||
return new Solver(game, random).Run();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user