From 818d34095fe3d3fddd1a3e3d381ecf4e235a3c4c Mon Sep 17 00:00:00 2001 From: Joe Sweeney Date: Sun, 2 Apr 2017 17:14:11 -0400 Subject: [PATCH 1/8] Add GameState2 and Move2 --- src/CheckersGameState2.java | 266 ++++++++++++++++++++++++++++++++++++ src/Move2.java | 39 ++++++ 2 files changed, 305 insertions(+) create mode 100644 src/CheckersGameState2.java create mode 100644 src/Move2.java diff --git a/src/CheckersGameState2.java b/src/CheckersGameState2.java new file mode 100644 index 0000000..e468788 --- /dev/null +++ b/src/CheckersGameState2.java @@ -0,0 +1,266 @@ +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +public class CheckersGameState2 implements CheckersGameState { + + // 0 = empty + // 1 = black piece + // 2 = white piece + // 3 = black king + // 4 = white king + private int[] board; + + // 1 = black, 2 = white + private int player; + + public static void main(String args[]) { + CheckersGameState2 state = new CheckersGameState2(); + state.printState(); + List actions = state.actions(); + for(Move move : actions) { + System.out.println((Move2)move); + state.result(move).printState(); + } + } + + public CheckersGameState2(int player, int[] board) { + this.board = board; + this.player = player; + } + public CheckersGameState2(int player) { + board = new int[32]; + for(int i = 0; i<32; i++) { + if(i<12) { + board[i] = 1; + } + else if(i>=20) { + board[i] = 2; + } + else { + board[i] = 0; + } + } + if(player == 1 || player == 2) { + this.player = player; + } + else { + this.player = 1; + } + } + public CheckersGameState2() { + this(1); + } + + public String player () { + if(this.player == 1) { + return "black"; + } + else if(this.player == 2) { + return "white"; + } + else { + System.out.println("Player data is wrong."); + return "Error"; + } + } + + private int otherPlayer() { + return (player%2) + 1; + } + + private boolean correctColor(int space) { + // returns true if piece at a space is your color + return space != 0 && (player == space || (player + 2) == space); + } + + private boolean isEnemy(int piece) { + int other = otherPlayer(); + return piece == other || (other + 2) == piece; + } + + private int[] neighbors(int index) { + int[] neighbors = new int[4]; + int row = (index - index%4)/4; + int col = index%4; + if (row % 2 == 0) { + neighbors[0] = index + 4; + neighbors[1] = index + 5; + neighbors[2] = index - 4; + neighbors[3] = index - 3; + + if(col == 3) { + neighbors[1] = -1; + neighbors[3] = -1; + } + } + else { + neighbors[0] = index + 3; + neighbors[1] = index + 4; + neighbors[2] = index - 5; + neighbors[3] = index - 4; + + if(col == 0) { + neighbors[0] = -1; + neighbors[2] = -1; + } + } + + for(int i = 0; i<4; i++) { + if(neighbors[i] < 0 || neighbors[i] >=32) { + neighbors[i] = -1; + } + } + + return neighbors; + } + + private ArrayList findJumpMoves(int starting, int current, int[] path, int capture) { + ArrayList moves = new ArrayList(); + int piece = board[starting]; + int[] neighbors = neighbors(current); + if(piece == 1) { + for(int i = 0; i<2; i++) { + if(neighbors[i] != -1 && isEnemy(board[neighbors[i]])) { + int next = neighbors(neighbors[i])[i]; + if(board[next] == 0) { + int [] newPath = Arrays.copyOf(path, path.length+1); + int c = capture == -1 ? neighbors[i] : capture; + moves.add(new Move2(newPath, c)); + moves.addAll(findJumpMoves(starting, next, newPath,c)); + } + } + } + } + else if(piece == 2) { + for(int i = 2; i<4; i++) { + if(neighbors[i] != -1 && isEnemy(board[neighbors[i]])) { + int next = neighbors(neighbors[i])[i]; + if(board[next] == 0) { + int [] newPath = Arrays.copyOf(path, path.length+1); + int c = capture == -1 ? neighbors[i] : capture; + moves.add(new Move2(newPath, c)); + moves.addAll(findJumpMoves(starting, next, newPath, c)); + } + } + } + } + else { + for(int i = 0; i<4; i++) { + if(neighbors[i] != -1 && isEnemy(board[neighbors[i]])) { + int next = neighbors(neighbors[i])[i]; + if(board[next] == 0) { + int [] newPath = Arrays.copyOf(path, path.length+1); + int c = capture == -1 ? neighbors[i] : capture; + moves.add(new Move2(newPath, c)); + moves.addAll(findJumpMoves(starting, next, newPath, c)); + } + } + } + } + return moves; + } + + private ArrayList captures() { + ArrayList captures = new ArrayList(); + for(int i = 0; i<32; i++) { + int piece = board[i]; + if(piece != 0 && correctColor(piece)) { + captures.addAll(findJumpMoves(i, i, new int[]{i}, -1)); + } + } + return captures; + } + + private ArrayList noncaptures() { + ArrayList moves = new ArrayList(); + for(int i = 0; i<32; i++) { + int space = board[i]; + if(space != 0 && correctColor(space)) { + int[] neighbors = neighbors(i); + if(space == 1) { + // black piece + if(neighbors[0] != -1 && board[neighbors[0]] == 0) { + moves.add(new Move2(i, neighbors[0], -1)); + } + if(neighbors[1] != -1 && board[neighbors[1]] == 0) { + moves.add(new Move2(i, neighbors[1], -1)); + } + } + else if(space == 2) { + // white piece + if(neighbors[2] != -1 && board[neighbors[2]] == 0) { + moves.add(new Move2(i, neighbors[2], -1)); + } + if(neighbors[3] != -1 && board[neighbors[3]] == 0) { + moves.add(new Move2(i, neighbors[3], -1)); + } + } + else { + // king + for(int j = 0; j<4; j++) { + if(neighbors[j] != -1 && board[neighbors[j]] == 0) { + moves.add(new Move2(i, neighbors[j], -1)); + } + } + } + } + } + return moves; + } + + public List actions() { + ArrayList actions = this.captures(); + if(actions.size() != 0) { + return actions; + } + else { + actions = this.noncaptures(); + } + return actions; + } + + public CheckersGameState result ( Move x ) { + Move2 move = (Move2) x; + int[] newBoard = Arrays.copyOf(board, board.length); + int newPlayer = otherPlayer(); + if(move.captures != -1) { + newBoard[move.captures] = 0; + } + newBoard[move.dest] = newBoard[move.src]; + newBoard[move.src] = 0; + + return new CheckersGameState2(newPlayer, newBoard); + } + + public void printState () { + String output = ""; + for(int i = 0; i<32; i++) { + int space = board[i]; + int row = (i - i%4)/4; + if(i%4 == 0 && i != 0){ + output += "\n"; + } + if(row % 2 == 0) { + output += " - "; + } + switch (space) { + case 0: output += " - "; + break; + case 1: output += " b "; + break; + case 2: output += " w "; + break; + case 3: output += " B "; + break; + case 4: output += " W "; + break; + } + + if(row % 2 == 1) { + output += " - "; + } + } + System.out.println(output); + } +} diff --git a/src/Move2.java b/src/Move2.java new file mode 100644 index 0000000..6dc689a --- /dev/null +++ b/src/Move2.java @@ -0,0 +1,39 @@ + +public class Move2 implements Move { + public int src, dest; + public int[] path; + public int captures; + + public Move2(int src, int dest, int capture) { + this.src = src; + this.dest = dest; + path = new int[] {src, dest}; + this.captures = capture; + } + public Move2(int[] p, int capture) { + src = p[0]; + dest = p[p.length - 1]; + path = p; + this.captures = capture; + } + + private String convert(int position) { + // Converts a position to the correct String + int col = position % 4; + int row = (position - col) / 4; + col = col * 2; + if(row%2 == 0) { + col ++; + } + return "("+(7-row)+":"+col+")"; + } + + public String toString() { + String output = ""; + for(int i = 0; i Date: Sun, 2 Apr 2017 17:15:02 -0400 Subject: [PATCH 2/8] Tweak style in State interface --- src/CheckersGameState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CheckersGameState.java b/src/CheckersGameState.java index aa87035..70c826d 100644 --- a/src/CheckersGameState.java +++ b/src/CheckersGameState.java @@ -1,4 +1,4 @@ -import java . util . List ; +import java.util.List; public interface CheckersGameState { String player (); List < Move > actions (); From edeb3e372f946991e084b9c1181af36800f1776a Mon Sep 17 00:00:00 2001 From: Joe Sweeney Date: Sun, 2 Apr 2017 22:32:05 -0400 Subject: [PATCH 3/8] Fix a few bugs, change test --- src/CheckersGameState2.java | 59 +++++++++++++++---------------------- 1 file changed, 24 insertions(+), 35 deletions(-) diff --git a/src/CheckersGameState2.java b/src/CheckersGameState2.java index e468788..37bbf2b 100644 --- a/src/CheckersGameState2.java +++ b/src/CheckersGameState2.java @@ -17,10 +17,13 @@ public class CheckersGameState2 implements CheckersGameState { public static void main(String args[]) { CheckersGameState2 state = new CheckersGameState2(); state.printState(); - List actions = state.actions(); - for(Move move : actions) { - System.out.println((Move2)move); - state.result(move).printState(); + for(int i = 0; i<6; i++){ + List actions = state.actions(); + for(Move move : actions) { + System.out.println((Move2)move+" ~~ "+((Move2)move).dest); + } + state = (CheckersGameState2)state.result(actions.get(0)); + state.printState(); } } @@ -119,42 +122,28 @@ public class CheckersGameState2 implements CheckersGameState { ArrayList moves = new ArrayList(); int piece = board[starting]; int[] neighbors = neighbors(current); + int beg, end; if(piece == 1) { - for(int i = 0; i<2; i++) { - if(neighbors[i] != -1 && isEnemy(board[neighbors[i]])) { - int next = neighbors(neighbors[i])[i]; - if(board[next] == 0) { - int [] newPath = Arrays.copyOf(path, path.length+1); - int c = capture == -1 ? neighbors[i] : capture; - moves.add(new Move2(newPath, c)); - moves.addAll(findJumpMoves(starting, next, newPath,c)); - } - } - } + beg = 0; + end = 2; } else if(piece == 2) { - for(int i = 2; i<4; i++) { - if(neighbors[i] != -1 && isEnemy(board[neighbors[i]])) { - int next = neighbors(neighbors[i])[i]; - if(board[next] == 0) { - int [] newPath = Arrays.copyOf(path, path.length+1); - int c = capture == -1 ? neighbors[i] : capture; - moves.add(new Move2(newPath, c)); - moves.addAll(findJumpMoves(starting, next, newPath, c)); - } - } - } + beg = 2; + end = 4; } else { - for(int i = 0; i<4; i++) { - if(neighbors[i] != -1 && isEnemy(board[neighbors[i]])) { - int next = neighbors(neighbors[i])[i]; - if(board[next] == 0) { - int [] newPath = Arrays.copyOf(path, path.length+1); - int c = capture == -1 ? neighbors[i] : capture; - moves.add(new Move2(newPath, c)); - moves.addAll(findJumpMoves(starting, next, newPath, c)); - } + beg = 0; + end = 4; + } + for(int i = beg; i Date: Sun, 2 Apr 2017 22:59:12 -0400 Subject: [PATCH 4/8] Change behaviors of captures and jump moves I changed this because of [this](https://piazza.com/class/iy9nmh0fyvc2jx?cid=40) piazza post. Hopefully this is correct. --- src/CheckersGameState2.java | 30 ++++++++++------- src/Move2.java | 65 ++++++++++++++++++++++++++++++++++--- 2 files changed, 78 insertions(+), 17 deletions(-) diff --git a/src/CheckersGameState2.java b/src/CheckersGameState2.java index 37bbf2b..8a7b57e 100644 --- a/src/CheckersGameState2.java +++ b/src/CheckersGameState2.java @@ -118,7 +118,7 @@ public class CheckersGameState2 implements CheckersGameState { return neighbors; } - private ArrayList findJumpMoves(int starting, int current, int[] path, int capture) { + private ArrayList findJumpMoves(int starting, int current, int[] path) { ArrayList moves = new ArrayList(); int piece = board[starting]; int[] neighbors = neighbors(current); @@ -141,9 +141,12 @@ public class CheckersGameState2 implements CheckersGameState { if(next != -1 && board[next] == 0) { int [] newPath = Arrays.copyOf(path, path.length+1); newPath[path.length] = next; - int c = capture == -1 ? neighbors[i] : capture; - moves.add(new Move2(newPath, c)); - moves.addAll(findJumpMoves(starting, next, newPath, c)); + ArrayList jumpMoves = findJumpMoves(starting, next, newPath); + if(jumpMoves.size() == 0){ + moves.add(new Move2(newPath)); + } else { + moves.addAll(jumpMoves); + } } } } @@ -155,7 +158,7 @@ public class CheckersGameState2 implements CheckersGameState { for(int i = 0; i<32; i++) { int piece = board[i]; if(piece != 0 && correctColor(piece)) { - captures.addAll(findJumpMoves(i, i, new int[]{i}, -1)); + captures.addAll(findJumpMoves(i, i, new int[]{i})); } } return captures; @@ -170,26 +173,26 @@ public class CheckersGameState2 implements CheckersGameState { if(space == 1) { // black piece if(neighbors[0] != -1 && board[neighbors[0]] == 0) { - moves.add(new Move2(i, neighbors[0], -1)); + moves.add(new Move2(i, neighbors[0])); } if(neighbors[1] != -1 && board[neighbors[1]] == 0) { - moves.add(new Move2(i, neighbors[1], -1)); + moves.add(new Move2(i, neighbors[1])); } } else if(space == 2) { // white piece if(neighbors[2] != -1 && board[neighbors[2]] == 0) { - moves.add(new Move2(i, neighbors[2], -1)); + moves.add(new Move2(i, neighbors[2])); } if(neighbors[3] != -1 && board[neighbors[3]] == 0) { - moves.add(new Move2(i, neighbors[3], -1)); + moves.add(new Move2(i, neighbors[3])); } } else { // king for(int j = 0; j<4; j++) { if(neighbors[j] != -1 && board[neighbors[j]] == 0) { - moves.add(new Move2(i, neighbors[j], -1)); + moves.add(new Move2(i, neighbors[j])); } } } @@ -213,8 +216,11 @@ public class CheckersGameState2 implements CheckersGameState { Move2 move = (Move2) x; int[] newBoard = Arrays.copyOf(board, board.length); int newPlayer = otherPlayer(); - if(move.captures != -1) { - newBoard[move.captures] = 0; + int[] captures = move.captures(); + if(captures[0] != -1) { + for(int i = 0; i=32) { + neighbors[i] = -1; + } + } + + return neighbors; + } + + public int[] captures() { + int[] captures = new int[path.length-1]; + for(int i = 0; i Date: Tue, 4 Apr 2017 19:57:26 -0400 Subject: [PATCH 5/8] Got GameState2 all working! It can play the checkers! --- src/CheckersGameState2.java | 43 ++++++++++++++++++++++++++++++++----- src/Move2.java | 8 +++++++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/CheckersGameState2.java b/src/CheckersGameState2.java index 8a7b57e..bffc613 100644 --- a/src/CheckersGameState2.java +++ b/src/CheckersGameState2.java @@ -4,6 +4,8 @@ import java.util.Arrays; public class CheckersGameState2 implements CheckersGameState { + // TODO: Fix king infinite recursion + // 0 = empty // 1 = black piece // 2 = white piece @@ -17,10 +19,11 @@ public class CheckersGameState2 implements CheckersGameState { public static void main(String args[]) { CheckersGameState2 state = new CheckersGameState2(); state.printState(); - for(int i = 0; i<6; i++){ + for(int i = 0; i<100; i++){ List actions = state.actions(); + if(actions.size()==0){break;} for(Move move : actions) { - System.out.println((Move2)move+" ~~ "+((Move2)move).dest); + System.out.println((Move2)move+" ~~ "+((Move2)move).destination()); } state = (CheckersGameState2)state.result(actions.get(0)); state.printState(); @@ -136,7 +139,8 @@ public class CheckersGameState2 implements CheckersGameState { end = 4; } for(int i = beg; i captures() { ArrayList captures = new ArrayList(); for(int i = 0; i<32; i++) { @@ -222,12 +237,30 @@ public class CheckersGameState2 implements CheckersGameState { newBoard[captures[i]] = 0; } } - newBoard[move.dest] = newBoard[move.src]; - newBoard[move.src] = 0; + newBoard[move.destination()] = newBoard[move.source()]; + newBoard[move.source()] = 0; + + if(promote(move.source(), move.destination())) { + newBoard[move.destination()] += 2; + } return new CheckersGameState2(newPlayer, newBoard); } + private boolean promote(int src, int dest) { + switch(board[src]) { + case 0: + return false; + case 1: + return dest>=28; + case 2: + return dest<=3; + case 3: case 4: + return false; + } + return false; + } + public void printState () { String output = ""; for(int i = 0; i<32; i++) { diff --git a/src/Move2.java b/src/Move2.java index 20e229e..027e060 100644 --- a/src/Move2.java +++ b/src/Move2.java @@ -15,6 +15,14 @@ public class Move2 implements Move { path = p; } + public int source() { + return src; + } + + public int destination() { + return dest; + } + private int[] neighbors(int index) { int[] neighbors = new int[4]; int row = (index - index%4)/4; From 9d84c5ed8716bc844a3db3faa841161a3bf246ff Mon Sep 17 00:00:00 2001 From: Sailesh Date: Tue, 4 Apr 2017 20:59:53 -0400 Subject: [PATCH 6/8] Fix bug in jumps --- src/CheckersGameState2.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CheckersGameState2.java b/src/CheckersGameState2.java index bffc613..3ec0ba0 100644 --- a/src/CheckersGameState2.java +++ b/src/CheckersGameState2.java @@ -124,6 +124,7 @@ public class CheckersGameState2 implements CheckersGameState { private ArrayList findJumpMoves(int starting, int current, int[] path) { ArrayList moves = new ArrayList(); int piece = board[starting]; + board[starting] = 0; int[] neighbors = neighbors(current); int beg, end; if(piece == 1) { @@ -154,6 +155,7 @@ public class CheckersGameState2 implements CheckersGameState { } } } + board[starting] = piece; return moves; } From 14edbbfc938bdfb3b0cbfb78462c9177c7fb7bfa Mon Sep 17 00:00:00 2001 From: Sailesh Date: Tue, 4 Apr 2017 21:04:31 -0400 Subject: [PATCH 7/8] Added test for diamond move --- src/CheckersGameState2.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/CheckersGameState2.java b/src/CheckersGameState2.java index 3ec0ba0..4d47c51 100644 --- a/src/CheckersGameState2.java +++ b/src/CheckersGameState2.java @@ -28,6 +28,18 @@ public class CheckersGameState2 implements CheckersGameState { state = (CheckersGameState2)state.result(actions.get(0)); state.printState(); } + int[] b = new int[32]; + b[5] = 3; + b[8] = 2; + b[16] = 2; + b[17] = 2; + b[9] = 2; + CheckersGameState s = new CheckersGameState2(1, b); + s.printState(); + for(Move m: s.actions()){ + System.out.println(m); + } + } public CheckersGameState2(int player, int[] board) { From 668f9436660208334129a45d651afbd9a986ef57 Mon Sep 17 00:00:00 2001 From: Sailesh Date: Tue, 4 Apr 2017 21:51:30 -0400 Subject: [PATCH 8/8] Fix bug in result function --- src/CheckersGameState3.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/CheckersGameState3.java b/src/CheckersGameState3.java index c46313b..0cbef6b 100644 --- a/src/CheckersGameState3.java +++ b/src/CheckersGameState3.java @@ -240,7 +240,16 @@ public class CheckersGameState3 implements CheckersGameState{ newState[k] = 0; } } - return new CheckersGameState3(1 - this.player, newState); + return new CheckersGameState3(other(this.player), newState); + } + + private int other(int player){ + if(player == 1){ + return 2; + } + else{ + return 1; + } } public void printState(){