update,
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
package com.game.tictacteo.engine;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.game.tictacteo.localDB.GameLogDB;
|
||||
import com.game.tictacteo.model.GameLog;
|
||||
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Date;
|
||||
|
||||
public class Game {
|
||||
|
||||
private Timestamp startTime;
|
||||
private Timestamp endTime;
|
||||
private GameBoard board;
|
||||
private Context ctx;
|
||||
|
||||
|
||||
public Game(Context ctx) {
|
||||
startTime = new Timestamp(System.currentTimeMillis());
|
||||
board = new GameBoard();
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
// User move
|
||||
public GameStatus player1Place(int row, int col) throws GameBoardPlacedException {
|
||||
|
||||
GameStatus gs = place(row, col, 1);
|
||||
checkGameStatus(gs); // check status if won not need AI move
|
||||
if (gs.status == GameBoard.Status.CONTINUE) {
|
||||
gs = aiPlayerPlace();
|
||||
checkGameStatus(gs); // check status
|
||||
}
|
||||
return gs;
|
||||
}
|
||||
|
||||
private GameStatus place(int row, int col, int player) throws GameBoardPlacedException {
|
||||
|
||||
if (player == 1)
|
||||
return this.board.placePlayer1(row, col);
|
||||
else if (player == 2)
|
||||
return this.board.placePlayer2(row, col);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void checkGameStatus(GameStatus gs) {
|
||||
// check status if Player1 or Player2 win need to insert the log to db
|
||||
if (gs.status != GameBoard.Status.CONTINUE) {
|
||||
endTime = new Timestamp(System.currentTimeMillis());
|
||||
int duration = (int) ((endTime.getTime() - startTime.getTime()) / 1000);
|
||||
|
||||
int winingStatus = ((gs.status == GameBoard.Status.DRAW) ? 2 : (gs.status == GameBoard.Status.PLAYER2_WIN) ? 0 : 1);
|
||||
GameLogDB.getInstance(this.ctx).addLog(new GameLog(new Date(endTime.getTime()), new Time(endTime.getTime()), duration, winingStatus));
|
||||
}
|
||||
}
|
||||
|
||||
// AI move
|
||||
private GameStatus aiPlayerPlace() throws GameBoardPlacedException {
|
||||
Log.i("game-OBJ-AI", "aiPLayerPlace");
|
||||
int[] move = GameAI.findBestMove(board.getBoard());
|
||||
return place(move[0], move[1], 2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,151 @@
|
||||
package com.game.tictacteo.engine;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class GameAI {
|
||||
|
||||
static final byte player = 2;
|
||||
static final byte opponent = 1;
|
||||
|
||||
private static Boolean isMovesLeft(byte board[][]) {
|
||||
for (int i = 0; i < board.length; i++)
|
||||
for (int j = 0; j < board[i].length; j++)
|
||||
if (board[i][j] == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int evaluate(byte[][] board) {
|
||||
// Checking for Rows is player or opponent victory.
|
||||
for (int row = 0; row < board.length; row++) {
|
||||
if (board[row][0] == board[row][1] &&
|
||||
board[row][1] == board[row][2]) {
|
||||
if (board[row][0] == player)
|
||||
return +10;
|
||||
else if (board[row][0] == opponent)
|
||||
return -10;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int col = 0; col < board[0].length; col++) {
|
||||
if (board[0][col] == board[1][col] &&
|
||||
board[1][col] == board[2][col]) {
|
||||
if (board[0][col] == player)
|
||||
return +10;
|
||||
|
||||
else if (board[0][col] == opponent)
|
||||
return -10;
|
||||
}
|
||||
}
|
||||
|
||||
if (board[0][0] == board[1][1] && board[1][1] == board[2][2]) {
|
||||
if (board[0][0] == player)
|
||||
return +10;
|
||||
else if (board[0][0] == opponent)
|
||||
return -10;
|
||||
}
|
||||
|
||||
if (board[0][2] == board[1][1] && board[1][1] == board[2][0]) {
|
||||
if (board[0][2] == player)
|
||||
return +10;
|
||||
else if (board[0][2] == opponent)
|
||||
return -10;
|
||||
}
|
||||
|
||||
// Else if none of them have won then return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int minimax(byte board[][], int depth, Boolean isMax) {
|
||||
int score = evaluate(board);
|
||||
|
||||
// Evaluated score if Maximizer has won the game
|
||||
if (score == 10)
|
||||
return score;
|
||||
|
||||
if (score == -10)
|
||||
return score;
|
||||
|
||||
// no winner then it is a tie if false
|
||||
if (isMovesLeft(board) == false)
|
||||
return 0;
|
||||
|
||||
if (isMax) {
|
||||
int best = -1000;
|
||||
|
||||
// Traverse all cells
|
||||
for (int i = 0; i < board.length; i++) {
|
||||
for (int j = 0; j < board[i].length; j++) {
|
||||
// Check cell is empty
|
||||
if (board[i][j] == 0) {
|
||||
// Make the move
|
||||
board[i][j] = player;
|
||||
|
||||
// calculate minimax recursively and choose
|
||||
best = Math.max(best, minimax(board, depth + 1, !isMax));
|
||||
|
||||
// Undo move
|
||||
board[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}else {
|
||||
int best = 1000;
|
||||
|
||||
// Traverse all cells
|
||||
for (int i = 0; i < board.length; i++) {
|
||||
for (int j = 0; j < board[i].length; j++) {
|
||||
// Check cell is empty
|
||||
if (board[i][j] == 0) {
|
||||
// Make the move
|
||||
board[i][j] = opponent;
|
||||
|
||||
// calculate minimax recursively and choose
|
||||
best = Math.min(best, minimax(board,
|
||||
depth + 1, !isMax));
|
||||
|
||||
// Undo move
|
||||
board[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] findBestMove(byte board[][]) {
|
||||
int bestVal = -1000;
|
||||
int[] bestMove = new int[2];
|
||||
bestMove[0] = -1;
|
||||
bestMove[1] = -1;
|
||||
|
||||
// evaluate minimax func
|
||||
for (int i = 0; i < board.length; i++) {
|
||||
for (int j = 0; j < board[i].length; j++) {
|
||||
// Check cell is empty
|
||||
if (board[i][j] == 0) {
|
||||
// Make the move
|
||||
board[i][j] = player;
|
||||
|
||||
// compute evaluation function
|
||||
int moveVal = minimax(board, 0, false);
|
||||
|
||||
// Undo the move
|
||||
board[i][j] = 0;
|
||||
|
||||
// If the value of the current move is higher then best value, then update
|
||||
if (moveVal > bestVal) {
|
||||
bestMove[0] = i;
|
||||
bestMove[1] = j;
|
||||
bestVal = moveVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bestMove;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,139 @@
|
||||
package com.game.tictacteo.engine;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class GameBoard {
|
||||
|
||||
private final static int ROW = 3; // Game Board ROW
|
||||
private final static int COL = 3; // Game Board COL
|
||||
|
||||
private byte[][] board;
|
||||
private short step;
|
||||
private short winner; // Winner
|
||||
|
||||
public enum Status {
|
||||
CONTINUE,
|
||||
PLAYER1_WIN,
|
||||
PLAYER2_WIN,
|
||||
DRAW
|
||||
}
|
||||
|
||||
// 0 0 0
|
||||
// 0 0 0
|
||||
// 0 0 0
|
||||
|
||||
GameBoard() {
|
||||
board = new byte[ROW][COL];
|
||||
step = 0;
|
||||
winner = -1;
|
||||
}
|
||||
|
||||
public byte[][] getBoard() {
|
||||
return board;
|
||||
}
|
||||
|
||||
public GameStatus placePlayer1(int row, int col) throws GameBoardPlacedException {
|
||||
return place(row, col, 1);
|
||||
}
|
||||
|
||||
public GameStatus placePlayer2(int row, int col) throws GameBoardPlacedException{
|
||||
return place(row, col, 2);
|
||||
}
|
||||
|
||||
|
||||
private GameStatus place(int row, int col, int player) throws GameBoardPlacedException {
|
||||
if(board[row][col] != 0)
|
||||
throw new GameBoardPlacedException("The position is placed: " + row + " " + col);
|
||||
board[row][col] = (byte) player;
|
||||
step++; // count step for game
|
||||
return genGameStatus();
|
||||
}
|
||||
|
||||
private GameStatus genGameStatus(){
|
||||
|
||||
// return current game board status
|
||||
// step == board.length mean all is placed
|
||||
if(step == board[0].length * board.length)
|
||||
return new GameStatus(Status.DRAW, this.board);
|
||||
|
||||
// check has winner?
|
||||
if(winner == -1 && !checkWin())
|
||||
return new GameStatus(Status.CONTINUE, this.board);
|
||||
else
|
||||
return new GameStatus((this.winner == 1) ? Status.PLAYER1_WIN: Status.PLAYER2_WIN, this.board);
|
||||
|
||||
}
|
||||
|
||||
private boolean checkWin(){
|
||||
return (checkRows() || checkColumns() || checkDiagonals());
|
||||
}
|
||||
|
||||
|
||||
private boolean checkRows() {
|
||||
for (int i = 0; i < board.length; i++) {
|
||||
int count = 1;
|
||||
for (int j = 1; j < board[i].length; j++) {
|
||||
// compare other col is same?
|
||||
if (board[i][0] != 0 && board[i][0] == board[i][j])
|
||||
count++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (count == board[i].length){
|
||||
this.winner = board[i][0];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkColumns() {
|
||||
for (int i = 0; i < board[0].length; i++) {
|
||||
int count = 1;
|
||||
for (int j = 1; j < board.length; j++) {
|
||||
// compare other col is same?
|
||||
if (board[0][i] != 0 && board[0][i] == board[j][i])
|
||||
count++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (count == board.length) {
|
||||
this.winner = board[0][i];
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// checkDiagonals
|
||||
private boolean checkDiagonals() {
|
||||
int countX = 1; // for count left-top to right-bottom
|
||||
int countY = 1; // for count right-top to left-bottom
|
||||
for (int j = 1; j < board.length; j++) {
|
||||
// compare other col is same?
|
||||
if (board[0][0] != 0 && board[0][0] == board[j][j])
|
||||
countX++;
|
||||
if (board[0][board[0].length - 1] != 0 && board[0][board[0].length - 1] == board[j][board[0].length - 1 - j])
|
||||
countY++;
|
||||
}
|
||||
|
||||
|
||||
if (countX == board.length) {
|
||||
this.winner = board[0][0];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (countY == board.length) {
|
||||
this.winner = board[0][board[0].length-1];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,9 @@
|
||||
package com.game.tictacteo.engine;
|
||||
|
||||
public class GameBoardPlacedException extends Exception{
|
||||
public GameBoardPlacedException(String mes){
|
||||
super(mes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,12 @@
|
||||
package com.game.tictacteo.engine;
|
||||
|
||||
public class GameStatus {
|
||||
|
||||
public GameBoard.Status status;
|
||||
public byte[][] board;
|
||||
|
||||
public GameStatus(GameBoard.Status status, byte[][] board){
|
||||
this.status = status;
|
||||
this.board = board;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user