Skip to content

Instantly share code, notes, and snippets.

@morintd
Created March 14, 2024 17:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save morintd/e2e0ddc9d1ab7c17ace80ddf7178ae92 to your computer and use it in GitHub Desktop.
Save morintd/e2e0ddc9d1ab7c17ace80ddf7178ae92 to your computer and use it in GitHub Desktop.
import { Response, NextFunction } from "express";
import { BoardService } from "./board.repository";
import { BadRequestException } from "../common/exceptions/bad-request.exception";
export class TicTacToeController {
constructor(private boardService: BoardService) {}
handleInitialize(res: Response) {
const history = this.boardService.findHistory();
if (history.length > 0) {
const board = history[history.length - 1];
res.status(201).json({
moves: this.getMoves([board]),
status: this.getStatus(this.getWinner(board), this.xIsNext(board)),
squares: board,
});
}
const board = this.getInitialBoard();
this.boardService.setHistory([board]);
res.status(201).json({
moves: this.getMoves([board]),
status: this.getStatus(this.getWinner(board), this.xIsNext(board)),
squares: board,
});
}
handlePlay(res: Response, next: NextFunction, step: number, square: number) {
try {
const history = this.boardService.findHistory();
const currentBoard = history[step];
if (!currentBoard) {
return next(
new BadRequestException({
error: "step does not exist",
})
);
}
const xIsNext = this.xIsNext(currentBoard);
const winner = this.getWinner(currentBoard);
if (winner) {
res.status(201).json({
moves: this.getMoves([currentBoard]),
status: this.getStatus(
this.getWinner(currentBoard),
this.xIsNext(currentBoard)
),
squares: currentBoard,
});
}
if (currentBoard[square]) {
new BadRequestException({
error: "cell already taken",
});
}
const board = [...currentBoard];
if (xIsNext) {
board[square] = "X";
} else {
board[square] = "O";
}
this.boardService.setHistory([...history.slice(0, step + 1), board]);
res.status(201).json({
history: [...history.slice(0, step + 1), board],
winner: this.getWinner(board),
xIsNext: this.xIsNext(board),
step: step + 1,
});
} catch (e) {
next(e);
}
}
handleJumpTo(res: Response, next: NextFunction, step: number) {
try {
const history = this.boardService.findHistory();
const board = history[step];
if (!board) {
return next(
new BadRequestException({
error: "step does not exist",
})
);
}
res.status(201).json({
moves: this.getMoves([board]),
status: this.getStatus(this.getWinner(board), this.xIsNext(board)),
squares: board,
});
} catch (e) {
next(e);
}
}
private getWinner(squares: string[]) {
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (
squares[a] &&
squares[a] === squares[b] &&
squares[a] === squares[c]
) {
return squares[a];
}
}
if (squares.every((square) => !!square)) return "draw";
return null;
}
private getStep(squares: string[]) {
return squares.filter((square) => !!square).length;
}
private xIsNext(squares: string[]) {
return this.getStep(squares) % 2 === 0;
}
private getInitialBoard() {
return ["", "", "", "", "", "", "", "", ""];
}
private getMoves(history: string[][]) {
const moves = history.map((_, move: number) => {
return {
move,
description: move > 0 ? "Go to move #" + move : "Go to game start",
};
});
return moves;
}
private getStatus(winner: string | null, xIsNext: boolean) {
const status = winner
? winner === "draw"
? "Draw"
: "Winner: " + winner
: "Next player: " + (xIsNext ? "X" : "O");
return status;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment