Computer Science 15-100 (Sections T & U), Spring 2008
Class Notes:  Writing Tic-Tac-Toe Using Strings, Methods, Loops, and Conditionals


Logistics

  1. Schedule
    1. Test 1 on Thursday
      Covers all material through from Day 1 up to and including today.
    2. Review session tomorrow night (watch for Grant's email)
    3. Bonus lecture on Thursday at 4:30.

// TicTacToe.java
// Written (mostly) in 15-100-TU class, 5-March-2008

// This is a rudimentary, and only partially-completed,
// version fo TicTacToe.

// 98% of this code was written in class, and so it may
// contain bugs, and its style is not exactly up to par
// (for example, we didn't comment everything carefully...)

// NOTE:  this code implements tic-tac-toe using STRINGS,
// whereas the sensible thing to do is to use ARRAYS.
// But we don't know arrays yet, so strings will have to do (for now).

// Briefly, here is how we encode a board in a String:
// 3x4 board
//   1 2 3 4
// A - - x - A
// B - - x - B
// C o o - - C
//   1 2 3 4
// String: "--x---x-oo--"

class TicTacToe {
    
  public static void printBoard(String board, int rows, int cols) {
    if ((rows < 1) || (cols < 1) || (rows > 9) || (cols > 9)) {
      System.out.println("no way");  // @TODO: handle >9 rows/cols
      return;
    }    
    String colLabels = " ";
    for (int col=0; col<cols; col++)
      colLabels += " " + (col+1);
    System.out.println(colLabels);

    for (int row=0; row<rows; row++) {
      char rowChar = (char)('A' + row);
      System.out.print(rowChar);
      for (int col=0; col<cols; col++)
        System.out.print(" " + getPiece(board,row,col,rows,cols));
      System.out.println(" " + rowChar);
    }
    
    System.out.println(colLabels);
  }

  // returns -1 if the position is off the board  
  public static int getIndex(int row, int col, int rows, int cols) {
    if ((row < 0) || (row >= rows) || (col < 0) || (col >= cols))
        return -1;
    return row*cols + col;
  }

  // returns (char)0 if the piece is off the board  
  public static char getPiece(String board, int row, int col, int rows, int cols) {
    int i = getIndex(row,col,rows,cols);
    return ((i < 0) ? ((char)0) : board.charAt(getIndex(row,col,rows,cols)));
  }

  // return null if move is illegal  
  public static String makeMove(String board, char piece,
                                int row, int col, int rows, int cols) {
    int i = getIndex(row,col,rows,cols);
    if (i < 0) {
        System.out.println("Out of bounds.  Try again.");
        return null;
    }
    if (getPiece(board,row,col,rows,cols) != '-') {
        System.out.println("That space is occupied.  Try again.");
        return null;
    }
    return board.substring(0,i) + piece + board.substring(i+1); 
  }
  
  public static String doMove(String board, int rows, int cols, char piece) {
    java.util.Scanner scanner = new java.util.Scanner(System.in);
    String newBoard = null;
    while (newBoard == null) {
        System.out.print("\n" + piece + "'s move (or 'q' to quit) --> ");
        String move = scanner.next().toUpperCase();
        if (move.startsWith("Q"))
            System.exit(0);
        // input:  B3 --> row B, col 3 --> row 1, col 2
        if (move.length() != 2) {
            System.out.println("Illegal format.  Try again.");
            continue;
        }
        int row = move.charAt(0) - 'A';
        int col = move.charAt(1) - '0' - 1;
        newBoard = makeMove(board,piece,row,col,rows,cols);
    }
    return newBoard;
  }

  // is the piece a winner starting from the given row,col
  // in the given direction defined by dr,dc
  public static boolean isWinner(String board, char piece,
                                 int row, int col,
                                 int dr, int dc,
                                 int rows, int cols) {
    int n = 3; // # of pieces in a row to win
    for (int i=0; i<n; i++) {
        int r = row + i*dr;
        int c = col + i*dc;
        if (getPiece(board,r,c,rows,cols) != piece)
            return false;
    }
    return true;
  }

  // is the piece a winner starting from the given row,col
  public static boolean isWinner(String board, char piece,
                                 int row, int col, int rows, int cols) {
    // dr = +1, dc = -1
    for (int dr=-1; dr<=+1; dr++)
      for (int dc=-1; dc<=+1; dc++)
        if (((dr != 0) || (dc != 0)) &&
            isWinner(board, piece,row,col,dr,dc,rows,cols))
               return true;
    return false;
  }
  
  public static boolean isWinner(String board, char piece, int rows, int cols) {
    for (int row=0; row<rows; row++)
      for (int col=0; col<cols; col++)
         if (isWinner(board,piece,row,col,rows,cols))
           return true;
    return false;
  }
  
  public static void playTicTacToe() {
    String newBoard = "------------";
    String board = newBoard;
    int rows = 3, cols = 4;
    char piece = 'x';
    while (true) {
      printBoard(board,rows,cols);
      board = doMove(board,rows,cols,piece);
      if (isWinner(board,piece,rows,cols)) {
        System.out.println(piece + " wins!!!!\n\n");
        board = newBoard;
        piece = 'x';
      }
      else
        piece = ((piece == 'x') ? 'o' : 'x');
    }
  }
  
  public static void main(String[] args){
    playTicTacToe();
  }
}

carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem