Connect 4 - OOP Game
Connect 4 game developed with TypeScript
Links & Resources
Description
Connect 4 game developed with TypeScript using object-oriented programming, offering an interactive experience in the browser with a well-structured architecture.
This web implementation of the classic board game demonstrates the practical application of object-oriented programming concepts.

The project implements a well-structured OOP architecture with several main classes such as Game, Board, Player, and UI, each with specific responsibilities. The fundamental principles of object-oriented programming are rigorously applied:
- Encapsulation with well-defined private properties and public methods
- Inheritance forming a class hierarchy for game elements
- Polymorphism allowing specific behaviors for different types of elements
- Composition assembling objects to create complex functionalities
The game offers a complete experience with several features:
- Classic rules of Connect 4 faithfully implemented
- Victory detection in all directions (horizontal, vertical, diagonal)
- Color selection for player tokens
- Responsive design adapted to all devices
The development of this game presented several interesting technical challenges, notably the implementation of an efficient victory detection algorithm and the creation of a modular and reusable TypeScript architecture.
SOLID principles were applied throughout development to ensure a maintainable and evolving code base, facilitating the addition of future features such as an online multiplayer mode or advanced AI.
// Extract from the Game class showing victory detection logic
export class Game {
private board: Board;
private players: Player[];
private currentPlayerIndex: number = 0;
private gameState: GameState = GameState.PLAYING;
private winningCells: Cell[] = [];
constructor(
private readonly rows: number = 6,
private readonly columns: number = 7,
private readonly connectToWin: number = 4,
private readonly ui: UI
) {
this.board = new Board(rows, columns);
this.players = [
new Player('Player 1', 'red'),
new Player('Player 2', 'yellow')
];
this.ui.drawBoard(this.board);
this.ui.updateStatus(`${this.currentPlayer.name}'s turn`);
this.setupEventListeners();
}
public get currentPlayer(): Player {
return this.players[this.currentPlayerIndex];
}
private nextTurn(): void {
this.currentPlayerIndex = (this.currentPlayerIndex + 1) % this.players.length;
this.ui.updateStatus(`${this.currentPlayer.name}'s turn`);
}
public dropToken(columnIndex: number): void {
if (this.gameState !== GameState.PLAYING) return;
const rowIndex = this.board.findAvailableRow(columnIndex);
if (rowIndex === -1) return; // Column full
const cell = this.board.getCell(rowIndex, columnIndex);
cell.player = this.currentPlayer;
this.ui.updateCell(cell);
this.ui.animateDropToken(columnIndex, rowIndex, this.currentPlayer.color);
if (this.checkWin(rowIndex, columnIndex)) {
this.gameState = GameState.WON;
this.ui.highlightWinningCells(this.winningCells);
this.ui.updateStatus(`${this.currentPlayer.name} wins!`);
} else if (this.board.isFull()) {
this.gameState = GameState.DRAW;
this.ui.updateStatus('Draw!');
} else {
this.nextTurn();
}
}
private checkWin(row: number, col: number): boolean {
// Direction arrays (vertical, horizontal, diagonals)
const directions = [
[1, 0], [0, 1], [1, 1], [1, -1]
];
for (const [dRow, dCol] of directions) {
const line = this.findLine(row, col, dRow, dCol);
if (line.length >= this.connectToWin) {
this.winningCells = line;
return true;
}
}
return false;
}
private findLine(row: number, col: number, dRow: number, dCol: number): Cell[] {
const player = this.currentPlayer;
const line: Cell[] = [];
// Search in positive direction
let r = row, c = col;
while (
r >= 0 && r < this.rows &&
c >= 0 && c < this.columns &&
this.board.getCell(r, c).player === player
) {
line.push(this.board.getCell(r, c));
r += dRow;
c += dCol;
}
// Search in negative direction
r = row - dRow;
c = col - dCol;
while (
r >= 0 && r < this.rows &&
c >= 0 && c < this.columns &&
this.board.getCell(r, c).player === player
) {
line.push(this.board.getCell(r, c));
r -= dRow;
c -= dCol;
}
return line;
}
// Other Game class methods...
}