/* Connect 4 */ /* Carsten Schuermann */ import java.util.ArrayList; import java.io.IOException; import java.io.InputStreamReader; import java.io.BufferedReader; class IllegalMove extends Exception { int i; IllegalMove (int i) { this.i = i; } } interface Player { void init (Boolean color); String name (); int move (); void inform (int i); } class Board { Boolean[][] board; Board () { init (); } void init () { board = new Boolean[7][6]; } Board copy () { Board newboard = new Board(); for (int i=0; i<7; i++) { for (int j=0; j<6; j++) { newboard.board[i][j]= board[i][j]; } } return newboard; } Boolean isValid (int i) { if (0 <= i && i < 7) {return true;} else {return false;} } Boolean isFull (int i) { if (board[i][5] == null) {return false;} else {return true;} } void drop (int i, int j, Boolean color) { if (board[i][j] == null) { if (j == 0) { board[i][j] = color;} else { this.drop (i, j-1, color);} } else {board[i][j+1] = color;} /* will be ok by invariant */ } void insert (int i, Boolean color) throws IllegalMove { if (this.isFull(i)) {throw (new IllegalMove (i));} else { if (this.isValid(i)) {this.drop (i, 5, color);} else {throw (new IllegalMove (i));}; } } Boolean slash(Boolean color, int i, int j) { if (i>2 || j>1) {return false;} else { Boolean b = true; for (int k = 0; k < 4; k++) {b = b && (board[i+k][j+k]) == color; } return b; } } Boolean minus(Boolean color, int i, int j) { if (i>2) {return false;} else { Boolean b = true; for (int k = 0; k < 4; k++) {b = b && (board[i+k][j]) == color; } return b; } } Boolean backslash(Boolean color, int i, int j) { if (i>2 || j<3) {return false;} else { Boolean b = true; for (int k = 0; k < 4; k++) {b = b && (board[i+k][j-k]) == color; } return b; } } Boolean pipe (Boolean color, int i, int j) { if (j<3) {return false;} else { Boolean b = true; for (int k = 0; k < 4; k++) {b = b && (board[i][j-k]) == color; } return b; } } Boolean win (Boolean color) { Boolean b = false; for (int i = 0 ; i<7 ; i++) { for (int j = 0; j< 6; j++) { b = b || slash (color, i, j) || minus (color, i, j) || backslash (color, i, j) || pipe (color, i, j); } } return (b); } Boolean tie () { Boolean b = true; for (int i = 0; i<6; i++) { b = b && isFull(i); } return b; } void print () { for (int j=5; j>=0; j--) { for (int i=0; i<7; i++) { if (board[i][j] == null) {System.out.print ("| ");} else { if (board[i][j]) {System.out.print ("| R ");} else {System.out.print ("| Y ");} } } System.out.println ("|"); } } } class ConnectFour { Board b; Player p1; /* p1 plays true */ Player p2; /* p2 plays false */ ConnectFour (Player p1, Player p2) { init (); this.p1 = p1; this.p2 = p2; p1.init(true); p2.init(false); } void init () { b = new Board (); } void illegal (String s, int i) { System.out.println ("Illegal Move: Player " + s + " moved to " + i); } /* Invariant: Board b is ok, might be full. No winner yet. */ int move (Boolean player) { b.print (); if (player) {System.out.println (p1.name() + " please make your move");} else {System.out.println (p2.name() + " please make your move");} if (b.tie ()) { System.out.println ("Tie!"); return 0;} else { if (player) { int m = p1.move (); try {b.insert (m, player); } catch (IllegalMove exn) {this.illegal (p1.name(), exn.i); return 2;} if (b.win (player)) {System.out.println ("Winner:" + p1.name()); return 1;} p2.inform (m); } else { int m = p2.move (); try {b.insert (m, player);} catch (IllegalMove exn) {this.illegal (p2.name(), exn.i); return 1;} if (b.win (player)) {System.out.println ("Winner:" + p1.name()); return 2;} p1.inform (m); }; return (move (! player)); } } int run () { this.init (); int result = this.move (true); b.print (); return (result); } public static void main (String [] args) { ConnectFour c = new ConnectFour (new Carsten (), new AutomaticCarsten ()); c.run (); } } class Carsten implements Player{ Boolean color; BufferedReader console = new BufferedReader(new InputStreamReader(System.in)); public void init (Boolean color) { this.color = color; } public String name () { return "Carsten";} public int move () { try { return (Integer.parseInt(console.readLine()));} catch (Exception exn) { return (this.move ()); } } public void inform (int i) {} } class Stage { Board[] boards = new Board[7]; Boolean color; int best; Boolean winning; /* is never null */ Boolean loosing; /* is never null */ int depth; Stage (Board b, Boolean color, int depth) { this.depth = depth; if (b.win (! color)) {loosing = true; winning = false;} else { if (b.win (color)) {winning = true; loosing = false;} else { loosing = false; winning = false; this.color = color; for (int i=0; i<7; i++) { if (b.isFull (i)) {boards[i] = null;} else{ boards[i] = b.copy (); try {boards[i].insert(i, color);} catch (IllegalMove exn) {}; } } } } } double minimax (double a, double b) { if (this.depth < 0) {return 0.0;} if (this.winning) {return 1.0;} if (this.loosing) {return -1.0;} else { double newa = a; best = 0; for (int i = 0; i<7; i++) { if (boards[i] != null) { double n = new Stage (boards[i], ! color, this.depth-1).maximin (a, b); if (newa < n) {newa = n; best = i;} if (b <= newa) {return newa;} } } return newa; } } double maximin (double a, double b) { if (this.depth < 0) {return 0.0;} if (winning) {return 1.0;} if (loosing) {return -1.0;} else { double newb = b; best = 0; for (int i=0; i<7; i++) { if (boards[i] != null) { double n = new Stage (boards[i], ! color, this.depth-1).minimax (a, b); if (n < newb) {newb = n; best = i;} if (newb <= a) {return newb;} } } return newb; } } } class AutomaticCarsten implements Player { Board board = new Board (); Boolean color; public String name () { return "Automatic Carsten";} public void init (Boolean color) { this.color = color; } public int move () { Stage start= new Stage (board, color, 5); start.minimax (-100.0, 100.0); try {board.insert (start.best, color);} catch (IllegalMove exn) {}; return (start.best); } public void inform (int i) { try {board.insert (i, ! color);} catch (IllegalMove exn) {}; } }