Skip to content

A game of chinese checkers implemented in java with graphs using jGraphT with "perfect game" AI.

License

Notifications You must be signed in to change notification settings

HarryZalessky/Chinese-Checkers

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Chinese Checkers

Background on the game and rules

Background on the game

Chinese checkers (US and Canadian spelling) or Chinese chequers (UK spelling) is a strategy board game of German origin (named "Sternhalma") which can be played by two, three, four, or six people, playing individually or with partners. The game is a modern and simplified variation of the game Halma.

The objective is to be first to race all of one's pieces across the hexagram-shaped board into "home"—the corner of the star opposite one's starting corner—using single-step moves or moves that jump over other pieces. The remaining players continue the game to establish second-, third-, fourth-, fifth-, and last-place finishers. The rules are simple, so even young children can play.

Chinese checkers board
Figure 1 - Chinese Checkers Board with 6 player sets

Despite its name, the game isn't a variation of checkers, nor did it originate in China or any part of Asia (whereas the game 象棋 xiangqi, or "Chinese chess", is from China). The game was invented in Germany in 1892 under the name "Stern-Halma" as a variation of the older American game Halma. The "Stern" (German for star) refers to the board's star shape (in contrast to the square board used in Halma).

The name "Chinese Checkers" originated in the United States as a marketing scheme by Bill and Jack Pressman in 1928. The Pressman company's game was originally called "Hop Ching Checkers".

The game was introduced to Chinese-speaking regions mostly by the Japanese.

Rules

The goal of the game

To race all one's pieces into the star corner on the opposite side of the board before opponents do the same.

Structure of the board

The game goard is made of 121 cells ordered in the shape of a six pointed star (Star of David), while the small triangles that make its corners are made of 10 cells each.

Chinese checkers board

Starting layout

Each player sets his 10 pieces in one of the board corners. When two players play, like in our case, the pieces go in opposing corners of the board.

Game progression

Players take turns moving a single piece, either by moving one step in any direction to an adjacent empty space, or by jumping in one or any number of available consecutive hops over other single pieces. A player may not combine hopping with a single-step move – a move consists of one or the other. There is no capturing in Chinese Checkers, so hopped pieces remain active and in play.

Chinese checkers piece movement options

The winner

The first to move all 10 of his game pieces to the opposing base.


Data structure

The game board is represented with an undirected and unweighted graph, consisting of 121 vertexes (one for each cell on the board). The maximum degree for each vertex is 6, the minimum degree is 2, and it is connected with an edge to each of its neighbours. In addition, the vertexes are placed in a matrix using which we get the location of the vertex on the board and print the vertex on screen.

The empty matrix.

The matrix with the game pieces.

public class GraphFacilities {
	public static final int W=25, H=17;
	public static CellVertex[][] vertexMat = new CellVertex[H][W];
	public static Graph<CellVertex, CCEdge> g = new SimpleGraph<CellVertex, CCEdge>(CCEdge.class);
}

Every vertex contains the following data:

  • A field that contains info about the occupation of the cell:
    • 0 - Empty cell.
    • 1 - The cell is occupied with a piece belonging to the AI player.
    • 2 - The cell is occupied with a piece belonging to the human player.
  • A field that contains the position of the vertex in the matrix.

public class CellVertex {
	public int content; // The content of the vertex
	private Point l; // The location of the vertex in the graph
}

At the start, the program creates an array of all possible edges and updates the graph accordingly.

On every turn, the player (human or AI) get all the places where they can move the chosen piece.

They choose the destination cell, and the program checks if the current player won.

If he didn't win the program updates the active edges and passes the turn to the opponent.

The reasons to use a graph over other data structures are:
  • It is possible to find all possible jumps from a given vertex at O(1) complexity.
  • It is possible to calculate a path at O(E log(V)) complexity.


The main algorithm

AI move strategy

1. Calculate amount of pieces not in destination base (Function 1).
2. If only one piece isn't in the destination base:
2.1. For every piece belonging to the AI:
2.1.1. If the pieace isn't in the destination base:
2.1.1.1. For every cell in the destination base:
2.1.1.1.1. If the cell is empty:
2.1.1.1.1.1. Set the cell as path end.
2.1.1.2. Calculate the shortest path from piece location to path end location.
2.1.1.3. Set move start location as the first vertex in the path.
2.1.1.4. Set move end location as the second vertex in the path.
2.1.1.5. Do the move (Function 9).
2.1.1.6. Update the piece location to the new location.
2.1.1.7. End turn (Function 7).
3. If there is a piece able to perform an S1 move (Function 2):
3.1. Find the index of the piece in the AI pieces array (Function 3).
3.2. Set the move start location to the piece location.
3.3. Set the move end location to the S move end location (4 rows forward, same column).
3.4. Do the move (Function 9).
3.5. Update the piece location to the new location.
3.6. End turn (Function 7).
4. Else if the left outermost piece2 is in its original place:
4.1. Set its location as the move start location.
4.2. Set the move end location (1 row down, 1 column right).
4.3. Do the move (Function 9).
4.4. Update the piece location to the new location.
4.5. End turn (Function 7).
5. Else if the right outermost piece2 is in its original place:
5.1. Set its location as the move start location.
5.2. Set the move end location (1 row down, 1 column left).
5.3. Do the move (Function 9).
5.4. Update the piece location to the new location.
5.5. End turn (Function 7).
6. Else:
6.1. Find farthest jump (Function 4).
6.2. If jump exists:
6.2.1. Set move start location to jumping piece location.
6.2.2. Set move end location to jump end location.
6.2.3. Do the move (Function 9).
6.2.4. Update the piece location to the new location.
6.2.5. End turn (Function 7).
6.3. Else:
6.3.1. For every piece from the rearmost:
6.3.1.1. Set its location as the move start location.
6.3.1.2. Reset board (Function 8).
6.3.1.3. Find optional moves for the piece (Function 5).
6.3.1.4. If it can move forward and centerward:
6.3.1.4.1. Set move end location to the said location.
6.3.1.4.2. Do the move (Function 9).
6.3.1.4.3. Update the piece location to the new location.
6.3.1.4.4. End turn (Function 7).
6.3.1.5. Else if it is in the center and can move forward:
6.3.1.5.1. Set move end location to the said location.
6.3.1.5.2. Do the move (Function 9).
6.3.1.5.3. Update the piece location to the new location.
6.3.1.5.4. End turn (Function 7).
6.3.1.6. Else if it move Centerward:
6.3.1.6.1. Set move end location to the said location.
6.3.1.6.2. Do the move (Function 9).
6.3.1.6.3. Update the piece location to the new location.
6.3.1.6.4. End turn (Function 7).
6.3.1.7. Else if it can move forward:
6.3.1.7.1. Set move end location to the said location.
6.3.1.7.2. Do the move (Function 9).
6.3.1.7.3. Update the piece location to the new location.
6.3.1.7.4. End turn (Function 7).

1. An s move is a jump move involving 4 pieces belonging to the player. The rearmost piece jumps twice so its final position is 4 rows forward and in the same column.
2. The outermost piece is the piece located in one of the base corners of the triangle (tangent to the neutral zone) at game start.


Function 1: countOutsideSoldiers

1. Initialize a counter to 10.
2. For every cell in the destination base:
2.1. If the cell has an AI piece:
2.1.1. Decrement counter.
3. Return counter.

Function 2: is_S_TurnExist

1. For every cell on the board starting rearmost:
1.1. If the cell contains an AI piece:
1.2. Reset board (Function 8).
1.3. Find optional moves for the piece (Function 5).
1.4. If an AI piece exists at (same column, 2 rows down) and a target exists at (same column, 4 rows down) and either an AI piece exists at (1 column left, 1 row down) and at (1 column left, 3 rows down) and a target exists at (2 columns left, 2 rows down) or an AI piece exists at (1 column right, 1 row down) and at (1 column right, 3 rows down) and a target exists at (2 columns right, 2 rows down):
1.4.1. Return soldier position.
2. Return null.

Function 3: findCpuPlayerIndex

1. If passed location is a cell:
1.1. For every AI piece:
1.1.1. If the piece is in the passed location:
1.1.1.1. Return piece index.
2) Return -1.

Function 4: findFarthestJump

1. Initalize "longest jump" variable to null.
2. For every AI piece from rearmost:
2.1. Reset board (Function 8).
2.2. Find its optional jumps (Function 6).
2.3. For every possible jump forwards and/or centerwards:
2.3.1. If "longest jump" is null:
2.3.1.1. If the jump advances the piece forwards and/or centerwards:
2.3.1.1.1. Set the jump as the longest jump.
2.3.2. Else if the jump advances the piece farther than the longest jump or to the same row but closer to the center than the longest jump:
2.3.2.1. Set the jump as the longest jump.
3. Return the longest jump.

Function 5: optionalPlays

1. Create empty location set.
2. For every edge outgoing from the passed location:
2.1. If the other cell is empty:
2.1.1. Set the cell as possible target.
2.1.2. Add cell location to location set.
2.1.3 If the edge is a jump:
2.1.3.1. Find all optional jumps from the passed location (Function 6).
2.1.3.2. Add all jumps to location set.
3. Return location set.

Function 6: optionalPlaysLen3

1. Create empty location set.
2. For every edge outgoing from the passed location:
2.1. If the other cell is empty and if the edge is a jump:
2.1.1. Set the cell as possible target.
2.1.2. Add cell location to location set.
2.1.3. Find all optional jumps from the passed location (Function 6).
2.1.4. Add all jumps to location set.
3. Return location set.

Function 7: endTurn

1. Reset board (Function 8).
2. If no one won yet:
2.1. Switch active player.
2.2. Reset touch.

Function 8: resetBoard

1. For every graph cell:
1.1. If it doesn't contain a piece but isn't empty (Past piece or a target):
1.1.1. Empty the cell.
2. Update graph edges (Function 10).

Function 9: Move

1. Set move end location to current player's piece.
2. Set move start location to past piece.

Function 10: updateGraph

1. For every edge in the edges array:
1.1. If the edge connects 2 adjacent cells and the edge doesn't exist:
1.1.1. Add the edge.
1.2. Else if the edge jumps over an occupied cell:
1.2.1. Add the edge.
1.3. Else if the edge exists:
1.3.1. Delete the edge.

Function 11: win

1. Initialize a boolian variable for each player to true.
2. For each cell in the home bases of the players:
2.1. If the cell is occupied with an opponent piece:
2.1.1. Set the opponent's variable to itself.
2.2. Else:
2.2.1 Set the opponent's variable to false 3. If the human player's variableis true:
3.1. Show appropriate message.
3.2. Return true.
4. If the AI player's variableis true:
4.1. Show appropriate message.
4.2. Return true.
5. Return false


The code

AI:

public void AI() {
	int i;
	// If only one player is outside
	if (countOutsideSoldiers() == 1) {
		CellVertex dest = null;
		for (i = 0; i < cpuSoldiers.length; i++) {
			if (cpuSoldiers[i].y < 13) {
				for (int h = 13; h < GraphFacilities.H; h++) {
					for (int j = 9 + (h - 13); j < 16 - (h - 13); j += 2) {
						if (GraphFacilities.vertexMat[h][j].content == PlayerAffiliation.NONE) {
							dest = GraphFacilities.vertexMat[h][j];
						}
					}
				}
				List<CellVertex> path = GraphFacilities.findShortestPathLength(
					GraphFacilities.vertexMat[cpuSoldiers[i].y][cpuSoldiers[i].x], dest).getVertexList();
				setTx(path.get(0).getLocation().x);
				setTy(path.get(0).getLocation().y);
				Move(path.get(1).getLocation().y, path.get(1).getLocation().x);
				cpuSoldiers[i].setLocation(path.get(1).getLocation());
				return;
			}
		}
	}
	// If there's an S turn available
	if ((i = findCpuPlayerIndex(is_S_TurnExist())) > -1) {
		setTx(cpuSoldiers[i].x);
		setTy(cpuSoldiers[i].y);
		Move(cpuSoldiers[i].y + 4, cpuSoldiers[i].x);
		cpuSoldiers[i].y += 4;
	} else {
		if (cpuSoldiers[6].getLocation().equals(new Point(9, 3))
				&& GraphFacilities.vertexMat[4][10].content != PlayerAffiliation.HUMAN_PLAYER
				&& GraphFacilities.vertexMat[4][10].content != PlayerAffiliation.CPU_PLAYER) {
			setTx(9);
			setTy(3);
			Move(4, 10);
			cpuSoldiers[6].setLocation(10, 4);
		} else if (cpuSoldiers[9].getLocation().equals(new Point(15, 3))
				&& GraphFacilities.vertexMat[4][14].content != PlayerAffiliation.HUMAN_PLAYER
				&& GraphFacilities.vertexMat[4][14].content != PlayerAffiliation.CPU_PLAYER) {
			setTx(15);
			setTy(3);
			Move(4, 14);
			cpuSoldiers[9].setLocation(14, 4);
		} else {
			CCEdge jump = findFarthestJump();
			if (jump != null) {
				setTx(jump.getSrcVertx().getLocation().x);
				setTy(jump.getSrcVertx().getLocation().y);
				Move(jump.getDestVertx().getLocation().y, jump.getDestVertx().getLocation().x);
				cpuSoldiers[findCpuPlayerIndex(jump.getSrcVertx().getLocation())].setLocation(jump.getDestVertx().getLocation());
			} else {
				for (i = 0; i < GraphFacilities.H; i++) {
					for (i = 0; i < GraphFacilities.H; i++) {
						for (int j = 0; j < GraphFacilities.W; j++) {
							if (GraphFacilities.vertexMat[i][j] != null
									&& GraphFacilities.vertexMat[i][j].content == PlayerAffiliation.CPU_PLAYER) {
								setTx(j);
								setTy(i);
								resetBoard();
								Set<Point> points = optinalPlays(tx, ty);
								Iterator<Point> it = points.iterator();
								while (it.hasNext()) {
									Point p = it.next();
									if ((p.y > ty
											&& ((Math.abs(tx - GraphFacilities.W / 2) > Math.abs(p.x - GraphFacilities.W / 2))
											|| (Math.abs(tx - GraphFacilities.W / 2) == 0)))) {
										Move(p.y, p.x);
										cpuSoldiers[findCpuPlayerIndex(new Point(tx, ty))].setLocation(p);
										return;
									}
								}
								it = points.iterator();
								while (it.hasNext()) {
									Point p = it.next();
									if ((p.y == ty && Math.abs(tx - GraphFacilities.W / 2) > Math.abs(p.x - GraphFacilities.W / 2))) {
										Move(p.y, p.x);
										cpuSoldiers[findCpuPlayerIndex(new Point(tx, ty))].setLocation(p);
										return;
									}
								}
								it = points.iterator();
								while (it.hasNext()) {
									Point p = it.next();
									if (p.y > i) {
										Move(p.y, p.x);
										cpuSoldiers[findCpuPlayerIndex(new Point(tx, ty))].setLocation(p);
										return;
									}
								}
							}
						}
					}
				}
			}
		}
	}
}

countOutsideSoldiers:

private int countOutsideSoldiers() {
	int counter = 10;
	for (int i = 13; i < GraphFacilities.H; i++) {
		for (int j = 9 + (i - 13); j < 16 - (i - 13); j += 2) {
			if (GraphFacilities.vertexMat[i][j].content == PlayerAffiliation.CPU_PLAYER) {
				counter--;
			}
		}
	}
	return counter;
}

Move:

public void Move(int y, int x) {
	GraphFacilities.vertexMat[y][x].content = player;
	GraphFacilities.vertexMat[ty][tx].content = 99;
}

is_S_TurnExist:

private Point is_S_TurnExist() {
	for (int i = GraphFacilities.vertexMat.length - 1; i >= 0; i--) {
		for (int j = GraphFacilities.vertexMat[i].length - 1; j >= 0; j--) {
			if (GraphFacilities.vertexMat[i][j] != null && GraphFacilities.vertexMat[i][j].content == PlayerAffiliation.CPU_PLAYER) {
				resetBoard();
				optinalPlays(j, i);
				if (i + 4 < GraphFacilities.vertexMat.length
						&& GraphFacilities.vertexMat[i + 4][j] != null
						&& j - 1 > 0 && j + 1 < GraphFacilities.vertexMat[i].length
						&& GraphFacilities.vertexMat[i + 2][j].content == PlayerAffiliation.CPU_PLAYER
						&& GraphFacilities.vertexMat[i + 4][j].content == PlayerAffiliation.POSSIBLE_CPU_TARGET
						&& ((GraphFacilities.vertexMat[i + 1][j + 1].content == PlayerAffiliation.CPU_PLAYER
						&& GraphFacilities.vertexMat[i + 3][j + 1].content == PlayerAffiliation.CPU_PLAYER
						&& GraphFacilities.vertexMat[i + 2][j + 2].content == PlayerAffiliation.POSSIBLE_CPU_TARGET)
						|| (GraphFacilities.vertexMat[i + 1][j - 1].content == PlayerAffiliation.CPU_PLAYER
						&& GraphFacilities.vertexMat[i + 3][j - 1].content == PlayerAffiliation.CPU_PLAYER
						&& GraphFacilities.vertexMat[i + 2][j - 2].content == PlayerAffiliation.POSSIBLE_CPU_TARGET))) {
					return new Point(j, i);
				}
			}
		}
	}
	return null;
}

findCpuPlayerIndex:

private int findCpuPlayerIndex(Point p) {
	if (p != null) {
		for (int i = 0; i < cpuSoldiers.length; i++) {
			if (cpuSoldiers[i].equals(p)) {
				return i;
			}
		}
	}
	return -1;
}

endTurn:

public void endTurn() {
	resetBoard();
	if (!win()) {
		player = (player == PlayerAffiliation.CPU_PLAYER) ? PlayerAffiliation.HUMAN_PLAYER : PlayerAffiliation.CPU_PLAYER;
		ty = 0;
		tx = 0;
	}
}

resetBoard:

public void resetBoard() {
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (GraphFacilities.vertexMat[i][j] != null && GraphFacilities.vertexMat[i][j].content > 9) {
				GraphFacilities.vertexMat[i][j].content = PlayerAffiliation.NONE;
			}
		}
	}
	GraphFacilities.updateGraph(coordMat);
}

findFarthestJump:

private CCEdge findFarthestJump() {
	CCEdge jump = null;
	for (int i = 0; i < GraphFacilities.vertexMat.length; i++) {
		for (int j = 0; j < GraphFacilities.vertexMat[i].length; j++) {
			if (GraphFacilities.vertexMat[i][j] != null && GraphFacilities.vertexMat[i][j].content == PlayerAffiliation.CPU_PLAYER) {
				resetBoard();
				optinalPlaysLen3(j, i);
				for (int h = i; h < GraphFacilities.vertexMat.length; h++) {
					for (int g = 0; g < GraphFacilities.vertexMat[h].length; g++) {
						if (GraphFacilities.vertexMat[h][g] != null
								&& GraphFacilities.vertexMat[h][g].content == PlayerAffiliation.POSSIBLE_CPU_TARGET) {
							if (jump != null) {
								if ((jump.getDestVertx().getLocation().y < h) 
										|| (jump.getDestVertx().getLocation().y == h
										&& Math.abs(jump.getDestVertx().getLocation().x - (GraphFacilities.W / 2)) > Math.abs(g - (GraphFacilities.W / 2)))) {
									if ((i < h)
											|| (i == h
											&& Math.abs(j - (GraphFacilities.W / 2)) > Math.abs(g - (GraphFacilities.W / 2)))) {
										jump.setSrcVertx(GraphFacilities.vertexMat[i][j]);
										jump.setDestVertx(GraphFacilities.vertexMat[h][g]);
									}
								}
							} else {
								if ((i < h)
										|| (i == h
										&& Math.abs(j - (GraphFacilities.W / 2)) > Math.abs(g - (GraphFacilities.W / 2)))) {
									jump = new CCEdge(GraphFacilities.vertexMat[i][j], GraphFacilities.vertexMat[h][g]);
								}
							}
						}
					}
				}
			}
		}
	}
	return jump;
}

updateGraph:

public static void updateGraph(Point[][] edgeArr) {
	for (int i = 0; i < edgeArr.length; i++) {
		if (edgeArr[i].length == 2) {
			addEdge(edgeArr[i][0].y, edgeArr[i][0].x, edgeArr[i][1].y, edgeArr[i][1].x);
		} else {
			if (vertexMat[edgeArr[i][1].y][edgeArr[i][1].x].getContent() == PlayerAffiliation.CPU_PLAYER
					|| vertexMat[edgeArr[i][1].y][edgeArr[i][1].x].getContent() == PlayerAffiliation.HUMAN_PLAYER) {
				addEdge(edgeArr[i][0].y, edgeArr[i][0].x, edgeArr[i][2].y, edgeArr[i][2].x);
			} else {
				g.removeEdge(vertexMat[edgeArr[i][0].y][edgeArr[i][0].x], vertexMat[edgeArr[i][2].y][edgeArr[i][2].x]);
			}
		}
	}
}

optinalPlays:

public Set<Point> optinalPlays(int x, int y) {
	Set<Point> endPoints = new HashSet<>();
	Set<CCEdge> edges = GraphFacilities.g.outgoingEdgesOf(GraphFacilities.vertexMat[y][x]);
	Iterator<CCEdge> it = edges.iterator();
	while (it.hasNext()) {
		CCEdge edge = it.next();
		// Source isn't the origin.
		if (!edge.getSrcVertx().getLocation().equals(new Point(x, y))) {
			// Cell empty
			if (edge.getSrcVertx().content != PlayerAffiliation.CPU_PLAYER
					&& edge.getSrcVertx().content != PlayerAffiliation.HUMAN_PLAYER) {
				if (player == PlayerAffiliation.HUMAN_PLAYER) {
					edge.getSrcVertx().content = PlayerAffiliation.POSSIBLE_HUMAN_TARGET;
				} else {
					edge.getSrcVertx().content = PlayerAffiliation.POSSIBLE_CPU_TARGET;
				}
				endPoints.add(edge.getSrcVertx().getLocation());
				if (edge.getSrcVertx().getLocation().y - 2 == edge.getDestVertx().getLocation().y
						|| edge.getSrcVertx().getLocation().y + 2 == edge.getDestVertx().getLocation().y
						|| edge.getSrcVertx().getLocation().x - 4 == edge.getDestVertx().getLocation().x
						|| edge.getSrcVertx().getLocation().x + 4 == edge.getDestVertx().getLocation().x) {
					endPoints.addAll(optinalPlaysLen3(edge.getSrcVertx().getLocation().x, edge.getSrcVertx().getLocation().y));
				}
			}
		} else {
			// Cell empty
			if (edge.getDestVertx().content != PlayerAffiliation.CPU_PLAYER
					&& edge.getDestVertx().content != PlayerAffiliation.HUMAN_PLAYER) {
				if (player == PlayerAffiliation.HUMAN_PLAYER) {
					edge.getDestVertx().content = PlayerAffiliation.POSSIBLE_HUMAN_TARGET;
				} else {
					edge.getDestVertx().content = PlayerAffiliation.POSSIBLE_CPU_TARGET;
				}
				endPoints.add(edge.getDestVertx().getLocation());
				if (edge.getSrcVertx().getLocation().y - 2 == edge.getDestVertx().getLocation().y
						|| edge.getSrcVertx().getLocation().y + 2 == edge.getDestVertx().getLocation().y
						|| edge.getSrcVertx().getLocation().x - 4 == edge.getDestVertx().getLocation().x
						|| edge.getSrcVertx().getLocation().x + 4 == edge.getDestVertx().getLocation().x) {
					endPoints.addAll(optinalPlaysLen3(edge.getDestVertx().getLocation().x, edge.getDestVertx().getLocation().y));
				}
			}
		}
	}
	return endPoints;
}

optinalPlaysLen3

public Set<Point> optinalPlaysLen3(int x, int y) {
	Set<Point> endPoints = new HashSet<>();
	Set<CCEdge> edges = GraphFacilities.g.outgoingEdgesOf(GraphFacilities.vertexMat[y][x]);
	Iterator<CCEdge> it = edges.iterator();
	while (it.hasNext()) {
		CCEdge edge = it.next();
		// Source isn't the origin.
		if (!edge.getSrcVertx().getLocation().equals(new Point(x, y))) {
			// Cell empty
			if (edge.getSrcVertx().content == PlayerAffiliation.NONE) {
				if (edge.getSrcVertx().getLocation().y - 2 == edge.getDestVertx().getLocation().y
						|| edge.getSrcVertx().getLocation().y + 2 == edge.getDestVertx().getLocation().y
						|| edge.getSrcVertx().getLocation().x - 4 == edge.getDestVertx().getLocation().x
						|| edge.getSrcVertx().getLocation().x + 4 == edge.getDestVertx().getLocation().x) {
					if (player == PlayerAffiliation.HUMAN_PLAYER) {
						edge.getSrcVertx().content = PlayerAffiliation.POSSIBLE_HUMAN_TARGET;
					} else {
						edge.getSrcVertx().content = PlayerAffiliation.POSSIBLE_CPU_TARGET;
					}
					endPoints.add(edge.getSrcVertx().getLocation());
					endPoints.addAll(optinalPlaysLen3(edge.getSrcVertx().getLocation().x, edge.getSrcVertx().getLocation().y));
				}
			}
		} else {
			// Cell empty
			if (edge.getDestVertx().content == PlayerAffiliation.NONE) {
				if (edge.getSrcVertx().getLocation().y - 2 == edge.getDestVertx().getLocation().y
						|| edge.getSrcVertx().getLocation().y + 2 == edge.getDestVertx().getLocation().y
						|| edge.getSrcVertx().getLocation().x - 4 == edge.getDestVertx().getLocation().x
						|| edge.getSrcVertx().getLocation().x + 4 == edge.getDestVertx().getLocation().x) {
					if (player == PlayerAffiliation.HUMAN_PLAYER) {
						edge.getDestVertx().content = PlayerAffiliation.POSSIBLE_HUMAN_TARGET;
					} else {
						edge.getDestVertx().content = PlayerAffiliation.POSSIBLE_CPU_TARGET;
					}
					endPoints.add(edge.getDestVertx().getLocation());
					endPoints.addAll(optinalPlaysLen3(edge.getDestVertx().getLocation().x, edge.getDestVertx().getLocation().y));
				}
			}
		}
	}
	return endPoints;
}

Win:

public boolean win() {
	boolean p1 = true, p2 = true;
	for (int i = 0; i < 10 && (p1 || p2); i++) {
		p1 = (GraphFacilities.vertexMat[win[i][0]][win[i][1]].content == PlayerAffiliation.HUMAN_PLAYER && p1);
		p2 = (GraphFacilities.vertexMat[(H - 1) - win[i][0]][win[i][1]].content == PlayerAffiliation.CPU_PLAYER && p2);
	}
	if (p1) {
		if (status == 2) {
			JOptionPane.showConfirmDialog(null, "Blue Player Won!", "Winner", JOptionPane.CLOSED_OPTION,
				JOptionPane.INFORMATION_MESSAGE);
		} else {
			JOptionPane.showConfirmDialog(null, "You Won!", "Winner", JOptionPane.CLOSED_OPTION, JOptionPane.INFORMATION_MESSAGE);
		}
		player = PlayerAffiliation.NONE;
		return true;
	} else if (p2) {
		if (status == 2) {
			JOptionPane.showConfirmDialog(null, "Red Player Won!", "Winner", JOptionPane.CLOSED_OPTION,
				JOptionPane.INFORMATION_MESSAGE);
		} else {
			JOptionPane.showConfirmDialog(null, "The Computer Won!", "Winner", JOptionPane.CLOSED_OPTION,
				JOptionPane.INFORMATION_MESSAGE);
		}
		player = PlayerAffiliation.NONE;
		return true;
	}
	return false;
}

About

A game of chinese checkers implemented in java with graphs using jGraphT with "perfect game" AI.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published