First pass on converting existing Java game code into Python.

This commit is contained in:
Dorian 2014-08-13 00:20:22 -04:00
parent 8ec38e5020
commit cf103bcbb8
10 changed files with 638 additions and 1078 deletions

View File

@ -1,249 +0,0 @@
/*****************************************************************************
Board.java -- Container for the state of a game in progress.
*****************************************************************************
*****************************************************************************
This file is part of justCheckers.
justCheckers is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
justCheckers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with justCheckers. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
package org.justcheckers.game;
/**
* The main game handling object of GameLoop.
*
* Objects registering as observers on an instance of GameEngine will be
* notified of a change in either the board state or the turn state. The turn
* will change automatically when a complete move is made. Multiple jumps are
* managed by a call to the makeMove method for each jump segment, and the turn
* will not pass to the other player until the jump sequence is complete.
*
* @author Ross Etchells
* @author Dorian Pula
*/
public class Game {
// -- Constants -----------------------------------------------------------
/** State of the game when the dark player wins. */
public static final int STATE_DARK_VICTORY = 2;
/** State of the game when both players draw. */
public static final int STATE_GAME_DRAWN = 3;
/** State of the game when game is in progress. */
public static final int STATE_GAME_IN_PROGRESS = 0;
/** State of the game when the light player wins. */
public static final int STATE_LIGHT_VICTORY = 1;
// -- Object Fields -------------------------------------------------------
/** Represents the dark (usually defending) player. */
private Player darkPlayer;
/** Contains the current checker board used for the game. */
private Board gameBoard;
/** Contains the current rules used for playing the game. */
private Rulebook gameRules;
/** The state of the game. */
private int gameState;
/**
* This point holds the coordinates of a piece making a jump. Mostly used
* for a piece whose move has not finished after 1 jump. This point is set
* to null if not in use.
*/
private final IPoint jumpInProgress;
/** Represents the light (usually attacking) player. */
private Player lightPlayer;
/** Represents whose turn it is. */
private boolean lightPlayerTurn;
/*
* TODO: Game needs to declare who won or better yet, the state of the game
* to be: in progress, light win, dark win or draw.
*/
// -- Constructors --------------------------------------------------------
/**
* Create a new game. Uses the defaults of two unnamed players and the
* American rules.
*/
public Game() {
this(Rulebook.AMERICAN_CHECKERS, new Player(), new Player());
}
/**
* Create a new game. Uses the default of two unnamed players. The variant
* (which rules) can be set here.
*
* @param variant
* Which variant of checkers will this game be.
*/
public Game(int variant) {
this(variant, new Player(), new Player());
}
/**
* Creates a new game.
*
* @param variant
* The variant of checkers to be played.
* @param light
* The player playing the light side.
* @param dark
* The player playing the dark side.
*/
public Game(int variant, Player light, Player dark) {
// Setup all the components of the game.
this.gameRules = new Rulebook(variant);
this.gameBoard = new Board(this.gameRules);
this.darkPlayer = dark;
this.lightPlayer = light;
// Setup the board and start the game.
this.lightPlayerTurn = this.gameRules.isLightPlayerFirst();
this.gameBoard.setupNewGame();
this.jumpInProgress = null; // No moves in progress yet.
this.gameState = Game.STATE_GAME_IN_PROGRESS;
}
// TODO: Add a constructor for games already in progress.
// -- Game methods --------------------------------------------------------
/**
* Gets the player playing the dark side.
*
* @return The player playing the dark side.
*/
public Player getDarkPlayer() {
return this.darkPlayer;
}
// -- Get/Set Methods ------------------------------------------------------
/**
* Gets the board used for this game.
*
* @return The board used for this game.
*/
public Board getGameBoard() {
return this.gameBoard;
}
/**
* Gets the rules used for this game.
*
* @return The rules used for this game.
*/
public Rulebook getGameRules() {
return this.gameRules;
}
/**
* Gets the state of the game. The state is defined by the STATE_*
* constants.
*
* @return The state of the game.
*/
public int getGameState() {
return this.gameState;
}
/**
* Gets the player playing the light side.
*
* @return The player playing the light side.
*/
public Player getLightPlayer() {
return this.lightPlayer;
}
/**
* Gets if it is the light player's turn. Returns false if it is the dark
* player's turn.
*
* @return If it is the light player's turn. Returns false if it is the dark
* player's turn.
*/
public boolean isLightPlayerTurn() {
return this.lightPlayerTurn;
}
/**
* Set the player playing the dark side.
*
* @param player
* The player playing the dark side.
*/
public void setDarkPlayer(Player player) {
this.darkPlayer = player;
}
/**
* Sets the board used for this game.
*
* @param board
* The board for this game.
*/
public void setGameBoard(Board board) {
this.gameBoard = board;
}
// -- Private Methods ------------------------------------------------------
/**
* Sets the rules used for this game.
*
* @param rules
* The rules used for this game.
*/
public void setGameRules(Rulebook rules) {
this.gameRules = rules;
}
/**
* Sets the state of the game. The state is defined by the STATE_*
* constants.
*
* @param state
* The state of the game.
*/
public void setGameState(int state) {
this.gameState = state;
}
/**
* Sets the player playing the light side.
*
* @param player
* The player playing the light side.
*/
public void setLightPlayer(Player player) {
this.lightPlayer = player;
}
/**
* Sets if it is the light player's turn. Set it to false if its the dark
* player's turn.
*
* @param playerTurn
* If it is the light player's turn.
*/
public void setLightPlayerTurn(boolean playerTurn) {
this.lightPlayerTurn = playerTurn;
}
/**
* @return the jumpInProgress
*/
public IPoint getJumpInProgress() {
return jumpInProgress;
}
}

View File

@ -1,14 +0,0 @@
package org.justcheckers.game;
/**
* @author dorian
* Created 2013-04-03 @ 4:59 PM by IntelliJ IDEA.
*/
public interface IPoint {
public void setX(double x);
public void setY(double y);
public double getX();
public double getY();
}

View File

@ -1,145 +0,0 @@
/*****************************************************************************
Player.java -- Data objects for maintaining player information.
*****************************************************************************
*****************************************************************************
This file is part of justCheckers.
justCheckers is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
justCheckers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with justCheckers. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
package org.justcheckers.game;
/**
* Manages the information of a single player.
*
* @author Chris Bellini
* @author Dorian Pula
*/
public class Player {
/** The player's total number of losses. */
private int gamesLost;
/** The total number of games played by the player. */
private int gamesPlayed;
/** The player's total number of ties. */
private int gamesTied;
/** The player's total number of wins. */
private int gamesWon;
/** The player's name. */
private final String playerName;
/** Creates an unnamed player with a blank record. */
public Player() {
this("Unnamed Player", 0, 0, 0, 0);
}
/**
* Creates a player with a given name and a blank record.
*
* @param name
* The name of the player.
*/
public Player(String name) {
this(name, 0, 0, 0, 0);
}
/**
* Creates a player with a given name and record.
*
* @param name
* The name of the player to be created.
* @param wins
* Player's total wins.
* @param losses
* Player's total losses.
* @param ties
* Player's total ties.
* @param played
* Total games played by the player.
*/
public Player(String name, int wins, int losses, int ties, int played) {
this.playerName = name;
this.gamesWon = wins;
this.gamesLost = losses;
this.gamesTied = ties;
this.gamesPlayed = played;
}
/** Adds a new loss for the player's total losses. */
public void addLoss() {
this.gamesLost++;
this.gamesPlayed++;
}
/** Adds a new tie for the player's total ties. */
public void addTie() {
this.gamesTied++;
this.gamesPlayed++;
}
/** Adds a new win for the player's total wins. */
public void addWin() {
this.gamesWon++;
this.gamesPlayed++;
}
/**
* Gets the player's total losses.
*
* @return The player's total losses.
*/
public int getLosses() {
return this.gamesLost;
}
/**
* Gets the total number of games played by the player.
*
* @return The total number of games played by the player.
*/
public int getPlayedGames() {
return this.gamesPlayed;
}
/**
* Gets the player's total score.
*
* @return The player's total score.
*/
public int getTies() {
return this.gamesTied;
}
/**
* Gets the player's total wins.
*
* @return The player's total wins.
*/
public int getWins() {
return this.gamesWon;
}
/**
* Prints all the data about the player.
*
* @return A string representing the player's data.
*/
@Override
public String toString() {
return "Name: " + this.playerName + "\n" + "Games: Won "
+ this.gamesWon + " Lost " + this.gamesLost + " Tied "
+ this.gamesTied;
}
}

View File

@ -1,352 +0,0 @@
/*****************************************************************************
Rulebook.java -- A generic 'rulebook' for a checkers game.
*****************************************************************************
*****************************************************************************
This file is part of justCheckers.
justCheckers is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
justCheckers is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with justCheckers. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
package org.justcheckers.game;
/**
* The rules for a game of checkers. This class provides a reference object for
* a game of checkers. This helps deal with the number of variants of checkers.
* One of the goals of justCheckers is to provide the flexibility of choose
* between different kinds of checker variants. This class builds a skeleton of
* the rules by defining what setup, moves, jumps, victory conditions and
* special moves make up a particular variant of checkers.
*
* @author Dorian Pula
* @author Chris Bellini
*/
public class Rulebook {
// -- Constants -----------------------------------------------------------
// Checkers variants.
/** Playing by the American rules. */
public static final int AMERICAN_CHECKERS = 0;
/** Playing by International (Polish) rules. */
public static final int INTERNATIONAL_CHECKERS = 1;
/** Playing by the Brazilian rules. */
public static final int BRAZILIAN_CHECKERS = 2;
/** Playing by the Canadian rules. */
public static final int CANADIAN_CHECKERS = 3;
/** Playing by Pool (Southern USA) rules. */
public static final int POOL_CHECKERS = 4;
/** Playing by the Spanish rules. */
public static final int SPANISH_CHECKERS = 5;
/** Playing by the Russian rules. */
public static final int RUSSIAN_CHECKERS = 6;
/** Playing by the Italian rules. */
public static final int ITALIAN_CHECKERS = 7;
/** Playing by Suicide rules. */
public static final int SUICIDE_CHECKERS = 8;
/** Playing by the Ghanaian rules. */
public static final int GHANAIAN_CHECKERS = 9;
// TODO: Implement special rules for these checkers. Version >0.1.1?
// Victory conditions.
/** Victory achieved by capturing all enemy pieces. */
public static final int CAPTURE_ALL_ENEMIES_VICTORY = 0;
/**
* Victory achieved by capturing all pieces. Only caveat is the three king
* versus one king draw rule:
*
* In many games at the end one adversary has three kings while the other
* one has just one king. In such a case the first adversary must win in
* thirteen moves or the game is declared a draw. (Shamelessly stolen from
* http://en.wikipedia.org/wiki/Draughts).
*/
public static final int SPECIAL_POOL_VICTORY = 1;
/** Victory achieved some bizarre manner. TODO: Figure out Russian checkers. */
public static final int SPECIAL_RUSSIAN_VICTORY = 2;
/** Victory achieved by losing all your pieces. */
public static final int SPECIAL_SUICIDE_VICTORY = 3;
/** Victory achieved by not being the first with one piece left. */
public static final int SPECIAL_GHANAIAN_VICTORY = 4;
// Checker board sizes.
/** Using a "standard" American checkers board. */
public static final int STANDARD_BOARD_SIZE = 8;
/** Using an international sized checkers board. */
public static final int INTERNATIONAL_BOARD_SIZE = 10;
/** Using a Canadian sized checkers board. */
public static final int CANADIAN_BOARD_SIZE = 12;
/** The number of variants currently supported. */
private static final int NUMBER_OF_VARIANTS_SUPPORTED = 2;
/** The size of the board. */
private int boardSize;
/** Can kings fly across the board? */
private boolean canKingsFly;
/** Can pawns capture backwards? */
private boolean canPawnsJumpBackwards;
// -- Object Fields --------------------------------------------------------
/** Stores what kind of checkers variant of rule are we playing? */
private int checkersVariant;
/** Does the light player start first? */
private boolean lightPlayerFirst;
/** Is the board mirrored? As in white square lower right corner. */
private boolean mirroredBoard;
/** Must capture if have opportunity. */
private boolean mustCapture;
/** Must player capture the highest number of pieces. */
private boolean mustCaptureMaxium;
/** The type of victory conditions. */
private int victoryConditions;
// -- Constructors ---------------------------------------------------------
/**
* Creates a rulebook for a checkers game. We use the American variant rules
* by default.
*/
public Rulebook() {
this(Rulebook.AMERICAN_CHECKERS);
}
/**
* Creates a rulebook for a checkers game. If a bad/unsupported variant is
* created, the default of American checkers is chosen.
*
* @param variant
* The variant of checkers we will play.
*/
public Rulebook(int variant) {
if (variant >= 0 && variant < Rulebook.NUMBER_OF_VARIANTS_SUPPORTED) {
this.checkersVariant = variant;
} else {
this.checkersVariant = Rulebook.AMERICAN_CHECKERS;
}
this.setUpRules();
}
/**
* Returns if kings can fly. That is can kings move as far they wish.
*
* @return If kings can fly.
*/
public boolean canKingsFly() {
return this.canKingsFly;
}
/**
* Returns if pawns can capture backwards.
*
* @return If pawns can capture backwards.
*/
public boolean canPawnsJumpBackwards() {
return this.canPawnsJumpBackwards;
}
/**
* Returns the size of the board.
*
* @return The size of the board.
*/
public int getBoardSize() {
return this.boardSize;
}
// -- Get/set methods ------------------------------------------------------
/**
* Returns the checkers variant being played.
*
* @return The checkers variant being played.
*/
public int getCheckersVariant() {
return this.checkersVariant;
}
/**
* Returns the victory conditions of this game.
*
* @return The victory conditions of this game.
*/
public int getVictoryConditions() {
return this.victoryConditions;
}
/**
* Returns is the board mirrored in this game.
*
* @return Is the board mirrored in this game.
*/
public boolean isBoardMirrored() {
return this.mirroredBoard;
}
/**
* Returns if the light player starts the game.
*
* @return If the light player starts the game.
*/
public boolean isLightPlayerFirst() {
return this.lightPlayerFirst;
}
/**
* Returns if you must capture a piece if you can.
*
* @return If you must capture a piece if you can.
*/
public boolean mustCapture() {
return this.mustCapture;
}
/**
* Returns if you must capture the maximum number of pieces possible.
*
* @return If you must capture the maximum number of pieces possible.
*/
public boolean mustCaptureMaxium() {
return this.mustCaptureMaxium;
}
// -- Private implementation methods.
/**
* Setups the rules according to what variant of checkers was chosen.
*/
private void setUpRules() {
// Save my sanity.
assert this.checkersVariant >= 0;
assert this.checkersVariant < Rulebook.NUMBER_OF_VARIANTS_SUPPORTED;
// Set up the rules by the type of variant.
switch (this.checkersVariant) {
case Rulebook.AMERICAN_CHECKERS:
this.boardSize = Rulebook.STANDARD_BOARD_SIZE;
this.canKingsFly = false;
this.canPawnsJumpBackwards = false;
this.lightPlayerFirst = false;
this.mirroredBoard = false;
this.mustCapture = true;
this.mustCaptureMaxium = false;
this.victoryConditions = Rulebook.CAPTURE_ALL_ENEMIES_VICTORY;
break;
case Rulebook.INTERNATIONAL_CHECKERS:
this.boardSize = Rulebook.INTERNATIONAL_BOARD_SIZE;
this.canKingsFly = true;
this.canPawnsJumpBackwards = true;
this.lightPlayerFirst = true;
this.mirroredBoard = false;
this.mustCapture = true;
this.mustCaptureMaxium = true;
this.victoryConditions = Rulebook.CAPTURE_ALL_ENEMIES_VICTORY;
break;
case Rulebook.BRAZILIAN_CHECKERS:
this.boardSize = Rulebook.STANDARD_BOARD_SIZE;
this.canKingsFly = true;
this.canPawnsJumpBackwards = true;
this.lightPlayerFirst = true;
this.mirroredBoard = false;
this.mustCapture = true;
this.mustCaptureMaxium = true;
this.victoryConditions = Rulebook.CAPTURE_ALL_ENEMIES_VICTORY;
break;
case Rulebook.CANADIAN_CHECKERS:
this.boardSize = Rulebook.CANADIAN_BOARD_SIZE;
this.canKingsFly = true;
this.canPawnsJumpBackwards = true;
this.lightPlayerFirst = true;
this.mirroredBoard = false;
this.mustCapture = true;
this.mustCaptureMaxium = false;
this.victoryConditions = Rulebook.CAPTURE_ALL_ENEMIES_VICTORY;
break;
case Rulebook.POOL_CHECKERS:
this.boardSize = Rulebook.STANDARD_BOARD_SIZE;
this.canKingsFly = true;
this.canPawnsJumpBackwards = true;
this.lightPlayerFirst = false;
this.mirroredBoard = false;
this.mustCapture = true;
this.mustCaptureMaxium = false;
this.victoryConditions = Rulebook.SPECIAL_POOL_VICTORY;
break;
case Rulebook.SPANISH_CHECKERS:
this.boardSize = Rulebook.STANDARD_BOARD_SIZE;
this.canKingsFly = true;
this.canPawnsJumpBackwards = false;
this.lightPlayerFirst = true;
this.mirroredBoard = true;
this.mustCapture = true;
this.mustCaptureMaxium = true;
this.victoryConditions = Rulebook.CAPTURE_ALL_ENEMIES_VICTORY;
break;
case Rulebook.RUSSIAN_CHECKERS:
// TODO: Needs special freshly-kinged-but-still-can-jump special
// rule.
this.boardSize = Rulebook.STANDARD_BOARD_SIZE;
this.canKingsFly = true;
this.canPawnsJumpBackwards = true;
this.lightPlayerFirst = true;
this.mirroredBoard = false;
this.mustCapture = true;
this.mustCaptureMaxium = false;
this.victoryConditions = Rulebook.SPECIAL_RUSSIAN_VICTORY;
break;
case Rulebook.ITALIAN_CHECKERS:
// TODO: Special rule on must jump most number of kings per capture.
this.boardSize = Rulebook.STANDARD_BOARD_SIZE;
this.canKingsFly = true;
// TODO: Special rule that pawns can't capture kings.
this.canPawnsJumpBackwards = false;
this.lightPlayerFirst = true;
this.mirroredBoard = true;
this.mustCapture = true;
this.mustCaptureMaxium = true;
this.victoryConditions = Rulebook.CAPTURE_ALL_ENEMIES_VICTORY;
break;
case Rulebook.SUICIDE_CHECKERS:
// TODO: Needs unconventional setup.
this.boardSize = Rulebook.STANDARD_BOARD_SIZE;
this.canKingsFly = true;
this.canPawnsJumpBackwards = true;
this.lightPlayerFirst = true;
this.mirroredBoard = false;
this.mustCapture = true;
this.mustCaptureMaxium = true;
this.victoryConditions = Rulebook.SPECIAL_SUICIDE_VICTORY;
break;
case Rulebook.GHANAIAN_CHECKERS:
// TODO: Special forfeit king if passing up a king's capture
// opportunity.
this.boardSize = Rulebook.INTERNATIONAL_BOARD_SIZE;
this.canKingsFly = true;
this.canPawnsJumpBackwards = true;
this.lightPlayerFirst = true;
this.mirroredBoard = true;
this.mustCapture = true;
this.mustCaptureMaxium = false;
this.victoryConditions = Rulebook.SPECIAL_GHANAIAN_VICTORY;
break;
}
}
}

View File

@ -1,25 +1,21 @@
/***************************************************************************** #
Board.java -- Container for the state of the board of a game. # Copyright (c) 2014 Dorian Pula <dorian.pula@amber-penguin-software.ca>
***************************************************************************** #
# justCheckers is free software: you can redistribute it and/or modify it
***************************************************************************** # under the terms of the GNU General Public License as published by the
This file is part of justCheckers. # Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
justCheckers is free software: you can redistribute it and/or modify #
it under the terms of the GNU General Public License as published by # justCheckers is distributed in the hope that it will be useful, but
the Free Software Foundation, either version 3 of the License, or # WITHOUT ANY WARRANTY; without even the implied warranty of
(at your option) any later version. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
justCheckers is distributed in the hope that it will be useful, #
but WITHOUT ANY WARRANTY; without even the implied warranty of # You should have received a copy of the GNU General Public License along
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # with justCheckers. If not, see <http://www.gnu.org/licenses/>.
GNU General Public License for more details. #
# Please share and enjoy!
You should have received a copy of the GNU General Public License #
along with justCheckers. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
package org.justcheckers.game;
/** /**
* Container for the state of the checker board during a game. * Container for the state of the checker board during a game.

76
justcheckers/game/game.py Normal file
View File

@ -0,0 +1,76 @@
#
# Copyright (c) 2014 Dorian Pula <dorian.pula@amber-penguin-software.ca>
#
# justCheckers is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
#
# justCheckers is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with justCheckers. If not, see <http://www.gnu.org/licenses/>.
#
# Please share and enjoy!
#
from collections import namedtuple
from enum import Enum
from justcheckers.game import rules
Point = namedtuple('Point', ['x', 'y'])
class GameState(Enum):
NOT_STARTED = 0
LIGHT_MOVE = 1
DARK_MOVE = 2
LIGHT_VICTORY = 3
DARK_VICTORY = 4
DRAW = 5
class Game(object):
"""
Handles the logic behind the main game loop.
:author: Ross Etchells
:author: Dorian Pula
"""
def __init__(self, light_player,
dark_player,
game_board=None,
game_rules=rules.CheckersVariant.American,
game_state=GameState.NOT_STARTED):
"""
Initializes a new checker game
:param light_player: The attack player.
:param dark_player: The defending player.
:param game_board: The checkerboard to use for the game.
:param game_rules: The set of rules to use.
:param game_state: The state of the game.
:return: A representation of the game board.
"""
self.light_player = light_player
self.dark_player = dark_player
self.board = game_board
# TODO Initialize the rulebooks
self.rules = game_rules
self.state = game_state
def is_light_player_turn(self):
"""
Gets if it is the light player's turn. Returns false if it is the dark player's turn.
:returns: True if it is the light player's turn. Returns false if it is the dark player's turn.
"""
return self.state in [GameState.LIGHT_MOVE, GameState.LIGHT_VICTORY]

View File

@ -1,295 +1,287 @@
/***************************************************************************** #
GameEngine.java -- Logic engine for manipulating the state of a game. # Copyright (c) 2014 Dorian Pula <dorian.pula@amber-penguin-software.ca>
***************************************************************************** #
# justCheckers is free software: you can redistribute it and/or modify it
***************************************************************************** # under the terms of the GNU General Public License as published by the
This file is part of justCheckers. # Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
justCheckers is free software: you can redistribute it and/or modify #
it under the terms of the GNU General Public License as published by # justCheckers is distributed in the hope that it will be useful, but
the Free Software Foundation, either version 3 of the License, or # WITHOUT ANY WARRANTY; without even the implied warranty of
(at your option) any later version. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
justCheckers is distributed in the hope that it will be useful, #
but WITHOUT ANY WARRANTY; without even the implied warranty of # You should have received a copy of the GNU General Public License along
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # with justCheckers. If not, see <http://www.gnu.org/licenses/>.
GNU General Public License for more details. #
# Please share and enjoy!
You should have received a copy of the GNU General Public License #
along with justCheckers. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/ class GameEngine(object):
package org.justcheckers.game; // TODO: Add a constructor for games already in progress.
/** // -- Game methods --------------------------------------------------------
* @author dpula
* private static boolean canJump(Game game, int sourceRow, int sourceCol, int targetRow,
*/ int targetCol) {
public class GameEngine {
// TODO: Implement me.
// TODO: Add a constructor for games already in progress. return false;
}
// -- Game methods --------------------------------------------------------
/**
private static boolean canJump(Game game, int sourceRow, int sourceCol, int targetRow, * Returns if a piece can or cannot move. This move maybe either be a move
int targetCol) { * or a jump. This method is called by a user interface when a user wants to
* moves a piece on screen or over the network. The piece can moved if the
// TODO: Implement me. * current state of the game allows for it to do so.
return false; *
} * TODO: Add priority for king jumps over pawn jumps for any variants that
* do so.
/** *
* Returns if a piece can or cannot move. This move maybe either be a move * @param sourceRow
* or a jump. This method is called by a user interface when a user wants to * The row from where the piece is moving from.
* moves a piece on screen or over the network. The piece can moved if the * @param sourceCol
* current state of the game allows for it to do so. * The column from where the piece is moving from.
* * @param targetRow
* TODO: Add priority for king jumps over pawn jumps for any variants that * The row to where the piece is moving to.
* do so. * @param targetCol
* * The column to where the piece is moving to.
* @param sourceRow * @return True if the piece can move. False if the piece can not move.
* The row from where the piece is moving from. */
* @param sourceCol public static boolean canMove(Game game, int sourceRow, int sourceCol, int targetRow,
* The column from where the piece is moving from. int targetCol) {
* @param targetRow
* The row to where the piece is moving to. // A few things to figure out priorities in moving a piece.
* @param targetCol boolean legalMove = false; // Is the proposed move/jump legal?
* The column to where the piece is moving to. boolean realPositions = false; // Are the positions really on the board?
* @return True if the piece can move. False if the piece can not move. boolean isJump = false; // Is this a jump?
*/
public static boolean canMove(Game game, int sourceRow, int sourceCol, int targetRow, // Sanity check.
int targetCol) { if (game.getGameBoard().isLegalPosition(sourceRow, sourceCol)
&& game.getGameBoard().isLegalPosition(targetRow, targetCol)) {
// A few things to figure out priorities in moving a piece. realPositions = true;
boolean legalMove = false; // Is the proposed move/jump legal?
boolean realPositions = false; // Are the positions really on the board? }
boolean isJump = false; // Is this a jump?
// Is there a jump in progress?
// Sanity check. if (realPositions && game.getJumpInProgress() != null) {
if (game.getGameBoard().isLegalPosition(sourceRow, sourceCol)
&& game.getGameBoard().isLegalPosition(targetRow, targetCol)) { // Only allow the piece in movement to be moved.
realPositions = true; if (sourceRow == game.getJumpInProgress().getY()
&& sourceCol == game.getJumpInProgress().getX()) {
} legalMove = canJump(game, sourceRow, sourceCol, targetRow,
targetCol);
// Is there a jump in progress? isJump = true;
if (realPositions && game.getJumpInProgress() != null) { }
// Only allow the piece in movement to be moved. } else if (realPositions) {
if (sourceRow == game.getJumpInProgress().getY()
&& sourceCol == game.getJumpInProgress().getX()) { // Go with the regular flow, jumps first then "slides".
legalMove = canJump(game, sourceRow, sourceCol, targetRow, isJump = canPlayerJump(game);
targetCol); if (isJump) {
isJump = true; legalMove = canJump(game, sourceRow, sourceCol, targetRow,
} targetCol);
} else {
} else if (realPositions) { legalMove = canSlide(game, sourceRow, sourceCol, targetRow,
targetCol);
// Go with the regular flow, jumps first then "slides". }
isJump = canPlayerJump(game);
if (isJump) { }
legalMove = canJump(game, sourceRow, sourceCol, targetRow,
targetCol); return legalMove;
} else { }
legalMove = canSlide(game, sourceRow, sourceCol, targetRow,
targetCol); private static boolean canPlayerJump(Game game) {
} // TODO: Implement me.
return false;
} }
return legalMove; private static boolean canSlide(Game game, int sourceRow, int sourceCol, int targetRow,
} int targetCol) {
private static boolean canPlayerJump(Game game) { boolean legalMove = true;
// TODO: Implement me. boolean mustJump = canPlayerJump(game);
return false;
} // Is the move even on the board?
legalMove = game.getGameBoard().isLegalPosition(sourceRow, sourceCol)
private static boolean canSlide(Game game, int sourceRow, int sourceCol, int targetRow, && game.getGameBoard().isLegalPosition(targetRow, targetCol);
int targetCol) {
// See if the destination is even empty.
boolean legalMove = true; if (legalMove) {
boolean mustJump = canPlayerJump(game); legalMove = game.getGameBoard().isEmpty(targetRow, targetCol);
}
// Is the move even on the board?
legalMove = game.getGameBoard().isLegalPosition(sourceRow, sourceCol) // If yes, then look if right pieces were chosen.
&& game.getGameBoard().isLegalPosition(targetRow, targetCol); if (legalMove && !mustJump) {
if (game.isLightPlayerTurn()
// See if the destination is even empty. && game.getGameBoard().isLight(sourceRow, sourceCol)) {
if (legalMove) {
legalMove = game.getGameBoard().isEmpty(targetRow, targetCol); // To deal with flying kings.
} if (game.getGameBoard().isKing(sourceRow, sourceCol)
&& game.getGameRules().canKingsFly()) {
// If yes, then look if right pieces were chosen.
if (legalMove && !mustJump) { // FIXME: Fix this!
if (game.isLightPlayerTurn() } else {
&& game.getGameBoard().isLight(sourceRow, sourceCol)) { // if ((Math.abs(targetRow - sourceRow) == 1) && (Math.abs(targetRow - sourceRow) == 1)) {
// legalMove = false;
// To deal with flying kings. // }
if (game.getGameBoard().isKing(sourceRow, sourceCol) }
&& game.getGameRules().canKingsFly()) {
// Is the path clear for that move?
// FIXME: Fix this!
} else { } else if (!game.isLightPlayerTurn()
// if ((Math.abs(targetRow - sourceRow) == 1) && (Math.abs(targetRow - sourceRow) == 1)) { && game.getGameBoard().isDark(sourceRow, sourceCol)) {
// legalMove = false;
// } //TODO: Implement me, sometime.
} } else {
legalMove = false;
// Is the path clear for that move? }
}
} else if (!game.isLightPlayerTurn()
&& game.getGameBoard().isDark(sourceRow, sourceCol)) { return legalMove;
}
//TODO: Implement me, sometime.
} else { private static void checkForVictory(Game game) {
legalMove = false; // TODO: Implement me.
} }
}
/**
return legalMove; * Gets if a piece is movable. Returns true if the piece can slide or jump.
} * This method only calculates slides to the adjacent positions. Similarly,
* the method only looks at jumping an adjacent enemy piece. This check is
private static void checkForVictory(Game game) { * used by the graphical user interface to determine if a piece can be moved
// TODO: Implement me. * either for sliding or jumping. The method is aware of whose turn is it to
} * move.
*
/** * @param row
* Gets if a piece is movable. Returns true if the piece can slide or jump. * The row coordinate of the piece to check.
* This method only calculates slides to the adjacent positions. Similarly, * @param col
* the method only looks at jumping an adjacent enemy piece. This check is * The column coordinate of the piece to check.
* used by the graphical user interface to determine if a piece can be moved * @return Returns true if the piece can slide or jump in this turn.
* either for sliding or jumping. The method is aware of whose turn is it to */
* move. public static boolean isMovablePiece(Game game, int row, int col) {
*
* @param row // Fields for determining of a piece is movable.
* The row coordinate of the piece to check. boolean moveUpLeft = true;
* @param col boolean moveUpRight = true;
* The column coordinate of the piece to check. boolean moveDownLeft = true;
* @return Returns true if the piece can slide or jump in this turn. boolean moveDownRight = true;
*/
public static boolean isMovablePiece(Game game, int row, int col) { /*
* Checks first if the first colour of piece is being grabbed. Next if
// Fields for determining of a piece is movable. * the piece is blocked by its own pieces. Next if the opponent has
boolean moveUpLeft = true; * double blocked off the pieces. Also sanity checks if looking past the
boolean moveUpRight = true; * size of the board.
boolean moveDownLeft = true; */
boolean moveDownRight = true; if (game.isLightPlayerTurn() && game.getGameBoard().isLight(row, col)) { // Light
// player.
/*
* Checks first if the first colour of piece is being grabbed. Next if // Can piece move normally?
* the piece is blocked by its own pieces. Next if the opponent has moveDownLeft = canSlide(game, row, col, row + 1, col - 1);
* double blocked off the pieces. Also sanity checks if looking past the moveDownRight = canSlide(game, row, col, row + 1, col + 1);
* size of the board.
*/ if (game.getGameBoard().isKing(row, col)) {
if (game.isLightPlayerTurn() && game.getGameBoard().isLight(row, col)) { // Light moveUpLeft = canSlide(game, row, col, row - 1, col - 1);
// player. moveUpRight = canSlide(game, row, col, row - 1, col + 1);
} else {
// Can piece move normally? moveUpLeft = false;
moveDownLeft = canSlide(game, row, col, row + 1, col - 1); moveUpRight = false;
moveDownRight = canSlide(game, row, col, row + 1, col + 1); }
if (game.getGameBoard().isKing(row, col)) { // If no slides available try doing the same except for jumps.
moveUpLeft = canSlide(game, row, col, row - 1, col - 1); if (!moveDownLeft) {
moveUpRight = canSlide(game, row, col, row - 1, col + 1); moveDownLeft = canJump(game, row, col, row + 2, col - 2);
} else { } else if (!moveDownRight) {
moveUpLeft = false; moveDownRight = canJump(game, row, col, row + 2, col + 2);
moveUpRight = false; } else if (game.getGameBoard().isKing(row, col)
} || game.getGameRules().canPawnsJumpBackwards()) {
// If no slides available try doing the same except for jumps. if (!moveUpLeft) {
if (!moveDownLeft) { moveUpLeft = canJump(game, row, col, row - 2, col + 2);
moveDownLeft = canJump(game, row, col, row + 2, col - 2); } else if (!moveUpRight) {
} else if (!moveDownRight) { moveUpRight = canJump(game, row, col, row - 2, col - 2);
moveDownRight = canJump(game, row, col, row + 2, col + 2); }
} else if (game.getGameBoard().isKing(row, col)
|| game.getGameRules().canPawnsJumpBackwards()) { }
if (!moveUpLeft) { return moveUpLeft || moveUpRight || moveDownLeft || moveDownRight;
moveUpLeft = canJump(game, row, col, row - 2, col + 2);
} else if (!moveUpRight) { } else if (game.isLightPlayerTurn() && game.getGameBoard().isDark(row, col)) { // Dark
moveUpRight = canJump(game, row, col, row - 2, col - 2); // player
}
// Can piece move normally?
} moveUpLeft = canSlide(game, row, col, row - 1, col - 1);
moveUpRight = canSlide(game, row, col, row - 1, col + 1);
return moveUpLeft || moveUpRight || moveDownLeft || moveDownRight;
if (game.getGameBoard().isKing(row, col)) {
} else if (game.isLightPlayerTurn() && game.getGameBoard().isDark(row, col)) { // Dark moveDownLeft = canSlide(game, row, col, row + 1, col - 1);
// player moveDownRight = canSlide(game, row, col, row + 1, col + 1);
} else {
// Can piece move normally? moveDownLeft = false;
moveUpLeft = canSlide(game, row, col, row - 1, col - 1); moveDownRight = false;
moveUpRight = canSlide(game, row, col, row - 1, col + 1); }
if (game.getGameBoard().isKing(row, col)) { // If no slides available try doing the same except for jumps.
moveDownLeft = canSlide(game, row, col, row + 1, col - 1); if (!moveUpLeft) {
moveDownRight = canSlide(game, row, col, row + 1, col + 1); moveUpLeft = canJump(game, row, col, row - 2, col - 2);
} else { } else if (!moveUpRight) {
moveDownLeft = false; moveUpRight = canJump(game, row, col, row - 2, col + 2);
moveDownRight = false; } else if (game.getGameBoard().isKing(row, col)
} || game.getGameRules().canPawnsJumpBackwards()) {
// If no slides available try doing the same except for jumps. if (!moveDownLeft) {
if (!moveUpLeft) { moveDownLeft = canJump(game, row, col, row + 2, col + 2);
moveUpLeft = canJump(game, row, col, row - 2, col - 2); } else if (!moveDownRight) {
} else if (!moveUpRight) { moveDownRight = canJump(game, row, col, row + 2, col - 2);
moveUpRight = canJump(game, row, col, row - 2, col + 2); }
} else if (game.getGameBoard().isKing(row, col)
|| game.getGameRules().canPawnsJumpBackwards()) { }
if (!moveDownLeft) { return moveUpLeft || moveUpRight || moveDownLeft || moveDownRight;
moveDownLeft = canJump(game, row, col, row + 2, col + 2);
} else if (!moveDownRight) { } else {
moveDownRight = canJump(game, row, col, row + 2, col - 2); return false; // A wrong coloured piece.
} }
} }
return moveUpLeft || moveUpRight || moveDownLeft || moveDownRight; /**
* Moves a pieces from one location to another. This move maybe either be a
} else { * move or a jump. This method is called by a user interface when a user
return false; // A wrong coloured piece. * moves a piece on screen or over the network. The piece is moved if the
} * current state of the game allows for it to do so.
*
} * TODO: Add priority for king jumps over pawn jumps for any variants that
* do so. TODO: Implement jumping by piece removal.
/** *
* Moves a pieces from one location to another. This move maybe either be a * @param sourceRow
* move or a jump. This method is called by a user interface when a user * The row from where the piece is moving from.
* moves a piece on screen or over the network. The piece is moved if the * @param sourceCol
* current state of the game allows for it to do so. * The column from where the piece is moving from.
* * @param targetRow
* TODO: Add priority for king jumps over pawn jumps for any variants that * The row to where the piece is moving to.
* do so. TODO: Implement jumping by piece removal. * @param targetCol
* * The column to where the piece is moving to.
* @param sourceRow */
* The row from where the piece is moving from. public static void movePiece(Game game, int sourceRow, int sourceCol, int targetRow,
* @param sourceCol int targetCol) {
* The column from where the piece is moving from.
* @param targetRow // If everything checks out... move the piece!
* The row to where the piece is moving to. if (canMove(game, sourceRow, sourceCol, targetRow, targetCol)) {
* @param targetCol if (game.getJumpInProgress() != null) {
* The column to where the piece is moving to.
*/ // TODO: Implement jumping via removing of piece.
public static void movePiece(Game game, int sourceRow, int sourceCol, int targetRow, game.getGameBoard().movePiece(sourceRow, sourceCol, targetRow,
int targetCol) { targetCol);
} else {
// If everything checks out... move the piece! game.getGameBoard().movePiece(sourceRow, sourceCol, targetRow,
if (canMove(game, sourceRow, sourceCol, targetRow, targetCol)) { targetCol);
if (game.getJumpInProgress() != null) { }
// TODO: Implement jumping via removing of piece. checkForVictory(game);
game.getGameBoard().movePiece(sourceRow, sourceCol, targetRow, }
targetCol);
} else { }
game.getGameBoard().movePiece(sourceRow, sourceCol, targetRow,
targetCol); }
}
checkForVictory(game);
}
}
}

View File

@ -0,0 +1,41 @@
#
# Copyright (c) 2014 Dorian Pula <dorian.pula@amber-penguin-software.ca>
#
# justCheckers is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
#
# justCheckers is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with justCheckers. If not, see <http://www.gnu.org/licenses/>.
#
# Please share and enjoy!
#
class Player(object):
"""
Manages the information of a single player.
:author: Chris Bellini
:author: Dorian Pula
"""
def __init__(self, name='Unnamed Player', wins=0, losses=0, ties=0):
self.name = name
self.wins = wins
self.losses = losses
self.ties = ties
def total_games_played(self):
return self.wins + self.losses + self.ties
def __str__(self):
return 'Name: {name} \n Games: Won {wins} \ Lost {losses} \ Tied {ties}'.format(
name=self.name, wins=self.wins, losses=self.losses, ties=self.ties
)

216
justcheckers/game/rules.py Normal file
View File

@ -0,0 +1,216 @@
#
# Copyright (c) 2014 Dorian Pula <dorian.pula@amber-penguin-software.ca>
#
# justCheckers is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
#
# justCheckers is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with justCheckers. If not, see <http://www.gnu.org/licenses/>.
#
# Please share and enjoy!
#
from enum import Enum
class CheckersVariant(Enum):
AMERICAN = 0
INTERNATIONAL = 1
BRAZILIAN = 2
CANADIAN = 3
POOL = 4
SPANISH = 5
RUSSIAN = 6
ITALIAN = 7
SUICIDE = 8
GHANAIAN = 9
class Rules(object):
"""
Abstraction of the rules for a game of checkers.
The rules for a game of checkers. This class provides a reference object for
a game of checkers. This helps deal with the number of variants of checkers.
One of the goals of justCheckers is to provide the flexibility of choose
between different kinds of checker variants. This class builds a skeleton of
the rules by defining what setup, moves, jumps, victory conditions and
special moves make up a particular variant of checkers.
:author: Dorian Pula
:author: Chris Bellini
"""
# Victory conditions.
# Victory achieved by capturing all enemy pieces. */
CAPTURE_ALL_ENEMIES_VICTORY = 0
# TODO: Implement special rules for these checkers. Version >0.3?
# Victory achieved by capturing all pieces. Only caveat is the three king
# * versus one king draw rule:
# *
# * In many games at the end one adversary has three kings while the other
# * one has just one king. In such a case the first adversary must win in
# * thirteen moves or the game is declared a draw. (Shamelessly stolen from
# * http://en.wikipedia.org/wiki/Draughts).
# */
SPECIAL_POOL_VICTORY = 1
# Victory achieved some bizarre manner. TODO: Figure out Russian checkers.
SPECIAL_RUSSIAN_VICTORY = 2
# Victory achieved by losing all your pieces.
SPECIAL_SUICIDE_VICTORY = 3
# Victory achieved by not being the first with one piece left.
SPECIAL_GHANAIAN_VICTORY = 4
# TODO Move out into individual implementing Rules.
# Checker board sizes.
# Using a "standard" American checkers board.
STANDARD_BOARD_SIZE = 8
def __init__(self,
variant,
board_size=STANDARD_BOARD_SIZE,
kings_jump_multiple_times=True,
pawns_jump_backward=True,
light_player_starts_first=True,
mirrored_board=False,
force_capture=True,
force_capture_maximum=True):
self.checkers_variant = variant
self.board_size = board_size
self.can_kings_jump_multiple_times = kings_jump_multiple_times
self.can_pawns_jump_backwards = pawns_jump_backward
self.does_light_player_start_first = light_player_starts_first
self.is_board_mirrored = mirrored_board
self.is_player_forced_to_capture = force_capture
self.is_player_forced_to_capture_maximum_possible = force_capture_maximum
def is_player_victorious(self, player, game):
# TODO Check if the player is victorious
# TODO Implement me for the standard capture or block all opponent pieces.
return False
class AmericanRules(Rules):
def __init__(self):
super(AmericanRules, self).__init__(
variant=CheckersVariant.AMERICAN,
kings_jump_multiple_times=False,
pawns_jump_backward=False,
light_player_starts_first=False,
force_capture_maximum=False,
)
class InternationalRules(Rules):
INTERNATIONAL_BOARD_SIZE = 10
def __init__(self):
super(InternationalRules, self).__init__(
variant=CheckersVariant.INTERNATIONAL,
board_size=self.INTERNATIONAL_BOARD_SIZE,
)
class BrazilianRules(Rules):
def __init__(self):
super(BrazilianRules, self).__init__(
variant=CheckersVariant.BRAZILIAN,
)
class CanadianRules(Rules):
CANADIAN_BOARD_SIZE = 12
def __init__(self):
super(CanadianRules, self).__init__(
variant=CheckersVariant.CANADIAN,
board_size=self.CANADIAN_BOARD_SIZE,
force_capture_maximum=False,
)
class PoolRules(Rules):
def __init__(self):
super(PoolRules, self).__init__(
variant=CheckersVariant.POOL,
light_player_starts_first=False,
force_capture_maximum=False,
)
def is_player_victorious(self, player, game):
# TODO Check if the player is victorious
# TODO Implement special rules for Pool checkers.
return False
class SpanishRules(Rules):
def __init__(self):
super(SpanishRules, self).__init__(
variant=CheckersVariant.SPANISH,
pawns_jump_backward=False,
mirrored_board=True,
)
class RussianRules(Rules):
# TODO: Needs special freshly-kinged-but-still-can-jump special rule.
def __init__(self):
super(RussianRules, self).__init__(
variant=CheckersVariant.RUSSIAN,
force_capture_maximum=False,
)
def is_player_victorious(self, player, game):
# TODO Check if the player is victorious
# TODO Implement special rules for Russian checkers.
return False
class ItalianRules(Rules):
def __init__(self):
super(ItalianRules, self).__init__(
variant=CheckersVariant.ITALIAN,
pawns_jump_backward=False,
mirrored_board=True,
)
# TODO: Special rule on must jump most number of kings per capture.
# TODO: Special rule that pawns can't capture kings.
class SuicideRules(Rules):
# TODO: Needs unconventional setup.
def __init__(self):
super(SuicideRules, self).__init__(
variant=CheckersVariant.SUICIDE,
)
def is_player_victorious(self, player, game):
# TODO Check if the player is victorious
# TODO Implement special rules for suicide checkers.
return False
class GhanaianRules(Rules):
# TODO: Special forfeit king if passing up a king's capture opportunity.
def __init__(self):
super(GhanaianRules, self).__init__(
variant=CheckersVariant.GHANAIAN,
mirrored_board=True,
force_capture_maximum=False,
)
def is_player_victorious(self, player, game):
# TODO Check if the player is victorious
# TODO Implement special rules for Ghanian checkers.
return False

View File

@ -1 +0,0 @@
include 'core', 'console', 'web', 'android', 'desktop'