70 lines
2.1 KiB
D
70 lines
2.1 KiB
D
import std.stdio, std.random, std.ascii, std.string, std.range,
|
|
std.algorithm, std.conv;
|
|
|
|
enum N = 3; // Board side.
|
|
static assert(N <= lowercase.length);
|
|
enum columnIDs = lowercase[0 .. N];
|
|
alias Board = ubyte[N][N];
|
|
|
|
void flipBits(ref Board board, in size_t count=1) {
|
|
foreach (immutable _; 0 .. count)
|
|
board[uniform(0, $)][uniform(0, $)] ^= 1;
|
|
}
|
|
|
|
void notRow(ref Board board, in size_t i) pure nothrow {
|
|
board[i][] ^= 1;
|
|
}
|
|
|
|
void notColumn(ref Board board, in size_t i) pure nothrow {
|
|
foreach (ref row; board)
|
|
row[i] ^= 1;
|
|
}
|
|
|
|
Board generateGameBoard(in ref Board target) {
|
|
// board is generated with many flips, to keep parity unchanged.
|
|
Board board = target;
|
|
while (board == target)
|
|
foreach (immutable _; 0 .. 2 * N)
|
|
[¬Row, ¬Column][uniform(0, 2)](board, uniform(0, N));
|
|
return board;
|
|
}
|
|
|
|
void show(in ref Board board, in string comment) {
|
|
comment.writeln;
|
|
writefln(" %-(%c %)", columnIDs);
|
|
foreach (immutable j, const row; board)
|
|
writefln(" %2d %-(%d %)", j + 1, row);
|
|
}
|
|
|
|
void main() {
|
|
"T prints the target, and Q exits.\n".writeln;
|
|
// Create target and flip some of its bits randomly.
|
|
Board target;
|
|
flipBits(target, uniform(0, N) + 1);
|
|
show(target, "Target configuration is:");
|
|
|
|
auto board = generateGameBoard(target);
|
|
immutable prompt = format(" 1-%d / %s-%s to flip, or T, Q: ",
|
|
N, columnIDs[0], columnIDs.back);
|
|
uint move = 1;
|
|
while (board != target) {
|
|
show(board, format("\nMove %d:", move));
|
|
prompt.write;
|
|
immutable ans = readln.strip;
|
|
|
|
if (ans.length == 1 && columnIDs.canFind(ans)) {
|
|
board.notColumn(columnIDs.countUntil(ans));
|
|
move++;
|
|
} else if (iota(1, N + 1).map!text.canFind(ans)) {
|
|
board.notRow(ans.to!uint - 1);
|
|
move++;
|
|
} else if (ans == "T") {
|
|
show(target, "Target configuration is:");
|
|
} else if (ans == "Q") {
|
|
return "Game stopped.".writeln;
|
|
} else
|
|
writefln(" Wrong input '%s'. Try again.\n", ans.take(9));
|
|
}
|
|
|
|
"\nWell done!".writeln;
|
|
}
|