problemmediumood

Object-Oriented Design for Othello (Reversi)

MediumUpdated: Sep 15, 2018

Problem

Othello is played as follows: Each Othello piece is white on one side and black on the other. When a piece is surrounded by its opponents on both the left and right sides, or both the top and bottom, it is said to be captured and its color is flipped. On your turn, you must capture at least one of your opponent’s pieces. The game ends when either user has no more valid moves, and the win is assigned to the person with the most pieces. Implement the object oriented design for Othello.

othelloGame.jpg Solution The game flow looks like this:

  • Initialize the game which will be done by constructor
  • Get first user input
  • Validate the input
  • Change board configuration
  • Check if someone has won the game Get second user input
  • Validate the input
  • Change the board configuration
  • Check if someone has won the game

Understanding the classes Player There will be 2 players - black and white. The players will have the label with them - whether they are black or white, and set of pieces. The pieces can be added or removed from the set.

Board Board will consists of 2 players, and set of pieces. 

public class Player {
 private final char label;
 private Set<Pair<Integer>> pieces = new HashSet<Pair<Integer>>();

 public Player(char label) {
 this.label = label;
 }

 public void addOnePiece(Pair<Integer> piece) {
 pieces.add(piece);
 }

 public void removeOnePiece(Pair<Integer> piece) {
 pieces.remove(piece);
 }

 public Set<Pair<Integer>> getPieces() {
 return pieces;
 }

 public char getLabel() {
 return label;
 }

}

public class Board {
 private final char BLACK = '*';
 private final char WHITE = '^';
 private Player black;
 private Player white;

 private char[][] board = new char[8][8];

 public Board() {


## Problem

Othello (Reversi) is a two-player board game played on an 8x8 grid. Each piece has a black side and a white side. When a player places a piece such that one or more of the opponent's pieces are bounded in a straight line (horizontal, vertical or diagonal) between the new piece and another of the player's pieces, those opponent pieces are flipped. On your turn you must capture at least one opponent piece. The game ends when neither player has a valid move; the player with the most pieces wins. Implement an object-oriented design for Othello.

![Othello board image](http://2.bp.blogspot.com/-3vzdwFGVTD4/UytKwhaV5EI/AAAAAAAAbwg/jcohKrlRI6g/s1600/othelloGame.JPG)

## Solution

### 1. Requirements Analysis

Functional requirements:
- Represent the game board (8x8) and pieces (black/white).
- Allow two players to alternate turns and place pieces.
- Validate moves according to Othello rules (a move must flip at least one opponent piece).
- Flip the captured pieces when a valid move is played.
- Detect end-of-game and compute the winner by piece counts.
- Provide a simple I/O loop or API to read moves and display the board.

Non-functional requirements:
- Correctness: move validation and flipping must follow the rules precisely.
- Simplicity and testability: clear separation between model (Board, Player) and I/O.
- Extensibility: allow adding an AI player or alternate board sizes in the future.

Edge cases and constraints (inferred from source):
- Input validation for coordinates and bounds.
- Handling no-valid-move cases for a player (skip turn) and game termination when both players have no moves.

### 2. Use Case Diagram

Actors: Player (human or AI), Game Controller

Use case summary: Players start a game, make moves (place piece), view board, and end the game when no moves remain.

```mermaid
graph TD
    subgraph Othello Game
        UC1(Start Game)
        UC2(Make Move)
        UC3(View Board)
        UC4(End Game)
    end
    Player --> UC2
    Player --> UC3
    GameController --> UC1
    GameController --> UC4

3. Class Diagram

Core classes and responsibilities (derived from the original Java example):

  • Player: holds label/color and set of pieces (positions) owned by the player.
  • Board: maintains the 8x8 grid, validates moves, flips pieces, and provides board state.
  • GameController (or Game): coordinates turns, input/output, and end-of-game detection.
  • Pair / Position: small value object representing (row, col).
classDiagram
    class Player {
        +char label
        +Set~Position~ pieces
        +addOnePiece(Position)
        +removeOnePiece(Position)
    }

    class Board {
        +char[][] grid
        +Player black
        +Player white
        +boolean checkMove(Player, Player, Position)
        +void flip(Position)
        +boolean capturedLeftAndRight(Position)
        +boolean capturedUpAndDown(Position)
    }

    class GameController {
        +Board board
        +void start()
        +void step()
    }

    Player "1" -- "*" Position : owns
    GameController "1" -- "1" Board

4. Activity Diagrams

Activity: Making a Move

graph TD
    A[Player inputs coordinates] --> B[Validate input bounds]
    B --> C{Is move valid?}
    C -- Yes --> D[Place piece and flip captured pieces]
    C -- No --> E[Reject move and ask for input]
    D --> F[Update player's piece set]

Activity: Game Loop

graph TD
    S[Start game] --> T[Initialize board and players]
    T --> Turn[While either player has valid moves]
    Turn --> PlayerMove[Current player makes a move or passes]
    PlayerMove --> Check[Check and flip pieces]
    Check --> Switch[Switch turn]
    Switch --> Turn
    Turn --> End[Compute winner and end game]

5. High-Level Code Implementation

Below are cleaned skeletons adapted from the original Java implementation and a Python equivalent. These include key classes, attributes, and method signatures only.

Java

public class Position {
        private final int row;
        private final int col;

        public Position(int row, int col) { this.row = row; this.col = col; }
        public int getRow() { return row; }
        public int getCol() { return col; }
}

public class Player {
        private final char label;
        private Set<Position> pieces = new HashSet<>();

        public Player(char label) { this.label = label; }
        public void addOnePiece(Position p) { pieces.add(p); }
        public void removeOnePiece(Position p) { pieces.remove(p); }
        public Set<Position> getPieces() { return pieces; }
        public char getLabel() { return label; }
}

public class Board {
        private final char BLACK = '*';
        private final char WHITE = '^';
        private Player black;
        private Player white;
        private char[][] grid = new char[8][8];

        public Board() { /* initialize grid and starting pieces */ }

        public boolean checkMove(Player player, Player opponent, Position pos) {
                // validate bounds and flipping rules
                return false;
        }

        public boolean capturedLeftAndRight(Position pos) { return false; }
        public boolean capturedUpAndDown(Position pos) { return false; }
        public void flip(Position pos) { /* flip piece at pos */ }
}

public class GameController {
        private Board board;

        public void start() { /* game loop */ }
}

Python

from __future__ import annotations
from dataclasses import dataclass, field
from typing import Set

@dataclass(frozen=True)
class Position:
        row: int
        col: int

@dataclass
class Player:
        label: str
        pieces: Set[Position] = field(default_factory=set)

        def add_one_piece(self, p: Position) -> None:
                self.pieces.add(p)

        def remove_one_piece(self, p: Position) -> None:
                self.pieces.discard(p)

class Board:
        def __init__(self) -> None:
                self.black = Player('*')
                self.white = Player('^')
                self.grid: list[list[str]] = [['.' for _ in range(8)] for _ in range(8)]

        def check_move(self, player: Player, opponent: Player, pos: Position) -> bool:
                raise NotImplementedError

        def flip(self, pos: Position) -> None:
                raise NotImplementedError

class GameController:
        def __init__(self) -> None:
                self.board = Board()

        def start(self) -> None:
                # main loop handling turns
                raise NotImplementedError

References

Comments