import java.io.*; import java.util.*; public class Checkers { //game state: board config and whose turn: private char[][] board = new char[8][8]; private char turn; //ctor. play a game of checkers public Checkers() { // initialize(); file_initialize(); turn = 'r'; //red always plays first } public void play(int num_humans) { play(num_humans,'r'); } public void play(int num_humans, char humans_color) { display(); //test Checkers toString //System.out.println(toString()); //test file output //file_dump(); boolean winner=false; while (!winner) { if ((num_humans==1 && turn==humans_color) || num_humans==2) make_move(); else { //computer's turn } display(); if (turn == 'r') turn = 'b'; else turn = 'r'; } } private void initialize() { for (int i=0; i<8; i++) for (int j=0; j<8; j++) if (((i==0 || i==2) && j%2==1) || (i==1 && j%2==0)) board[i][j] = 'r'; else if (((i==5 || i==7) && j%2==0) || (i==6 && j%2==1)) board[i][j] = 'b'; else board[i][j] = ' '; } private void file_dump() { String fname = "saveboard"; try { PrintWriter outf = new PrintWriter(new FileWriter(fname)); String line; for (int i=0; i<8; i++) { for (int j=0; j<8; j++) outf.print(board[i][j]); outf.println(); } outf.println(turn); outf.close(); } catch (IOException e) { //so method doesn't need to throw IOException of readLine } } private void file_initialize() { String fname = "initboard"; try { BufferedReader inf = new BufferedReader(new FileReader(fname)); String line; for (int i=0; i<8; i++) { line = inf.readLine(); //debug: file must be 8x8 chars //System.out.println("line length="+line.length()); for (int j=0; j<8; j++) board[i][j] = line.charAt(j); } inf.close(); } catch (IOException e) { //so method doesn't need to throw IOException of readLine } } //all output here. change to awt later... private void display() { System.out.println(" 1 2 3 4 5 6 7 8"); System.out.println(" -----------------"); for (int i=0; i<8; i++) { System.out.print(i+1+"|"); for (int j=0; j<8; j++) System.out.print(board[i][j]+"|"); System.out.println(); System.out.println(" -----------------"); } } public String toString() { StringBuffer B = new StringBuffer(); for (int i=0; i<8; i++) { for (int j=0; j<8; j++) B.append(board[i][j]); B.append('\n'); } B.append(turn); B.append('\n'); return B.toString(); } private void make_move() { boolean bad_coords; int[] coords = new int[2]; int frow, fcol, trow, tcol; String coord_error=""; Set jumps = new HashSet(); find_jumps(jumps); //debug: System.out.println("Jumps:"); for (Iterator i=jumps.iterator(); i.hasNext(); ) System.out.println(i.next()); do { boolean int_coords = false; while (!int_coords) { int_coords = get_coords("From",coords,coord_error); coord_error = "not a number"; } frow = coords[0] - 1; fcol = coords[1] - 1 ; //debug: //System.out.println("row="+frow+" col="+fcol); bad_coords = false; if (frow<0 || frow>7 || fcol<0 || fcol>7) { bad_coords = true; coord_error = "not on board"; } else if (Character.toUpperCase(board[frow][fcol]) != Character.toUpperCase(turn)) { bad_coords = true; coord_error = "not yours"; } else if ((frow==0 || fcol==7 || Character.toUpperCase(board[frow-1][fcol+1])== Character.toUpperCase(turn)) && (frow==0 || fcol==0 || Character.toUpperCase(board[frow-1][fcol-1])== Character.toUpperCase(turn)) && (frow==7 || fcol==7 || Character.toUpperCase(board[frow+1][fcol+1])== Character.toUpperCase(turn)) && (frow==7 || fcol==0 || Character.toUpperCase(board[frow+1][fcol-1])== Character.toUpperCase(turn))) { bad_coords = true; coord_error = "surrounded"; } else if ((turn=='r' && board[frow][fcol]!='R' && ((frow==7 || fcol==7 || Character.toUpperCase(board[frow+1][fcol+1])=='R') || (Character.toUpperCase(board[frow+1][fcol+1])=='B' && (frow==6 || fcol==6 || board[frow+2][fcol+2]!=' '))) && ((frow==7 || fcol==0 || Character.toUpperCase(board[frow+1][fcol-1])=='R') || (Character.toUpperCase(board[frow+1][fcol-1])=='B' && (frow==6 || fcol==1 || board[frow+2][fcol-2]!=' ')))) || (turn=='b' && board[frow][fcol]!='B' && ((frow==0 || fcol==7 || Character.toUpperCase(board[frow-1][fcol+1])=='B') || (Character.toUpperCase(board[frow-1][fcol+1])=='R' && (frow==1 || fcol==6 || board[frow-2][fcol+2]!=' '))) && ((frow==0 || fcol==0 || Character.toUpperCase(board[frow-1][fcol-1])=='B') || (Character.toUpperCase(board[frow-1][fcol-1])=='R' && (frow==1 || fcol==1 || board[frow-2][fcol-2]!=' '))))){ bad_coords = true; coord_error = "no move forward"; } else if (!jumps.isEmpty()) { if (!jumps.contains(Integer.toString(frow)+" "+Integer.toString(fcol))) { bad_coords = true; coord_error = "must do available jump"; } } } while (bad_coords); boolean has_another_jump = false; do { //while has_another_jump from here coord_error=""; do { boolean int_coords = false; while (!int_coords) { int_coords = get_coords("To",coords,coord_error); coord_error = "not a number"; } trow = coords[0] - 1; tcol = coords[1] - 1; //debug: //System.out.println("row="+trow+" col="+tcol); bad_coords = false; if (trow<0 || trow>7 || tcol<0 || tcol>7) { bad_coords = true; coord_error = "not on board"; } else if ((turn=='r' && board[frow][fcol]!='R' && trow<=frow) || (turn=='b' && board[frow][fcol]!='B' && trow>=frow)) { bad_coords = true; coord_error = "not move forward"; } else if (board[trow][tcol] != ' ') { bad_coords = true; coord_error = "not empty"; } //jump attempt but not over other player else if (Math.abs(trow-frow)==2 && ((turn=='b' && Character.toUpperCase(board[(trow+frow)/2][(tcol+fcol)/2]) !='R') || (turn=='r' && Character.toUpperCase(board[(trow+frow)/2][(tcol+fcol)/2]) !='B'))) { bad_coords = true; coord_error = "bad jump"; } //not a jump and move is not +-1 row and col from frow and fcol else if (Math.abs(trow-frow)!=2 && (Math.abs(trow-frow)!=1 || Math.abs(tcol-fcol)!=1)) { bad_coords = true; coord_error = "bad move"; } else if (!jumps.isEmpty()) { //a jump From was selected if (Math.abs(trow-frow) != 2) { //but not taken bad_coords = true; coord_error = "jump must be taken"; } } } while (bad_coords); //the offcial positions int from_cell = frow*4 + (int)Math.ceil((fcol+1)/2.0); int to_cell = trow*4 + (int)Math.ceil((tcol+1)/2.0); //System.out.println(from_cell+"-"+to_cell); boolean kinged_this_play = false; if (trow==7 && board[frow][fcol]=='r') { //becomes king board[trow][tcol] = 'R'; kinged_this_play = true; //so if jumped here, must stop even if jump available } else if (trow==0 && board[frow][fcol]=='b') { //becomes king board[trow][tcol] = 'B'; kinged_this_play = true; } else board[trow][tcol] = board[frow][fcol]; board[frow][fcol] = ' '; if (Math.abs(trow-frow) == 2) { //jumped board[(trow+frow)/2][(tcol+fcol)/2] = ' '; if (has_jump(trow,tcol) && !kinged_this_play) { has_another_jump = true; frow = trow; //from here fcol = tcol; //so this jump is in set: jumps.add(Integer.toString(frow)+" "+Integer.toString(fcol)); display(); } else has_another_jump = false; } } while (has_another_jump); } //all input here. a row, col private boolean get_coords(String from_or_to, int[] coords, String coord_error) { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String line; System.out.println(coord_error); System.out.println(turn+" turn to play"); System.out.print(from_or_to+"Row (1-8): "); try { line = in.readLine(); coords[0] = Integer.parseInt(line); } catch (NumberFormatException e) { System.out.println("Invalid input, not a number"); return false; } //so don't need throws IOException (from readLine) for method catch (IOException e) { System.out.println("catch Exception"); return false; } System.out.print(from_or_to+"Col (1-8): "); try { line = in.readLine(); coords[1] = Integer.parseInt(line); } catch (NumberFormatException e) { System.out.println("Invalid input, not a number"); return false; } catch (IOException e) { System.out.println("catch Exception"); return false; } return true; } private boolean has_jump(int frow, int fcol) { if (((turn=='r' && Character.toUpperCase(board[frow][fcol])=='R' && ((frow<6 && fcol<6 && Character.toUpperCase(board[frow+1][fcol+1])=='B' && board[frow+2][fcol+2]==' ') || (frow<6 && fcol>1 && Character.toUpperCase(board[frow+1][fcol-1])=='B' && board[frow+2][fcol-2]==' '))) || (turn=='r' && board[frow][fcol]=='R' //backwards && ((frow>1 && fcol<6 && Character.toUpperCase(board[frow-1][fcol+1])=='B' && board[frow-2][fcol+2]==' ') || (frow>1 && fcol>1 && Character.toUpperCase(board[frow-1][fcol-1])=='B' && board[frow-2][fcol-2]==' ')))) || ((turn=='b' && Character.toUpperCase(board[frow][fcol])=='B' && ((frow>1 && fcol>1 && Character.toUpperCase(board[frow-1][fcol-1])=='R' && board[frow-2][fcol-2]==' ') || (frow>1 && fcol<6 && Character.toUpperCase(board[frow-1][fcol+1])=='R' && board[frow-2][fcol+2]==' '))) || (turn=='b' && board[frow][fcol]=='B' //backwards && ((frow<6 && fcol<6 && Character.toUpperCase(board[frow+1][fcol+1])=='R' && board[frow+2][fcol+2]==' ') || (frow<6 && fcol>1 && Character.toUpperCase(board[frow+1][fcol-1])=='R' && board[frow+2][fcol-2]==' '))))) return true; else return false; } private void find_jumps(Set s) { for (int i=0; i<8; i++) for (int j=0; j<8; j++) if (has_jump(i,j)){ s.add(Integer.toString(i)+" "+Integer.toString(j)); //debug: //System.out.println(Integer.toString(i)+" "+Integer.toString(j)); } } //nested test class public static class Play { public static void main(String[] args) { if (args.length==0 || (args.length==1 && !args[0].equals("2")) || (args.length==2 && (!args[1].equals("r") && !args[1].equals("b")))) { System.out.println("Usage: Play {1 r|b}|2"); System.exit(1); } Checkers game = new Checkers(); if (args.length == 1) game.play(2); else game.play(1,args[1].charAt(0)); } } }