Case Study: Implementing TicTacToe
Case Study: Implementing TicTacToe
Outline Overview
Case Study focus on implementing a TicTacToe game
Breakdown of three software development sprints
Discussion on software engineering practices utilized throughout the implementation
Sprint 1
Goals and Tasks
Establish a framework to start implementation and testing
User Stories and Acceptance Criteria
User Story AC1.1: Empty Board
Condition: When a new game is started
Expectation: There will be an empty 3×3 board
Turn: It is X’s turn to play
User Story AC1.2: Invalid Row Index
Condition: Given a tic-tac-toe board
Expectation: When a cell is referenced by a row index > 2, the cell reference is invalid
User Story AC1.3: Invalid Column Index
Condition: Given a tic-tac-toe board
Expectation: When a cell is referenced by a column index > 2, the cell reference is invalid
Software Engineering Practices
Test Programming: Emphasizing writing tests prior to code implementation
Test-Driven Development (TDD): Refers to writing test cases before implementing the corresponding functionality
Pair Programming: Two developers work together at one workstation, switching roles between 'driver' and 'navigator'
Refactoring: Improving the structure of existing code without changing its behavior
Code Coverage: Ensuring that a significant portion of the code is tested
Coding Standards: Establish guidelines for writing code consistently
Static Code Analysis: Checking code for potential errors without executing it
Code Summary for TicTacToe
Production Code
The implementation separates business logic from user interface elements
Board class: Manages the state of the game board.
Constructor: Initializes a 3x3 grid of integers.
Methods:
int getCell(int row, int column): Accesses the value of a given cell. Returns0for empty cells.char getTurn(): Returns the current player's turn ('X' or 'O').
Example of Board Class:
java public class Board { private int[][] grid; private char turn = 'X'; public Board() { grid = new int[3][3]; } public int getCell(int row, int column) { return grid[row][column]; } public char getTurn() { return turn; } }
Test Code
Test Class:
TestEmptyBoardEnsures the board initializes correctly as empty:
java @Test public void testNewBoard() { for (int row = 0; row<3; row++) { for (int column = 0; column<3; column++) { assertEquals("", board.getCell(row, column), 0); } } assertEquals("", board.getTurn(), 'X'); }
Pair Programming Techniques
Ping-Pong Pairing: One developer writes a failing test, then hands the keyboard to the other who writes the implementation code. They swap roles frequently.
Driver-Navigator Pairing: One developer types (Driver) while the other focuses on the broad strategic vision (Navigator).
Benefits:
Improved code quality through collaborative efforts.
Enhanced code readability and a reduction in errors.
Shortened development schedules through more efficient pairing.
Sprint 2
User Stories and Acceptance Criteria
User Story 1: As an X player, I need to place X on an empty cell to make a move.
Acceptance Criteria AC2.1: Given an ongoing game with X's turn, when X makes a valid move, then X is placed in the cell and the turn changes to O.
Acceptance Criteria AC2.2: For an illegal move on an occupied cell, the cell is not changed and the turn does not change.
Acceptance Criteria AC2.3: If a move is made outside the board, the turn is not changed.
Production Code (Example)
Implementation of move-making functionality:
java public void makeMove(int row, int column) { if (isWithinBounds(row, column) && grid[row][column] == 0) { grid[row][column] = (turn == 'X') ? 1 : 2; turn = (turn == 'X') ? 'O' : 'X'; } }
Sprint 3
User Story
Goal: As a player, I need to know if the game is over after each move.
Acceptance Criteria: Check game state after each move:
```java
assertEquals("",