Demo Link to heading

Table of Contents Link to heading

Game Engine Architecture Link to heading

A modular game engine built with JavaScript and OOP principles, designed to easily integrate multiple board games while maintaining a consistent architecture.

Code Structure Link to heading

├── index.html          # Main UI with game selection menu
├── style.css           # Styling for main menu and responsive layout
├── GameEngine.js       # Core engine class (abstract base)
└── games/              # Game implementations
├── TicTacToe.js
├── Connect4.js
├── Checkers.js
├── Chess.js
├── Sudoku.js
└── EightQueens.js

Core OOP Architecture Link to heading

Base Game Engine Class Link to heading

class GameEngine {
  // Template methods to be implemented by concrete games
  drawer(board) { throw "Not implemented" }  // Render game state
  controller(board, input, playerTurn) { throw "Not implemented" } // Handle moves
  
  // Common game loop logic
  async gameLoop(board) {
    // Handles turn management, input processing, and state updates
  }
}

Game Implementation Structure Link to heading

class BoardGame extends GameEngine {
  drawer(board) {
    // Custom rendering logic for the game pieces and board
  }

  controller(board, input, playerTurn) {
    // Game-specific move validation
  }
}

Key Design Patterns Link to heading

Template Method Pattern Link to heading

  • Base Class: defines algorithm skeleton (gameLoop).
  • Concrete Classes: implement specific steps (drawer, controller).

Factory Pattern Link to heading

function play(gameId) {
  const games = {
    1: TicTacToe,
    2: Connect4,
    3: Checkers,
    4: Chess,
    5: Sudoku,
    6: EightQueens
  };
  
  return new games[gameId]();
}

Polymorphism Link to heading

// Engine treats all games uniformly
const currentGame = new SelectedGame();
currentGame.drawer(board);
currentGame.controller(input);

Scalability Features Link to heading

Game Implementation Interface Link to heading

To add a new game, developers need to:

  1. Extend GameEngine class.
  2. Implement:
    • drawer(board): Visual representation logic.
    • controller(board, input, playerTurn): Move validation logic.
  3. Register in game factory.

Component Isolation Link to heading

  • Game Logic: Contained in individual classes.
  • Rendering: Handled through DOM manipulation in drawer().
  • Input Handling: Normalized to string-based format.

State Management Link to heading

  • Immutable board state passed between controller and drawer.
  • Turn management handled by base class.

Asset Management Link to heading

class BoardGame extends GameEngine {
  drawer() {
      document.write(`
      <style>
        .board-container {
          /* Other styles */
          background-image: url('assets/game-background.png') 
        }
      </style>
    `);
  }
}

Adding a New Game (3 Steps) Link to heading

  1. Create Game Class
// games/NewGame.js
class NewGame extends GameEngine {
    drawer(board) { /* Custom rendering */ }
    controller(board, input, playerTurn) { /* Move logic */ }
}
  1. Register in Factory
// GameEngine.js
function play(check) {
    switch(check) {
        // Existing cases
        case 7: return new NewGame();  // Add new case 
    }
}
  1. Add UI Entry
<!-- index.html -->
<div class="game newGame" onclick="play(7)">
  <h2>New Game</h2>
  <span class="d-none d-lg-block">
    <img class="resizable-image" src="assets/newGame.png" alt="..."/>
  </span>
  <p>
    New Game Description.
  </p>
</div>

Architecture Benefits Link to heading

  • Encapsulation

    • Game-specific details hidden within individual classes.
    • Base class handles common flow control.
  • Loose Coupling

    • Games don’t know about each other’s implementation.
    • UI interacts only through base class interface.
  • Consistent API

    • All games expose the same methods for engine interaction.
    • Input/Output formats standardized.
  • Easy Maintenance

    • Changes to base class propagate to all games.
    • Game updates don’t affect other components.

This architecture enables rapid game integration while maintaining performance and code quality through strict separation of concerns and polymorphic design.