/*
A simple Tic‑Tac‑Toe game written in TypeScript (Node.js).
Highlights:
- The board is represented as a typed array of 9 strings.
- All variables use explicit TypeScript types.
- Functions handle printing, move validation, win checking,
and turn progression.
- The game loop is clear and easy to follow.
*/
// Import readline with explicit type
import * as readline from "readline";
// Create a typed input helper for clean user prompts
const rl: readline.Interface = readline.createInterface({
input: process.stdin,
output: process.stdout
});
//---------------------------------------------------------------
// Print the board in a 3×3 layout
//---------------------------------------------------------------
function printBoard(board: string[]): void {
console.log();
for (let i: number = 0; i < 9; i++) {
process.stdout.write(board[i]);
if ((i + 1) % 3 === 0) {
console.log();
} else {
process.stdout.write(" | ");
}
}
console.log();
}
//---------------------------------------------------------------
// Check if a player has won
//---------------------------------------------------------------
function checkWin(board: string[], player: string): boolean {
const wins: number[][] = [
[0,1,2], [3,4,5], [6,7,8], // rows
[0,3,6], [1,4,7], [2,5,8], // columns
[0,4,8], [2,4,6] // diagonals
];
for (const combo of wins) {
const [a, b, c]: number[] = combo;
if (board[a] === player &&
board[b] === player &&
board[c] === player) {
return true;
}
}
return false;
}
//---------------------------------------------------------------
// Check if the board is full (draw)
//---------------------------------------------------------------
function boardFull(board: string[]): boolean {
return board.every((c: string): boolean => c !== " ");
}
//---------------------------------------------------------------
// Attempt to place a move; return true if successful
//---------------------------------------------------------------
function placeMove(board: string[], pos: number, player: string): boolean {
if (pos < 0 || pos >= 9) return false;
if (board[pos] !== " ") return false;
board[pos] = player;
return true;
}
//---------------------------------------------------------------
// Main game loop
//---------------------------------------------------------------
function main(): void {
const board: string[] = Array(9).fill(" ");
let currentPlayer: string = "X";
console.log("Tic‑Tac‑Toe");
printBoard(board);
function nextTurn(): void {
rl.question(`Player ${currentPlayer}, enter position (0‑8): `, (input: string): void => {
const pos: number = Number(input);
if (!Number.isInteger(pos)) {
console.log("Invalid input. Try again.");
return nextTurn();
}
if (!placeMove(board, pos, currentPlayer)) {
console.log("Invalid move. Try again.");
return nextTurn();
}
printBoard(board);
if (checkWin(board, currentPlayer)) {
console.log(`Player ${currentPlayer} wins!`);
rl.close();
return;
}
if (boardFull(board)) {
console.log("It's a draw!");
rl.close();
return;
}
currentPlayer = currentPlayer === "X" ? "O" : "X";
nextTurn();
});
}
nextTurn();
}
main();
/*
Tic‑Tac‑Toe
| |
| |
| |
Player X, enter position (0‑8): 4
| |
| X |
| |
Player O, enter position (0‑8): 1
| O |
| X |
| |
Player X, enter position (0‑8): 0
X | O |
| X |
| |
Player O, enter position (0‑8): 5
X | O |
| X | O
| |
Player X, enter position (0‑8): 3
X | O |
X | X | O
| |
Player O, enter position (0‑8): 6
X | O |
X | X | O
O | |
Player X, enter position (0‑8): 8
X | O |
X | X | O
O | | X
Player X wins!
*/