הלינקייה: מגזין חודשי למפתחים

רוצה לשמוע על כל האירועים, המדריכים, הקורסים והמאמרים שנכתבו החודש ?
הלינקייה הינו מגזין חופשי בעברית שמשאיר אותך בעניינים.
בלי ספאם. בלי שטויות. פעם בחודש אצלך בתיבה.

Tic Tac Toe Solution

Below is a suggested solution to the Tic Tac Toe game written in Java.
The solution is based on the following classes:

  • Game. The Game class manages the game flow. It is the "manager" of our application - its work: go to the Player and ask for her next move, then pass that move to the Board class and print the board to the screen, turning to the second Player for her move. Note how all the checks if a move is valid, or if someone has won are performed outside of the Game class. This gives us the flexibility to modify the game rules without touching this class.
  • Player. The Player class represents a player in the game. Every player has a name, and the class is equipped with methods to find the next move of that player. A Player also knows how to represent herself (using which character) on the game board.
  • Board. The Board class is the most complex of them all in this game. It manages game rules and holds all the data regarding the game's state. The board is a 3x3 square where every player can capture a square with her avatar. This class is responsible for printing the board to the screen, and check if one of the players had won.
    Note the board is implemented using a 9 slots array, but using the right methods, we are able to give everyone else the feelings they're dealing with a matrix.
  • Move. A Move in the tic-tac-toe game is a pair of line and row a player wishes to take over. The Board takes the Move, validates it, and gives the square to the relevant Player if it's valid.
public class Game {
	private Board board;
	private Player first;
	private Player second;
 
	private Player current;
 
	public Game(Board board, Player p1, Player p2) {
		this.board = board;
		this.first = p1;
		this.second = p2;
 
		this.current = second;
	}
 
	public void start() {
		while ( this.board.hasWinner() == null ) {
			this.current = (this.current == this.first) ? this.second : this.first;
			this.board.printBoard();
 
			boolean ok = false;
			while ( ! ok ) {
				Move next = this.current.play();
				ok = this.board.setSquare(this.current, next.getRow(), next.getCol());							
			}						
		}
 
		System.out.println("Congratz ! " + this.current.getName() + " Won");
	}
 
	public static void main(String [] args) {
		Player p1 = new Player("Jim", 'J');
		Player p2 = new Player("Jeff", 'F');
		Board b = new Board(3, 3);
 
		Game g = new Game(b, p1, p2);
 
		g.start();
	}
}
 
/**
 * The Board keeps the game's data
 * It uses an array of Player Refs to allow
 * easy access to the player taking a specific square
 * @author ynonperek
 *
 */
public class Board {
	int numRows;
	int numCols;
 
	Player [] squares;
 
	public Board(int numRows, int numCols) {
		this.numRows = numRows;
		this.numCols = numCols;
 
		this.squares = new Player[this.numRows * this.numCols];
	}
 
	public Player getPlayerForSquare(int row, int col) {
		int idx = getBoardIdxForCoordinates(row, col);
		return this.squares[idx];
	}
 
	public boolean setSquare(Player p, int row, int col) {
		if ( getPlayerForSquare(row, col) != null ) {
			return false;
		}
 
		if ( ( row >= this.numRows) || ( col >= this.numCols ) ) {
			return false;
		}
 
		int idx = getBoardIdxForCoordinates(row, col);
		this.squares[idx] = p;
		return true;
	}
 
	public Player hasWinner() {
		for ( int i=0; i < this.numRows; i++ ) {
			Player p = hasWinnerInRow(i);
			if ( p != null ) {
				return p;
			}
		}
 
		for ( int i=0; i < this.numCols; i++ ) {
			Player p = hasWinnerInCol(i);
			if ( p != null ) {
				return p;
			}
		}
 
		return null;
	}
 
	public void printBoard() {
		for ( int i=0; i < this.numRows; i++ ) {
			for ( int j=0; j < this.numCols; j++ ) {
				Player p = getPlayerForSquare(i, j);
				if ( p == null ) {
					System.out.print("0 ");
				} else {
					System.out.print(p.getAvatar() + " ");
				}
			}
			// end of line between rows
			System.out.println();
		}
	}
 
	private Player hasWinnerInRow(int row) {
		Player p = getPlayerForSquare(row, 0);
 
		if ( p != null ) {
			for ( int i=0; i < this.numCols; i++ ) {
				Player q = getPlayerForSquare(row, i);
				if ( q != p ) {
					p = null;
					break;
				}
			}
		}
 
		return p;
	}
 
	private Player hasWinnerInCol(int col) {
		Player p = getPlayerForSquare(0, col);
 
		if ( p != null ) {
			for ( int i=0; i < this.numRows; i++ ) {
				Player q = getPlayerForSquare(i, col);
 
				if ( q != p ) {
					p = null;
					break;
				}
			}
		}
 
		return p;
	}
 
	private int getBoardIdxForCoordinates(int row, int col) {
		int idx = row * this.numRows + col;
		return idx;
	}
 
 
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
 
 
public class Player {
	private String name;
	private char avatar;
 
	public Player(String name, char avatar) {
		this.name = name;
		this.avatar = avatar;
	}
 
	public Move play() {
		try {
			System.out.println(this.name + " Enter your move (format: row col)");
	        InputStreamReader reader = new InputStreamReader(System.in);
	        BufferedReader br = new BufferedReader(reader);
	        String input = br.readLine();
 
	        int indexOfSpace = input.indexOf(" ");
	        String row = input.substring(0, indexOfSpace);
	        String col = input.substring(indexOfSpace + 1);
 
	        int irow = Integer.valueOf(row).intValue();
	        int icol = Integer.valueOf(col).intValue();
 
	        return new Move(irow, icol);
		} catch (Exception e) {
			// abort game
			System.out.println("Error Reading User Input");
			System.exit(1);
		}
 
		// placeholder. We never reach here
		return null;
	}
 
	public char getAvatar() {
		return this.avatar;
	}
 
	public String getName() {
		return this.name;
	}
}
 
public class Move {
	private int row;
	private int col;
 
	public Move(int row, int col) {
		this.row = row;
		this.col = col;
	}
 
	public int getRow() {
		return row;
	}
 
	public int getCol() {
		return col;
	}
}
 
course: