Skip to content

Instantly share code, notes, and snippets.

@stereosteve
Last active August 16, 2019 14:48
Show Gist options
  • Save stereosteve/b857ff1ff975e32fe0d821b5821b2ece to your computer and use it in GitHub Desktop.
Save stereosteve/b857ff1ff975e32fe0d821b5821b2ece to your computer and use it in GitHub Desktop.
const std = @import("std");
const Mark = enum(u2) {
Empty,
X,
O,
};
const Game = struct {
board: [3][3]Mark,
turn: Mark,
pub fn init() Game {
return Game{
.board = [3][3]Mark{
[3]Mark{ .Empty, .Empty, .Empty },
[3]Mark{ .Empty, .Empty, .Empty },
[3]Mark{ .Empty, .Empty, .Empty },
},
.turn = .X,
};
}
pub fn print(self: Game) void {
std.debug.warn("\n---------\n");
for (self.board) |row| {
for (row) |cell, column_index| {
const m = switch (cell) {
.X => "X",
.O => "O",
.Empty => "-",
};
const sep = if (column_index == 2) "\n" else " | ";
std.debug.warn("{}{}", m, sep);
}
}
std.debug.warn("---------\n");
}
fn checkWinner(self: Game) Mark {
for (self.board) |row, i| {
if (row[0] != .Empty and row[0] == row[1] and row[0] == row[2])
return row[0];
if (self.board[0][i] != .Empty and self.board[0][i] == self.board[1][i] and self.board[0][i] == self.board[2][i])
return self.board[0][i];
}
const mid = self.board[1][1];
if (mid != .Empty and self.board[0][0] == mid and self.board[2][2] == mid)
return mid;
if (mid != .Empty and self.board[0][2] == mid and self.board[2][0] == mid)
return mid;
return .Empty;
}
fn isBoardFull(self: Game) bool {
for (self.board) |row| {
for (row) |cell| {
if (cell == .Empty) {
return false;
}
}
}
return true;
}
fn makeMove(self: *Game, cell_number: usize) !void {
var i: usize = 0;
for (self.board) |row, row_index| {
for (row) |cell, column_index| {
i += 1;
if (i != cell_number) continue;
if (cell != .Empty) return error.CellFull;
self.board[row_index][column_index] = self.turn;
self.turn = if (self.turn == .X) Mark.O else Mark.X;
}
}
}
};
test "checkWinner" {
const testing = std.testing;
{
var g = Game.init();
testing.expect(g.checkWinner() == .Empty);
g.board[0][0] = .X;
g.board[0][1] = .X;
g.board[0][2] = .X;
g.print();
testing.expect(g.checkWinner() == .X);
}
{
var g = Game.init();
testing.expect(g.checkWinner() == .Empty);
g.board[0][0] = .X;
g.board[1][0] = .X;
g.board[2][0] = .X;
g.print();
testing.expect(g.checkWinner() == .X);
}
{
var g = Game.init();
testing.expect(g.checkWinner() == .Empty);
g.board[0][0] = .O;
g.board[1][1] = .O;
g.board[2][2] = .O;
g.print();
testing.expect(g.checkWinner() == .O);
}
{
var g = Game.init();
testing.expect(g.checkWinner() == .Empty);
var i: usize = 1;
while (i < 10) {
try g.makeMove(i);
i += 1;
}
g.print();
testing.expect(g.isBoardFull());
}
}
pub fn main() void {
var bytes: [100]u8 = undefined;
var g = Game.init();
g.print();
while (true) {
std.debug.warn("\n{} Enter square 1 - 9: ", g.turn);
const got = std.io.readLineSlice(bytes[0..]) catch |err| {
std.debug.warn("Invalid number, try again. \n");
continue;
};
const n = std.fmt.parseUnsigned(u8, got, 10) catch |err| {
std.debug.warn("Invalid number, try again. \n");
continue;
};
if (n < 1 or n > 9) {
std.debug.warn("Invalid number, try again. \n");
continue;
}
g.makeMove(n) catch |err| {
std.debug.warn(" Cell already occupied: {} \n", err);
};
g.print();
const winner = g.checkWinner();
if (winner != .Empty) {
std.debug.warn("\n !!! Winner: {} !!! \n", winner);
break;
}
if (g.isBoardFull()) {
std.debug.warn("\n Stalemate \n");
break;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment