From 2eb3df823c63bd591d3061ae0f4aad9d7a118030 Mon Sep 17 00:00:00 2001 From: Gustavo Martin Morcuende Date: Thu, 30 Aug 2012 01:05:32 +0200 Subject: [PATCH] Check the permitted movements for the human player. --- AndroidManifest.xml | 7 +- src/de/android/reversi/CheckMovement.java | 170 +++++++++++++++++++++++++ src/de/android/reversi/Movement.java | 19 +++ src/de/android/reversi/Player.java | 36 ++---- src/de/android/reversi/ReversiView.java | 204 ++++++++++++++++++++++-------- src/de/android/reversi/Square.java | 54 ++++++++ 6 files changed, 408 insertions(+), 82 deletions(-) create mode 100644 src/de/android/reversi/CheckMovement.java create mode 100644 src/de/android/reversi/Movement.java create mode 100644 src/de/android/reversi/Square.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index be12a58..cc1f077 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -5,7 +5,9 @@ + android:targetSdkVersion="15" + android:maxSdkVersion="16"/> + + android:label="@string/title_activity_reversi" + android:screenOrientation="portrait"> diff --git a/src/de/android/reversi/CheckMovement.java b/src/de/android/reversi/CheckMovement.java new file mode 100644 index 0000000..c1dc0c0 --- /dev/null +++ b/src/de/android/reversi/CheckMovement.java @@ -0,0 +1,170 @@ +package de.android.reversi; + +public class CheckMovement { + public static boolean horizontal(Square gameBoard[][], short column, short row, Player player) { + return right(gameBoard, column, row, player) || + left(gameBoard, column, row, player); + } + + public static boolean vertical(Square gameBoard[][], short column, short row, Player player) { + return up(gameBoard, column, row, player) || + down(gameBoard, column, row, player); + } + + public static boolean diagonal(Square gameBoard[][], short column, short row, Player player) { + return diagonalLeftUp(gameBoard, column, row, player) || + diagonalRightDown(gameBoard, column, row, player) || + diagonalRightUp(gameBoard, column, row, player) || + diagonalLeftDown(gameBoard, column, row, player); + } + + private static boolean up (Square gameBoard[][], short column, short row, Player player) { + + //Precondition 1. + if (row <= 1) { + return false; + } + + //Precondition 2. + if (gameBoard[column][row-1].getPlayer() == player) { + return false; + } + + return outflank((short)0, (short)-1, gameBoard, player, (short)(row-2), column); + } + + private static boolean down (Square gameBoard[][], short column, short row, Player player) { + + //Precondition 1: + if (row >= ReversiView.NUMBER_OF_ROWS -2) { + return false; + } + + //Precondition 2. + if (gameBoard[column][row+1].getPlayer() == player) { + return false; + } + + return outflank((short)0, (short)1, gameBoard, player, (short)(row+2), column); + } + + private static boolean right (Square gameBoard[][], short column, short row, Player player) { + + //Precondition 1: + if (column >= ReversiView.NUMBER_OF_COLUMNS -2) { + return false; + } + + //Precondition 2. + if (gameBoard[column+1][row].getPlayer() == player) { + return false; + } + + return outflank((short)1, (short)0, gameBoard, player, row, (short)(column+2)); + } + + private static boolean left (Square gameBoard[][], short column, short row, Player player) { + + //Precondition 1: + if (column <= 1) { + return false; + } + + //Precondition 2. + if (gameBoard[column-1][row].getPlayer() == player) { + return false; + } + + return outflank((short)-1, (short)0, gameBoard, player, row, (short)(column-2)); + } + + private static boolean diagonalLeftUp (Square gameBoard[][], short column, short row, + Player player) { + + //Precondition 1: + if (column <= 1 && row <= 1) { + return false; + } + + //Precondition 2. + if (gameBoard[column-1][row-1].getPlayer() == player) { + return false; + } + + return outflank((short)-1, (short)-1, gameBoard, player, (short)(row-2), + (short)(column-2)); + } + + private static boolean diagonalRightDown (Square gameBoard[][], short column, short row, + Player player) { + + //Precondition 1: + if (column >= ReversiView.NUMBER_OF_COLUMNS -2 && row >= ReversiView.NUMBER_OF_ROWS -2) { + return false; + } + + //Precondition 2. + if (gameBoard[column+1][row+1].getPlayer() == player) { + return false; + } + + return outflank((short)1, (short)1, gameBoard, player, (short)(row+2), + (short)(column+2)); + } + + private static boolean diagonalLeftDown (Square gameBoard[][], short column, short row, + Player player) { + + //Precondition 1: + if (column <= 1 && row >= ReversiView.NUMBER_OF_ROWS -2) { + return false; + } + + //Precondition 2. + if (gameBoard[column-1][row+1].getPlayer() == player) { + return false; + } + + return outflank((short)1, (short)1, gameBoard, player, (short)(row+2), + (short)(column-2)); + } + + private static boolean diagonalRightUp (Square gameBoard[][], short column, short row, + Player player) { + + //Precondition 1: + if (row <= 1 && column >= ReversiView.NUMBER_OF_COLUMNS -2) { + return false; + } + + //Precondition 2. + if (gameBoard[column+1][row-1].getPlayer() == player) { + return false; + } + + return outflank((short)1, (short)1, gameBoard, player, (short)(row-2), + (short)(column+2)); + } + + public static boolean empty(Square gameBoard[][], short column, short row) { + if (gameBoard[column][row].getPlayer() == Player.NOPLAYER) { + return true; + } + return false; + } + + private static boolean outflank(short moveX, short moveY, Square gameBoard[][], Player player, + short row, short column) { + + do { + if (gameBoard[column][row].getPlayer() == player) { + return true; + } + row = (short)(row + moveX); + column = (short)(column + moveY); + }while (row > 0 && column >0 && + row <= ReversiView.NUMBER_OF_ROWS && column <= ReversiView.NUMBER_OF_COLUMNS); + + return false; + } +} diff --git a/src/de/android/reversi/Movement.java b/src/de/android/reversi/Movement.java new file mode 100644 index 0000000..62d417f --- /dev/null +++ b/src/de/android/reversi/Movement.java @@ -0,0 +1,19 @@ +package de.android.reversi; + +public class Movement { + private final short row; + private final short column; + + public Movement(short row, short column) { + this.row = row; + this.column = column; + } + + public short getRow() { + return row; + } + + public short getColumn() { + return column; + } +} diff --git a/src/de/android/reversi/Player.java b/src/de/android/reversi/Player.java index 904a380..a000c66 100644 --- a/src/de/android/reversi/Player.java +++ b/src/de/android/reversi/Player.java @@ -1,54 +1,38 @@ package de.android.reversi; -import java.util.HashMap; -import java.util.Map; - import android.graphics.Color; public enum Player { - PLAYER1(1) { + NOPLAYER { + @Override + int color() { + return 0; + } + + }, + PLAYER1 { @Override public int color() { return Color.BLACK; } }, - PLAYER2(2) { + PLAYER2 { @Override int color() { return Color.WHITE; } }; - private final int playerNumber; private final int color; - private static final Map playerMap = new HashMap(); - - static { - for (Player player : Player.values()) - { - playerMap.put(player.playerNumber, player); - } - } - - private Player (final int playerNumber) { - this.playerNumber = playerNumber; + private Player () { this.color = color(); } - public int getPlayerNumber() { - return this.playerNumber; - } - public int getColor() { return this.color; } - public static final Player getPlayer (final int playerNumber) - { - return playerMap.get(playerNumber); - } - abstract int color(); } diff --git a/src/de/android/reversi/ReversiView.java b/src/de/android/reversi/ReversiView.java index 3bea3dc..e08247b 100644 --- a/src/de/android/reversi/ReversiView.java +++ b/src/de/android/reversi/ReversiView.java @@ -1,5 +1,8 @@ package de.android.reversi; +import java.util.ArrayList; +import java.util.List; + import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; @@ -11,47 +14,38 @@ import android.view.SurfaceView; public class ReversiView extends SurfaceView { - private static final String TAG = "GameBoard"; + public static final short NUMBER_OF_COLUMNS = 8; + public static final short NUMBER_OF_ROWS = 8; - /** - * The number of columns of this board - */ - private static int NUMBER_OF_COLUMNS = 8; - - /** - * The number of rows of this board - */ - private static int NUMBER_OF_ROWS = 8; - - /** - * The top margin - */ - private static int TOP_MARGIN = 0; - - /** - * Vertical margin - */ - private static int LEFT_MARGIN = 0; + private static final short TOP_MARGIN = 0; + private static final short LEFT_MARGIN = 0; private int squareWidth; private int squareHeight; private int canvasHeight; private int canvasWidth; - private final int gameBoard[][] = new int[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]; + + private final Square gameBoard[][] = new Square[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]; + //¿Funciona bien volatile con enum? Ver mi codigo de Singletons y enums. + private volatile Player currentPlayer = Player.PLAYER1; + private volatile boolean isEnableUserTouch; public ReversiView(Context context) { super(context); + this.preInitBoard(); this.initialize(); } public ReversiView(Context context, AttributeSet attrs) { super(context, attrs); + this.preInitBoard(); this.initialize(); } public ReversiView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + this.preInitBoard(); this.initialize(); } @@ -123,12 +117,19 @@ public class ReversiView extends SurfaceView { @Override public void surfaceCreated(SurfaceHolder holder) { //White - updateGrid(Player.PLAYER1.getPlayerNumber(), 3, 3); - updateGrid(Player.PLAYER1.getPlayerNumber(), 4, 4); + updateBoard(Player.PLAYER1, (short)3, (short)3); + updateBoard(Player.PLAYER1, (short)4, (short)4); //Black - updateGrid(Player.PLAYER2.getPlayerNumber(), 4, 3); - updateGrid(Player.PLAYER2.getPlayerNumber(), 3, 4); + updateBoard(Player.PLAYER2, (short)4, (short)3); + updateBoard(Player.PLAYER2, (short)3, (short)4); + //AllowedMovements for Player + List list = allowedMovements(currentPlayer); + + //UpdateBoard with suggestions + for (Movement movement : list) { + updateBoard(currentPlayer, movement.getColumn(), movement.getRow(), true); + } } @Override @@ -136,6 +137,7 @@ public class ReversiView extends SurfaceView { int width, int height) { Canvas canvas = holder.lockCanvas(); calculateGraphicParameters(canvas, width, height); + updateSquareParameters(); drawGrid(canvas); drawPositions(canvas); holder.unlockCanvasAndPost(canvas); @@ -150,12 +152,16 @@ public class ReversiView extends SurfaceView { @Override public boolean onTouchEvent(MotionEvent event) { + if (!this.isEnableUserTouch) { + return false; + } + if (event.getAction() == MotionEvent.ACTION_DOWN) { // Hidden pointer - int column = transformCoordinateXInColumn(event.getX()); - int row = transformCoordinateYInRow(event.getY()); + short column = transformCoordinateXInColumn(event.getX()); + short row = transformCoordinateYInRow(event.getY()); if (row != -1 && column != -1 ) { - updateGrid(Player.PLAYER2.getPlayerNumber(), column, row); + updateBoard(this.currentPlayer, column, row); Canvas canvas = getHolder().lockCanvas(); drawGrid(canvas); drawPositions(canvas); @@ -168,9 +174,9 @@ public class ReversiView extends SurfaceView { } } - private int transformCoordinateYInRow(float y) { + private short transformCoordinateYInRow(float y) { - int row = (int) ((y - TOP_MARGIN) / this.squareWidth); + short row = (short) ((y - TOP_MARGIN) / this.squareWidth); // if tapped outside the board if (row < 0 || row >= NUMBER_OF_ROWS) { @@ -180,9 +186,9 @@ public class ReversiView extends SurfaceView { return row; } - private int transformCoordinateXInColumn(float x) { + private short transformCoordinateXInColumn(float x) { - int column = (int) ((x - LEFT_MARGIN) / this.squareWidth); + short column = (short) ((x - LEFT_MARGIN) / this.squareWidth); // if tapped outside the board if (column < 0 || column >= NUMBER_OF_COLUMNS) { @@ -192,41 +198,131 @@ public class ReversiView extends SurfaceView { return column; } - private void drawChip(Canvas canvas, int player, int column, int row) { - if (player != 0) { - // calculating the center of the cell - int cellMediumX = (column * this.squareWidth + (column + 1) * this.squareWidth) / 2; - int cellMediumY = (row * this.squareHeight + (row + 1) * this.squareHeight) / 2; + private void drawDisk(Canvas canvas, Square square, short column, short row) { + this.drawCircle(canvas, square.getPlayer(), square.getSquareMediumX(), + square.getSquareMediumY(), square.getRadius(), square.isSuggestion()); + } + + private void drawCircle(Canvas canvas, Player player, int cx, int cy, int radius, + boolean isSolid) { - // applying the margins - int cx = cellMediumX + LEFT_MARGIN; - int cy = cellMediumY + TOP_MARGIN; - // now the radius - int radius = (this.squareWidth - 2) / 2 - 2; + Paint paint = new Paint(); + + paint.setAntiAlias(true); + + //If not solid it is a suggestion. + if (!isSolid) { + paint.setAlpha(77); + } - this.drawCircle(canvas, player, cx, cy, radius); + switch (player){ + case PLAYER1: + paint.setColor(player.getColor()); + //paint.setAntiAlias(true); + canvas.drawCircle(cx, cy, radius, paint); + break; + case PLAYER2: + //border color + paint.setColor(Color.BLACK); + canvas.drawCircle(cx, cy, radius, paint); + //inside color + paint.setColor(player.getColor()); + canvas.drawCircle(cx, cy, radius-2, paint); + break; + default: + break; } } - private void drawCircle(Canvas canvas, int player, int cx, int cy, int radius) { + private void updateBoard(Player player, short column, short row) { + this.updateBoard(player, column, row, false); + } - Paint paint = new Paint(); + private void updateBoard(Player player, short column, short row, boolean suggestion) { + this.gameBoard[column][row].setPlayer(player); + this.gameBoard[column][row].setSuggestion(suggestion); + } - paint.setColor(Player.getPlayer(player).getColor()); - //paint.setAntiAlias(true); + private void drawPositions(Canvas canvas) { + for (short column = 0; column < NUMBER_OF_COLUMNS; column++) { + for (short row = 0; row < NUMBER_OF_ROWS; row++) { + if (this.gameBoard[column][row].getPlayer() != Player.NOPLAYER) { + drawDisk(canvas, this.gameBoard[column][row], column, row); + } + } + } + } - canvas.drawCircle(cx, cy, radius, paint); + private void preInitBoard() { + for (short column = 0; column < NUMBER_OF_COLUMNS; column++) { + for (short row = 0; row < NUMBER_OF_ROWS; row++) { + this.gameBoard[column][row] = new Square();; + } + } } - private void updateGrid(int player, int column, int row) { - this.gameBoard[column][row] = player; + private void updateSquareParameters() { + for (short column = 0; column < NUMBER_OF_COLUMNS; column++) { + for (short row = 0; row < NUMBER_OF_ROWS; row++) { + + // calculating the square's center + int cellMediumX = (column * this.squareWidth + (column + 1) * this.squareWidth) / 2; + int cellMediumY = (row * this.squareHeight + (row + 1) * this.squareHeight) / 2; + + // applying the margins + int cx = cellMediumX + LEFT_MARGIN; + int cy = cellMediumY + TOP_MARGIN; + + // the radius + int radius = (this.squareWidth - 2) / 2 - 2; + + //update squares + this.gameBoard[column][row].setRadius(radius); + this.gameBoard[column][row].setSquareMediumX(cx); + this.gameBoard[column][row].setSquareMediumY(cy); + } + } } - private void drawPositions(Canvas canvas) { - for (int column = 0; column < NUMBER_OF_COLUMNS; column++) { - for (int row = 0; row < NUMBER_OF_ROWS; row++) { - drawChip(canvas, this.gameBoard[column][row], column, row); + private void first() { + if (this.currentPlayer == Player.PLAYER1) { + //AllowedMovements for Player + List list = allowedMovements(this.currentPlayer); + + //UpdateBoard with suggestions + for (Movement movement : list) { + updateBoard(this.currentPlayer, movement.getColumn(), movement.getRow(), true); + } + + + //Draw board + Canvas canvas = getHolder().lockCanvas(); + drawGrid(canvas); + drawPositions(canvas); + getHolder().unlockCanvasAndPost(canvas); + + this.isEnableUserTouch = true; + } + else { + //The IA is always PLAYER2 ? + //Launch IA Thread. + } + } + + private List allowedMovements(Player player) { + List list = new ArrayList(); + + for (short column = 0; column < NUMBER_OF_COLUMNS; column++) { + for (short row = 0; row < NUMBER_OF_ROWS; row++) { + if (CheckMovement.empty(gameBoard, column, row) && + (CheckMovement.diagonal(gameBoard, column, row, player) || + CheckMovement.horizontal(gameBoard, column, row, player) || + CheckMovement.vertical(gameBoard, column, row, player))) { + list.add(new Movement(row, column)); + } } } + + return list; } } diff --git a/src/de/android/reversi/Square.java b/src/de/android/reversi/Square.java new file mode 100644 index 0000000..f981bce --- /dev/null +++ b/src/de/android/reversi/Square.java @@ -0,0 +1,54 @@ +package de.android.reversi; + +public class Square { + private Player player; + private boolean suggestion; + private int squareMediumX; + private int squareMediumY; + private int radius; + + //Default constructor. + public Square () { + this.player = Player.NOPLAYER; + } + + public boolean isSuggestion() { + return suggestion; + } + + public void setSuggestion(boolean suggestion) { + this.suggestion = suggestion; + } + + public int getSquareMediumX() { + return squareMediumX; + } + + public void setSquareMediumX(int squareMediumX) { + this.squareMediumX = squareMediumX; + } + + public int getSquareMediumY() { + return squareMediumY; + } + + public void setSquareMediumY(int squareMediumY) { + this.squareMediumY = squareMediumY; + } + + public void setPlayer (Player player) { + this.player = player; + } + + public Player getPlayer() { + return player; + } + + public void setRadius (int radius) { + this.radius = radius; + } + + public int getRadius() { + return radius; + } +} -- 2.1.4