Compare commits

...

65 Commits

Author SHA1 Message Date
Dorian a60a9959b9 Add notes for next steps. 2019-03-04 08:37:35 -05:00
Dorian 3d1f6f4ec8 Simplify code and improve setup. 2019-03-04 08:27:22 -05:00
Dorian 4e695f3a7e Create a new simple game setup. 2019-03-02 16:49:09 -05:00
Dorian 04d6837b5e Improve formatting setup.
Add concept of games.
2019-03-02 16:44:29 -05:00
Dorian c1608bacd1 Add working layout and setup code for the game engine. 2019-03-02 07:43:42 -05:00
Dorian 3af3ede5a7 Fix up setup of an initial game. 2019-03-02 00:16:50 -05:00
Dorian 6b9027bdd8 Build out system to get formatted display. 2019-03-01 21:46:06 -05:00
Dorian fc9a706c90 Add basic test for creating a gameboard representation. 2019-03-01 11:04:06 -05:00
Dorian 5e24c02cfb Implement basic setup of the checkerboard. 2019-03-01 09:04:11 -05:00
Dorian f20aa6989c Start by defining enums for pieces and the board. 2019-02-28 09:06:24 -05:00
Dorian c28458ff43 Update documentation and remove redundant sources. 2019-02-28 08:49:26 -05:00
Dorian 3023f51e13 Start initial layout for justcheckers project as cargo workspace. 2019-02-28 08:39:27 -05:00
Dorian d152eb52d7 Experiment with Qt Quick 2 controls. 2018-08-15 17:06:32 -04:00
Dorian 2bb6ae818e Add in example of working audio. 2018-02-22 08:03:26 -05:00
Dorian a1e0c9ebb1 Add in QML components. 2018-02-16 19:51:45 -05:00
Dorian b33b6cf71c Break out menu button into component. Add menu items. 2018-02-15 08:57:36 -05:00
Dorian e1ca79c291 Work in more realistic button layout. 2018-02-14 08:53:52 -05:00
Dorian 2c6ec93484 Get examples of working buttons. 2018-02-13 23:22:15 -05:00
Dorian 329152860d Figure out how to pass in properties. 2018-02-13 15:18:59 -05:00
Dorian 7b36312ed3 Build out very basic layout of menu based on Kivy. 2018-02-13 08:53:53 -05:00
Dorian 3f408edde6 First baby step to rebuilding justCheckers in Qt/QML. 2018-02-13 08:27:46 -05:00
Dorian 0e381b45ec Start the Qt transition of justCheckers. 2018-01-24 08:47:44 -05:00
Dorian 1a385d57bd Break out setup of game tile into a more complicated object. 2017-06-01 09:14:38 -04:00
Dorian c28457bbcf Play around with decorating the game tiles. 2017-05-31 08:43:19 -04:00
Dorian b6ff53fd8d Ensure that game board tiles get placed together. 2017-05-31 08:19:00 -04:00
Dorian c58c8b45fe Update to run tasks with invoke. 2017-04-19 08:41:32 -04:00
Dorian b23d4a9460 Add experimental pipfile management of dependencies. 2017-04-19 08:34:43 -04:00
Dorian 5f3e282afb Ignore the buildozer workspace. 2017-03-17 08:27:13 -04:00
Dorian f727ba7843 Quick gist of a checkerboard. 2017-02-26 19:28:39 -05:00
Dorian 81b17bef75 Allow stretching of backdrop image. 2017-02-24 00:14:22 -05:00
Dorian c6b39091ad Move assets to work in new setup. 2017-02-24 00:10:50 -05:00
Dorian c98a7d15d5 Add credit / license screen.
Add a basic buildozer setup.
2017-02-23 23:23:16 -05:00
Dorian 0505a10045 Refactor main menu button group in kv file. 2017-02-23 09:15:38 -05:00
Dorian 053430b77c Replicate main menu completely with styling. 2017-02-23 08:34:31 -05:00
Dorian a36a50464c Build up settings and main menu for justCheckers. 2017-02-22 23:53:21 -05:00
Dorian eddfac271a Recreate basic screen changing in PySide app. 2017-02-22 18:21:50 -05:00
Dorian ea9de695fd Convert Qt main window setup into Kivy app. 2017-02-22 17:55:44 -05:00
Dorian e5dae0520d Quick rough setup of justCheckers as a Kivy app. 2017-02-22 09:27:13 -05:00
Dorian 35742760b3 Initial setup to work with Kivy instead of PySide. 2014-09-16 08:00:25 -04:00
Dorian 750f561880 Experiment to use QGraphicsView to build out checkboard UI. 2014-09-15 09:14:49 -04:00
Dorian dc49718352 First steps to drawing a checkboard with pieces using OpenGL. 2014-09-04 08:47:15 -04:00
Dorian f9468b0562 Add in game board view.
Add in experimental OpenGL test to see if possible to use OpenGL as part of checkboard drawing.
2014-08-20 13:19:31 -04:00
Dorian 1079aca0bd Fix up board with unicode characters. 2014-08-20 09:01:57 -04:00
Dorian 0df9912730 Updated the main README for the project. 2014-08-20 08:06:08 -04:00
Dorian 0a8fdc0e93 Migrate internal game documentation to Markdown.
Minor fixes to info view.
2014-08-20 07:57:04 -04:00
Dorian 0039466767 Recreate the info activity as a PySide QWebView.
Add in Markdown for the documentation assets.
2014-08-20 07:39:08 -04:00
Dorian d791840bdd Raw translation of Java code into Python code. 2014-08-18 23:29:13 -04:00
Dorian cf103bcbb8 First pass on converting existing Java game code into Python. 2014-08-13 00:20:22 -04:00
Dorian 8ec38e5020 Fix requirements for project.
Fix gitignore to reflect a more Python specific project.
2014-08-07 17:47:35 -04:00
Dorian 11f7bf2789 Bring in extra invoke tasks from the rookeries project. 2014-08-07 08:22:04 -04:00
Dorian 6df858e7eb Rename tests directory for nosetests.
Remove cruft test Java stub classes.
2014-08-07 08:05:22 -04:00
Dorian 02dbdaa633 Improve logo in main menu. 2014-08-07 08:04:14 -04:00
Dorian d196d109ce Refactor main menu button construction.
Work on logo image loading.
2014-08-01 08:12:56 -04:00
Dorian bb21cc4577 Add in logo to main menu.
Add requirement for enums.
2014-07-31 22:27:20 -04:00
Dorian aace9864c2 Move app and game debug log into app module.
Remove old Java log class.
2014-07-31 21:46:11 -04:00
Dorian b80009850e Split up current app into separate UI components.
Add backdrop to main window.
Add troves and main entry point for app.
2014-07-31 21:25:50 -04:00
Dorian 5d2ecec3fb Move around existing Java class to convert into Python modules. 2014-07-30 18:30:14 -04:00
Dorian c51123767c Move image and text assets into justcheckers folder. \n Delete old Android main menu setup. \n Recreate main menu in PySide. 2014-07-30 08:33:43 -04:00
Dorian 1a23686e48 Remove Gradle and Android assets. Add version number to justcheckers main package. 2014-07-29 18:07:53 -04:00
Dorian b1a0024edf Minor stylistic code edits. 2014-07-29 17:59:29 -04:00
Dorian 6b9ecb5785 Split up extra requirements away from the rest of the project.
Add setup.py for PyPI distribution.
Enhance Invoke tasks.
2014-07-22 20:19:52 -04:00
Dorian a4e22c1f9b Simplify the calling of the application. Remove unneeded label. 2014-07-21 18:09:48 -04:00
Dorian c3bb8b453d Initial attempt at a PySide based UI. 2014-07-18 17:53:19 -04:00
Dorian fff98a41df Experimentation with QML. Plan to revert to a non-QML setup for now. 2014-07-10 08:08:37 -04:00
Dorian f209dc1d87 Experimental setup of a PySide + QML app for justCheckers. 2014-07-05 22:54:00 -04:00
93 changed files with 2356 additions and 5332 deletions

85
.gitignore vendored
View File

@ -1,8 +1,83 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe
# Original kivy ignored
bin
.DS_Store
.idea
.gradle
.eclipse
.settings
*.iml
classes
.buildozer
*.pyc
docs/_build
justcheckers.ini
/target
**/*.rs.bk

6
Board.qml Normal file
View File

@ -0,0 +1,6 @@
import QtQuick 2.0
Rectangle {
anchors.fill: parent
color: "orange"
}

View File

@ -1,11 +1,11 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
# GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
## Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
@ -68,7 +68,8 @@ patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
## TERMS AND CONDITIONS
0. Definitions.

6
Cargo.lock generated Normal file
View File

@ -0,0 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "justcheckers-engine"
version = "0.6.0"

5
Cargo.toml Normal file
View File

@ -0,0 +1,5 @@
[workspace]
members = [
"engine",
]

108
Menu.qml Normal file
View File

@ -0,0 +1,108 @@
import QtQuick 2.0
import QtMultimedia 5.8
import QtQuick.Controls 2.2
import QtQuick.Controls.Material 2.2
Rectangle {
anchors.fill: parent
Image {
source: 'images/backdrop.jpg'
anchors.fill: parent
}
Rectangle {
id: logo
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 20
color: Qt.rgba(1, 1, 1, 0.5)
width: parent.width
height: logoImage.height
Image {
id: logoImage
source: 'images/logo.png'
anchors.horizontalCenter: parent.horizontalCenter
}
}
Column {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
width: parent.width
spacing: 10
MenuButton {
buttonText: "New Game"
function actionOnClick() {
appPage.source = "Board.qml"
}
}
MenuButton {
buttonText: "Open Game"
enabled: false
}
MenuButton {
buttonText: "Save Game"
enabled: false
function actionOnClick() {
pingSound.seek(0)
pingSound.play()
}
// From: https://freesound.org/people/edsward/sounds/341871/
Audio {
id: pingSound
source: 'assets/ping.wav'
autoLoad: true
}
}
MenuButton {
buttonText: "About justCheckers"
}
MenuButton {
buttonText: "Settings"
}
Button {
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - 50
height: parent.parent.height * 0.1
text: "Quit"
onPressed: Qt.quit()
Material.accent: Material.Orange
}
MenuButton {
buttonText: "Quit"
function actionOnClick() {
Qt.quit()
}
}
}
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
color: Qt.rgba(1, 1, 1, 0.5)
width: parent.width
height: 20
Text {
text: "v" + appVersion
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 20
}
}
}

56
MenuButton.qml Normal file
View File

@ -0,0 +1,56 @@
import QtQuick 2.0
import QtGraphicalEffects 1.0
Rectangle {
id: button
property color backgroundAtRest: "#9e9e9e"
property color backgroundActive: "#555555"
property string buttonText: "Button"
property bool enabled: true
function actionOnClick() { }
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - 50
height: parent.parent.height * 0.1
radius: 10
color: {
if (enabled)
backgroundActive
else
backgroundAtRest
}
border.color: "#333333"
border.width: 2
antialiasing: true
layer.enabled: true
layer.effect: DropShadow {
transparentBorder: true
horizontalOffset: 5
verticalOffset: 5
radius: 5.0
samples: 5
}
Text {
text: buttonText
font.pointSize: parent.height * 0.2
font.bold: true
height: 30
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
MouseArea {
anchors.fill: parent
onPressed: button.color = backgroundActive
onReleased: button.color = backgroundAtRest
onClicked: actionOnClick()
}
}

16
Pipfile Normal file
View File

@ -0,0 +1,16 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
[dev-packages]
invoke = "*"
[packages]
Cython = "==0.23"
PyInstaller = "*"
[packages.Kivy]
git = "https://github.com/kivy/kivy"
[dev-packages.buildozer]
git = "https://github.com/kivy/buildozer"

56
Pipfile.lock generated Normal file
View File

@ -0,0 +1,56 @@
{
"_meta": {
"hash": {
"sha256": "40e008e812036981170caeb7b5fe7df74140cee7b9afbf3c98d8d8569fa2260d"
},
"requires": {},
"sources": [
{
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"Cython": {
"hash": "sha256:7e23a6b242880ff95f5835c72e4e2a5bec42f801b0c18176d4379c05894007a6",
"version": "==0.23"
},
"Kivy": {
"git": "https://github.com/kivy/kivy"
},
"PyInstaller": {
"hash": "sha256:f08ca806bc26e62034bca181a4b85de22568a3d39bdb062f05927c6e86c2a48c",
"version": "==3.2.1"
},
"appdirs": {
"hash": "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e",
"version": "==1.4.3"
},
"packaging": {
"hash": "sha256:99276dc6e3a7851f32027a68f1095cd3f77c148091b092ea867a351811cfe388",
"version": "==16.8"
},
"pyparsing": {
"hash": "sha256:fee43f17a9c4087e7ed1605bd6df994c6173c1e977d7ade7b651292fab2bd010",
"version": "==2.2.0"
},
"setuptools": {
"hash": "sha256:33a7b7910651bea57164c6c6dd66a2b1c5196c0f78ee2ff7319ce7bd031714c0",
"version": "==35.0.1"
},
"six": {
"hash": "sha256:0ff78c403d9bccf5a425a6d31a12aa6b47f1c21ca4dc2573a7e2f32a97335eb1",
"version": "==1.10.0"
}
},
"develop": {
"buildozer": {
"git": "https://github.com/kivy/buildozer"
},
"invoke": {
"hash": "sha256:a1c825fcc213b6b1ee35a9483556bd8ade0ff549ac96132f58d679087cbfc57b",
"version": "==0.16.3"
}
}
}

16
README.md Normal file
View File

@ -0,0 +1,16 @@
# justCheckers
*justCheckers* is an advanced, cross-platform, libre source checkers game.
The project's aim is to make a game capable of supporting:
- Skinning
- Network Games
- Computer Opponents
- Various Rules and Internationalization
- Multiple Desktop and Mobile OS
## Links
- [Website](http://justcheckers.dorianpula.ca/)
- [Project Source](https://bitbucket.org/dorianpula/justcheckers/)
- [Worlds Draughts Federation](https://fmjd.org/)

View File

@ -1,26 +0,0 @@
======================
justCheckers - README!
======================
About the Project
-----------------
*justCheckers* is an advanced open source checkers game for Android. The aim of
the project is to make a game capable of supporting:
- Skinning
- Network Games
- Computer Opponents
- Various Rules and Internationalizations
- Cross platform (both OS and input types)
Current Progress
----------------
The *justCheckers* project is in the middle of a general overhaul of the codebase to allow for a more modern approach. Both the game engine needs to get decoupled from the platform specific code.
Links
-----
- Project website: http://justcheckers.org/
- Project @ Github: https://github.com/dorianpula/justcheckers

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.justcheckers.android"
android:versionCode="1"
android:versionName="0.1.1">
<application android:icon="@drawable/icon" android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<activity android:name="org.justcheckers.android.MenuActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="org.justcheckers.android.GameActivity" />
<activity android:name="org.justcheckers.android.InfoActivity" />
<activity android:name="org.justcheckers.android.SettingsActivity" />
</application>
<uses-sdk android:minSdkVersion="7" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View File

@ -1,60 +0,0 @@
/*
Modular Gradle Build for justCheckers Android
---------------------------------------------
Author: Dorian Pula (dorian.pula@amber-penguin-software.ca)
License: AGPL v3.
Gradle docs:
http://www.gradle.org/docs/current/userguide/userguide_single.html
Gradle Android build docs:
https://sites.google.com/a/android.com/tools/tech-docs/new-build-system
*/
buildscript {
repositories {
maven { url 'http://repo1.maven.org/maven2' }
}
dependencies { classpath 'com.android.tools.build:gradle:0.3' }
}
apply plugin: 'android'
sourceCompatibility = 1.6
targetCompatibility = 1.6
// Description of the project
description = 'justcheckers-android'
version = '0.3'
// Androids!!!
android {
compileSdkVersion 14
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aild.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
instrumentTest.setRoot('tests')
}
}
// Setup build script repositories starting with Maven repositories
repositories {
maven {
url 'http://repo1.maven.org/maven2'
}
}
// Dependency management
dependencies {
compile project(':core')
//compile 'org.slf4j:slf4j-android:1.6.1-RC1'
}

View File

@ -1 +0,0 @@
sdk.dir=/home/dorian/Coding/android-sdk-linux

View File

@ -1,34 +0,0 @@
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class com.android.vending.licensing.ILicensingService
-keepclasseswithmembers class * {
native <methods>;
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}

View File

@ -1,11 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "ant.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-14

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,405 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/screen_root"
android:background="@drawable/backdrop"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView android:id="@+id/app_logo"
android:background="#DDFFFFFF"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dip"
android:src="@drawable/logo" />
<TableLayout android:id="@+id/game_board"
android:layout_below="@id/app_logo"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip">
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
</TableRow>
</TableLayout>
<TableLayout android:id="@+id/player_captured_pieces"
android:background="#DDFFFFFF"
android:layout_below="@+id/app_logo"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_toRightOf="@+id/game_board"
android:layout_width="wrap_content">
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:id="@+id/opposing_player_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip"
android:text="@string/template_opposing_player"
android:textColor="#FF000000"/>
<ImageView android:id="@+id/opposing_player_king"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/defend_king" />
<TextView android:id="@+id/opposing_player_king_captured"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF000000"
android:text="@string/template_capture_amounts" />
<ImageView android:id="@+id/opposing_player_pawn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/defend_pawn" />
<TextView android:id="@+id/opposing_player_pawn_captured"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF000000"
android:text="@string/template_capture_amounts" />
</TableRow>
</TableLayout>
<TableLayout android:id="@+id/opponent_captured_pieces"
android:background="#DDFFFFFF"
android:layout_below="@id/player_captured_pieces"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_toRightOf="@+id/game_board"
android:layout_width="wrap_content">
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:id="@+id/current_player_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/template_current_player"
android:textColor="#FF000000" android:padding="5dip"/>
<ImageView android:id="@+id/current_player_king"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/attack_king" />
<TextView android:id="@+id/current_player_king_captured"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF000000"
android:text="@string/template_capture_amounts" />
<ImageView android:id="@+id/current_player_pawn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/attack_pawn" />
<TextView android:id="@+id/current_player_pawn_captured"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF000000"
android:text="@string/template_capture_amounts" />
</TableRow>
</TableLayout>
</RelativeLayout>

View File

@ -1,407 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/screen_root"
android:background="@drawable/backdrop"
android:gravity="center_horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView android:id="@+id/app_logo"
android:background="#DDFFFFFF"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dip"
android:src="@drawable/logo" />
<TableLayout android:id="@+id/game_board"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip">
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/non_play" />
</TableRow>
</TableLayout>
<TableLayout android:id="@+id/player_captured_pieces"
android:background="#DDFFFFFF"
android:layout_below="@+id/game_board"
android:layout_centerHorizontal="true"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_width="wrap_content">
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:id="@+id/opposing_player_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip"
android:text="@string/template_opposing_player"
android:textColor="#FF000000"/>
<ImageView android:id="@+id/opposing_player_king"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/defend_king" />
<TextView android:id="@+id/opposing_player_king_captured"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF000000"
android:text="@string/template_capture_amounts" />
<ImageView android:id="@+id/opposing_player_pawn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/defend_pawn" />
<TextView android:id="@+id/opposing_player_pawn_captured"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF000000"
android:text="@string/template_capture_amounts" />
</TableRow>
</TableLayout>
<TableLayout android:id="@+id/opponent_captured_pieces"
android:background="#DDFFFFFF"
android:layout_below="@id/player_captured_pieces"
android:layout_centerHorizontal="true"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_width="wrap_content">
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:id="@+id/current_player_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/template_current_player"
android:textColor="#FF000000" android:padding="5dip"/>
<ImageView android:id="@+id/current_player_king"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/attack_king" />
<TextView android:id="@+id/current_player_king_captured"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF000000"
android:text="@string/template_capture_amounts" />
<ImageView android:id="@+id/current_player_pawn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/attack_pawn" />
<TextView android:id="@+id/current_player_pawn_captured"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF000000"
android:text="@string/template_capture_amounts" />
</TableRow>
</TableLayout>
</RelativeLayout>

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/screen_root"
android:background="@drawable/backdrop"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ImageView android:id="@+id/app_logo"
android:background="#DDFFFFFF"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dip"
android:src="@drawable/logo" />
<ScrollView
android:layout_below="@+id/app_logo"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_width="fill_parent">
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent">
<TextView android:id="@+id/info_text"
android:background="#BBFFFFFF"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:padding="5dip"
android:textColor="#FF000000" />
</LinearLayout>
</ScrollView>
</RelativeLayout>

View File

@ -1,70 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/screen_root"
android:background="@drawable/backdrop"
android:gravity="center_horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ImageView android:id="@+id/app_logo"
android:background="#DDFFFFFF"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:src="@drawable/logo"/>
<TableLayout android:id="@+id/menu_table"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp">
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button android:id="@+id/game_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/caption_play_checkers" />
<Button android:id="@+id/website_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/caption_visit_us" />
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button android:id="@+id/about_us_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/caption_about_us" />
<Button android:id="@+id/license_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/caption_license" />
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button android:id="@+id/settings_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/caption_settings" />
<Button android:id="@+id/quit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/caption_quit" />
</TableRow>
</TableLayout>
</RelativeLayout>

View File

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="Application Settings">
<CheckBoxPreference
android:title="Start New Game on Startup"
android:defaultValue="false"
android:summary="Should the app automatically start a new game."
android:key="startGameAtStartup" />
<!-- CheckBoxPreference
android:title="Save Game on Exit"
android:defaultValue="true"
android:summary="Saves the game automatically when exiting the app."
android:key="saveGameAtExit" /-->
</PreferenceCategory>
<!-- PreferenceCategory
android:title="Game Settings">
<CheckBoxPreference
android:title="Ask What Variant to Play"
android:defaultValue="true"
android:summary="Asks what variant of checkers you want to play, for each new game."
android:key="askVariantToPlay" />
<ListPreference
android:title="Type of Checkers Game"
android:summary="Should the app automatically start a new game."
android:defaultValue="American/Standard"
android:entries="@array/checkers_variants"
android:entryValues="@array/checkers_variants"
android:key="checkersVariant" />
</PreferenceCategory -->
</PreferenceScreen>

View File

@ -1,42 +0,0 @@
== What is justCheckers? ==
justCheckers is an open source advanced checkers game built using Java. The aim
of the project is to create a checkers game that:
* handles skins and themes
* handles multimedia
* allows for network games
* contains a powerful yet fun computer opponent
* simplifies managing on-line checkers tournaments
* handles different checker rules
Project homepage: http://justcheckers.sourceforge.net/
== Current Developers ==
* Dorian Pula
** Founder, lead developer, project management, documentation & core programming.
== Past Developers ==
* Chris Bellini
** Game engine data objects, XML settings & project management.
** Versions 0.0-0.1
* Daniel D'Alimonte (skwirl)
** Code clean-up, refactoring, documentation & file releases.
** Versions 0.0-0.1
* Ross Etchells
** Game engine logic and progressing.
** Versions 0.0-0.1
* Rras Lekone
** Console UI (jCurses)
** Versions 0.0
* Brinick Simmons
** Core programming, XML settings and processing.
** Versions 0.0-0.1
== Inspiration ==
* Nick Nolfi
** Creator of the Chubby Checkers project and assignment.
** Inspiration for Civilization Checkers and justCheckers.

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">justCheckers</string>
<string name="app_version">0.2-alpha</string>
<string name="project_website">http://justcheckers.org/</string>
<string-array name="checkers_variants">
<item>American/Standard</item>
<item>European</item>
<item>Canadian</item>
</string-array>
</resources>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="caption_about_us">About Us</string>
<string name="caption_license">License</string>
<string name="caption_play_checkers">Play Checkers</string>
<string name="caption_settings">Settings</string>
<string name="caption_visit_us">Visit Our Website</string>
<string name="caption_quit">Quit</string>
</resources>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="template_capture_amounts">x0</string>
<string name="template_current_player">Current Player</string>
<string name="template_opposing_player">Opposing Player</string>
</resources>

View File

@ -1,81 +0,0 @@
/*****************************************************************************
GameActivity.java - The activity that handles the actual checkers games.
*****************************************************************************
*****************************************************************************
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.android;
import org.justcheckers.game.Game;
import org.justcheckers.game.Rulebook;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
public class GameActivity extends Activity implements OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Setup the user interface for the main menu.
// Weirdness in orientation values in Galaxy Tab.
// http://www.ceveni.com/2009/08/how-to-get-screen-orientation-in.html
int screenOrientation =
this.getWindowManager().getDefaultDisplay().getOrientation();
//TODO: Cleaner per device implementation. Developed on Samsung Galaxy S Vibrant.
if (screenOrientation == 1) {
// Counter-clockwise landscape
this.setContentView(R.layout.game_screen_landscape);
} else if (screenOrientation == 3) {
// Clockwise landscape
this.setContentView(R.layout.game_screen_landscape);
} else if (screenOrientation == 0) {
// Portrait for Samsung Galaxy devices.
this.setContentView(R.layout.game_screen_portrait);
}
}
public void onClick(View view) {
//TODO: Stub
}
/**
* Starts a new game with the specified rulebook.
*
* @param rules
* The rules for the new game.
*/
public static void startGame(Rulebook rules) {
Game currentGame = new Game(rules.getCheckersVariant());
/* Instead of specialized UI commands, just a single method
that updates the UI with the current state of the game. */
// ui.setCurrentGame(currentGame);
//
// // Current until different game types are added.
// ui.clearBoard();
// ui.placePieces();
}
}

View File

@ -1,104 +0,0 @@
/*****************************************************************************
InfoActivity.java - The activity that provides built-in 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.android;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.justcheckers.common.GlobalConstants;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class InfoActivity extends Activity {
private int flagInformationToDisplay;
//TODO: Clean this up into something more modularized.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Setup the user interface for the main menu.
this.setContentView(R.layout.info_screen);
// Figure out which text to load. The default
if (savedInstanceState != null) {
this.flagInformationToDisplay =
savedInstanceState.getInt(GlobalConstants.EXTRA_INFORMATION_DISPLAY_FLAG);
} else {
Bundle extras = this.getIntent().getExtras();
if (extras != null) {
this.flagInformationToDisplay =
extras.getInt(GlobalConstants.EXTRA_INFORMATION_DISPLAY_FLAG);
}
}
// Load the right text.
int rawInfoRes = 0;
if (this.flagInformationToDisplay == GlobalConstants.FLAG_INFORMATION_DISPLAY_ABOUT_US) {
rawInfoRes = R.raw.readme;
} else if (this.flagInformationToDisplay == GlobalConstants.FLAG_INFORMATION_DISPLAY_LICENSE) {
rawInfoRes = R.raw.gpl_3_license;
} else {
rawInfoRes = R.raw.readme;
}
// Read the raw document into a string.
InputStream docInfoStream = this.getResources().openRawResource(rawInfoRes);
BufferedReader reader = new BufferedReader(new InputStreamReader(docInfoStream));
String result = "Text here";
try {
// Gather all the data.
StringBuilder buildDoc = new StringBuilder();
String docLine = reader.readLine();
while (docLine != null) {
buildDoc.append(docLine + "\n");
docLine = reader.readLine();
}
result = buildDoc.toString();
} catch (IOException e) {
Log.e("InfoActivity", "Input error: " + e.getMessage());
}
TextView infoText = (TextView) this.findViewById(R.id.info_text);
infoText.setText(result);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(GlobalConstants.EXTRA_INFORMATION_DISPLAY_FLAG,
this.flagInformationToDisplay);
}
}

View File

@ -1,140 +0,0 @@
/*****************************************************************************
MenuActivity.java - The activity that provides the main menu for the app.
*****************************************************************************
*****************************************************************************
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.android;
import org.justcheckers.common.GlobalConstants;
import org.justcheckers.common.LoggingAndStatistics;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MenuActivity extends Activity implements OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Setup the user interface for the main menu.
this.setContentView(R.layout.main_menu);
// Link up all the UI elements with their listeners.
Button menuButton = (Button) this.findViewById(R.id.game_button);
menuButton.setOnClickListener(this);
menuButton = (Button) this.findViewById(R.id.game_button);
menuButton.setOnClickListener(this);
menuButton = (Button) this.findViewById(R.id.website_button);
menuButton.setOnClickListener(this);
menuButton = (Button) this.findViewById(R.id.settings_button);
menuButton.setOnClickListener(this);
menuButton = (Button) this.findViewById(R.id.about_us_button);
menuButton.setOnClickListener(this);
menuButton = (Button) this.findViewById(R.id.license_button);
menuButton.setOnClickListener(this);
menuButton = (Button) this.findViewById(R.id.quit_button);
menuButton.setOnClickListener(this);
// TODO: Move logging info in a better place.
// LoggingAndStatistics.logApplicationInfo(this);
LoggingAndStatistics.logDeviceAndSystemInfo();
}
public void onClick(View view) {
// Determine which view fired off this event.
switch (view.getId()) {
case R.id.game_button:
this.startGame();
break;
case R.id.website_button:
this.launchWebsite();
break;
case R.id.settings_button:
this.displaySettings();
break;
case R.id.about_us_button:
this.displayInfo(GlobalConstants.FLAG_INFORMATION_DISPLAY_ABOUT_US);
break;
case R.id.license_button:
this.displayInfo(GlobalConstants.FLAG_INFORMATION_DISPLAY_LICENSE);
break;
case R.id.quit_button:
this.quitApp();
break;
};
}
/**
* Quits the application.
*/
private void quitApp() {
this.finish();
}
/**
* Displays an information screen.
*/
private void displayInfo(int infoToDisplay) {
// Validate info.
if ((infoToDisplay != GlobalConstants.FLAG_INFORMATION_DISPLAY_ABOUT_US) &&
(infoToDisplay != GlobalConstants.FLAG_INFORMATION_DISPLAY_LICENSE)) {
infoToDisplay = GlobalConstants.FLAG_INFORMATION_DISPLAY_ABOUT_US;
}
Intent launchDisplay = new Intent(this, InfoActivity.class);
launchDisplay.putExtra(GlobalConstants.EXTRA_INFORMATION_DISPLAY_FLAG,
infoToDisplay);
startActivity(launchDisplay);
}
/**
* Displays the settings for the application.
*/
private void displaySettings() {
Intent launchDisplay = new Intent(this, SettingsActivity.class);
startActivity(launchDisplay);
}
/**
* Starts an external browser to visit the project's website.
*/
private void launchWebsite() {
String url = this.getString(R.string.project_website);
Intent launcher = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(launcher);
}
/**
* Starts a new game or continues an existing one.
*/
private void startGame() {
Intent launchDisplay = new Intent(this, GameActivity.class);
startActivity(launchDisplay);
}
}

View File

@ -1,40 +0,0 @@
/*****************************************************************************
SettingsActivity.java - The activity for adjustings settings in the app.
*****************************************************************************
*****************************************************************************
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.android;
import android.graphics.Color;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class SettingsActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.addPreferencesFromResource(R.layout.settings_screen);
this.getListView().setBackgroundResource(R.drawable.backdrop);
this.getListView().setCacheColorHint(Color.TRANSPARENT);
}
}

62
assets/credits.md Normal file
View File

@ -0,0 +1,62 @@
What is justCheckers?
---------------------
justCheckers is an advanced libre source checkers game. The project's aim is to create a checkers game that:
* handles skins and themes
* handles multimedia
* allows for network games
* contains a powerful yet fun computer opponent
* simplifies managing on-line checkers tournaments
* handles different checker rules
This project is powered by Python 2 + PySide (Qt 4)
[justCheckers homepage - http://justcheckers.org/](http://justcheckers.org/)
Developers
==========
Current
-------
**Dorian Pula**
- Founder, lead developer, project management, documentation & core programming.
Past
----
**Chris Bellini**
- Game engine data objects, XML settings & project management.
- Versions 0.0-0.1
**Daniel D'Alimonte (skwirl)**
- Code clean-up, refactoring, documentation & file releases.
- Inspiration for move to PySide
- Versions 0.0-0.1
**Ross Etchells**
- Game engine logic and progressing.
- Versions 0.0-0.1
**Rras Lekone**
- Console UI (jCurses)
- Versions 0.0
**Brinick Simmons**
- Core programming, XML settings and processing.
- Versions 0.0-0.1
Special Thanks
--------------
**Nick Nolfi**
- Creator of the Chubby Checkers project and assignment.
- Inspiration for Civilization Checkers and justCheckers.

BIN
assets/ping.wav Normal file

Binary file not shown.

View File

@ -1,23 +0,0 @@
/*
Modular Gradle Build for justCheckers
---------------------------------------------
Author: Dorian Pula (dorian.pula@amber-penguin-software.ca)
License: AGPL v3.
Gradle docs:
http://www.gradle.org/docs/current/userguide/userguide_single.html
Gradle Android build docs:
https://sites.google.com/a/android.com/tools/tech-docs/new-build-system
*/
apply plugin: 'java'
sourceCompatibility = 1.6
targetCompatibility = 1.6
// Description of the project
description = 'justcheckers'
version = '0.3'
// TODO Add in extra targets for project setup or a simplified Gradle build API.

239
buildozer.spec Normal file
View File

@ -0,0 +1,239 @@
[app]
# (str) Title of your application
title = justCheckers
# (str) Package name
package.name = justcheckers
# (str) Package domain (needed for android/ios packaging)
package.domain = org.justcheckers
# (str) Source code where the main.py live
source.dir = .
# (list) Source files to include (let empty to include all the files)
source.include_exts = py,png,jpg,kv,atlas,md
# (list) List of inclusions using pattern matching
#source.include_patterns = assets/*,images/*.png
# (list) Source files to exclude (let empty to not exclude anything)
#source.exclude_exts = spec
# (list) List of directory to exclude (let empty to not exclude anything)
#source.exclude_dirs = tests, bin
# (list) List of exclusions using pattern matching
#source.exclude_patterns = license,images/*/*.jpg
# (str) Application versioning (method 1)
version = 0.3.0
# (str) Application versioning (method 2)
# version.regex = __version__ = ['"](.*)['"]
# version.filename = %(source.dir)s/main.py
# (list) Application requirements
# comma seperated e.g. requirements = sqlite3,kivy
requirements = kivy,hostpython2,docutils
# (str) Custom source folders for requirements
# Sets custom source for any requirements with recipes
# requirements.source.kivy = ../../kivy
# (list) Garden requirements
#garden_requirements =
# (str) Presplash of the application
presplash.filename = %(source.dir)s/images/splash.jpg
# (str) Icon of the application
icon.filename = %(source.dir)s/images/icon.png
# (str) Supported orientation (one of landscape, portrait or all)
orientation = landscape
# (list) List of service to declare
#services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY
#
# OSX Specific
#
#
# author = © Copyright Info
#
# Android specific
#
# (bool) Indicate if the application should be fullscreen or not
fullscreen = 1
# (list) Permissions
android.permissions = INTERNET
# (int) Android API to use
android.api = 19
# (int) Minimum API required
android.minapi = 9
# (int) Android SDK version to use
android.sdk = 20
# (str) Android NDK version to use
android.ndk = 9c
# (bool) Use --private data storage (True) or --dir public storage (False)
android.private_storage = True
# (str) Android NDK directory (if empty, it will be automatically downloaded.)
#android.ndk_path =
# (str) Android SDK directory (if empty, it will be automatically downloaded.)
#android.sdk_path =
# (str) ANT directory (if empty, it will be automatically downloaded.)
#android.ant_path =
# (str) python-for-android git clone directory (if empty, it will be automatically cloned from github)
#android.p4a_dir =
# (str) The directory in which python-for-android should look for your own build recipes (if any)
#p4a.local_recipes =
# (str) Filename to the hook for p4a
#p4a.hook =
# (list) python-for-android whitelist
#android.p4a_whitelist =
# (bool) If True, then skip trying to update the Android sdk
# This can be useful to avoid excess Internet downloads or save time
# when an update is due and you just want to test/build your package
# android.skip_update = False
# (str) Bootstrap to use for android builds (android_new only)
# android.bootstrap = sdl2
# (str) Android entry point, default is ok for Kivy-based app
#android.entrypoint = org.renpy.android.PythonActivity
# (list) List of Java .jar files to add to the libs so that pyjnius can access
# their classes. Don't add jars that you do not need, since extra jars can slow
# down the build process. Allows wildcards matching, for example:
# OUYA-ODK/libs/*.jar
#android.add_jars = foo.jar,bar.jar,path/to/more/*.jar
# (list) List of Java files to add to the android project (can be java or a
# directory containing the files)
#android.add_src =
# (str) python-for-android branch to use, if not master, useful to try
# not yet merged features.
#android.branch = master
# (str) OUYA Console category. Should be one of GAME or APP
# If you leave this blank, OUYA support will not be enabled
#android.ouya.category = GAME
# (str) Filename of OUYA Console icon. It must be a 732x412 png image.
#android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png
# (str) XML file to include as an intent filters in <activity> tag
#android.manifest.intent_filters =
# (list) Android additionnal libraries to copy into libs/armeabi
#android.add_libs_armeabi = libs/android/*.so
#android.add_libs_armeabi_v7a = libs/android-v7/*.so
#android.add_libs_x86 = libs/android-x86/*.so
#android.add_libs_mips = libs/android-mips/*.so
# (bool) Indicate whether the screen should stay on
# Don't forget to add the WAKE_LOCK permission if you set this to True
#android.wakelock = False
# (list) Android application meta-data to set (key=value format)
#android.meta_data =
# (list) Android library project to add (will be added in the
# project.properties automatically.)
#android.library_references =
# (str) Android logcat filters to use
#android.logcat_filters = *:S python:D
# (bool) Copy library instead of making a libpymodules.so
#android.copy_libs = 1
# (str) The Android arch to build for, choices: armeabi-v7a, arm64-v8a, x86
android.arch = armeabi-v7a
#
# iOS specific
#
# (str) Path to a custom kivy-ios folder
#ios.kivy_ios_dir = ../kivy-ios
# (str) Name of the certificate to use for signing the debug version
# Get a list of available identities: buildozer ios list_identities
#ios.codesign.debug = "iPhone Developer: <lastname> <firstname> (<hexstring>)"
# (str) Name of the certificate to use for signing the release version
#ios.codesign.release = %(ios.codesign.debug)s
[buildozer]
# (int) Log level (0 = error only, 1 = info, 2 = debug (with command output))
log_level = 2
# (int) Display warning if buildozer is run as root (0 = False, 1 = True)
warn_on_root = 1
# (str) Path to build artifact storage, absolute or relative to spec file
# build_dir = ./.buildozer
# (str) Path to build output (i.e. .apk, .ipa) storage
# bin_dir = ./bin
# -----------------------------------------------------------------------------
# List as sections
#
# You can define all the "list" as [section:key].
# Each line will be considered as a option to the list.
# Let's take [app] / source.exclude_patterns.
# Instead of doing:
#
#[app]
#source.exclude_patterns = license,data/audio/*.wav,data/images/original/*
#
# This can be translated into:
#
#[app:source.exclude_patterns]
#license
#data/audio/*.wav
#data/images/original/*
#
# -----------------------------------------------------------------------------
# Profiles
#
# You can extend section / key with a profile
# For example, you want to deploy a demo version of your application without
# HD content. You could first change the title to add "(demo)" in the name
# and extend the excluded directories to remove the HD content.
#
#[app@demo]
#title = My Application (demo)
#
#[app:source.exclude_patterns@demo]
#images/hd/*
#
# Then, invoke the command line with the "demo" profile:
#
#buildozer --profile demo android debug

View File

@ -1,32 +0,0 @@
/*
Gradle Build for justCheckers - Console
---------------------------------------
Author: Dorian Pula (dorian.pula@amber-penguin-software.ca)
License: AGPL v3.
Gradle docs:
http://www.gradle.org/docs/current/userguide/userguide_single.html
*/
apply plugin: 'java'
sourceCompatibility = 1.6
targetCompatibility = 1.6
// Description of the project
description = 'justcheckers-console'
version = '0.3'
// TODO Add in build for the terminal client.
// TODO Base of justcheckers-core
// TODO Look into potential terminal libraries...
/*
Ideas: http://stackoverflow.com/questions/1321308/whats-the-best-way-to-get-text-user-interfaces-ncurses-like-functionality-in
- Laterna: https://code.google.com/p/lanterna/
- jCurses: http://sourceforge.net/projects/javacurses/
- TUIAWT: http://bmsi.com/tuipeer/
- CHARVA: http://www.pitman.co.za/projects/charva/index.html
*/

View File

@ -1,61 +0,0 @@
/*
Gradle Build for justCheckers - Core
---------------------------------------------
Author: Dorian Pula (dorian.pula@amber-penguin-software.ca)
License: AGPL v3.
Gradle docs:
http://www.gradle.org/docs/current/userguide/userguide_single.html
*/
apply plugin: 'java'
sourceCompatibility = 1.6
targetCompatibility = 1.6
// Description of the project
description = 'justcheckers-core'
version = '0.3'
project.ext {
appName = 'justcheckers-core'
}
// Setup build script repositories starting with Maven repositories
repositories {
maven {
url 'http://repo1.maven.org/maven2'
}
}
// Dependency management
dependencies {
compile 'jdom:jdom:0.7'
compile 'org.slf4j:slf4j-api:1.7.5'
testCompile 'org.testng:testng:6.8'
}
// At the end of day we just need a JAR and a WAR.
ext.sharedManifest = manifest {
attributes(
'App-Name' : project.appName,
'App-Version' : version,
'Build-User' : System.properties['user.name'],
'Build-Time' : new Date().format('yyyy-MMMM-dd HH:mm:ss'),
'Build-OS' : System.properties['os.name'] + ' - version ' + System.properties['os.version'],
'Build-Sys' : System.properties['os.arch'],
'Java-Version' : System.properties['java.version'],
'Java-Vendor' : System.properties['java.vendor'],
'Java-VM' :
System.properties['java.vm.vendor'] + ' ' + System.properties['java.vm.name'] + ' v'
+ System.properties['java.vm.version'])
}
// Build the JAR.
jar {
enabled = true
includeEmptyDirs = false
manifest = sharedManifest
}

View File

@ -1,41 +0,0 @@
/*****************************************************************************
GlobalConstants.java - Constants for the entire application.
*****************************************************************************
*****************************************************************************
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.common;
/**
* Organizational class to keep all the constants in.
* @author Dorian Pula
*
*/
public class GlobalConstants {
/** Flag for the information screen to display a "About Us". */
public final static int FLAG_INFORMATION_DISPLAY_ABOUT_US = 0;
/** Flag for the information screen to display the license of the app. */
public final static int FLAG_INFORMATION_DISPLAY_LICENSE = 1;
/**
* The extras key that contains the information screens needs to display
* the right information.
*/
public final static String EXTRA_INFORMATION_DISPLAY_FLAG = "info-display";
}

View File

@ -1,74 +0,0 @@
/*****************************************************************************
GameLoop.java - Main controlling class for the justCheckers 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.common;
// TODO Resolve this with separation of various platform setups...
//import org.justcheckers.android.R;
//
//import android.app.Activity;
//import android.os.Build;
//import android.util.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Functions for logging errors and gathering statistics.
*
* @author Dorian Pula
*/
public abstract class LoggingAndStatistics {
/**
* Logs information about the program. Displays the game's header and
* relevant system properties at runtime.
*/
public static void logApplicationInfo(String gameVersion, String gameWebsite) {
// TODO Fix
// String gameVersion = caller.getString(R.string.app_version);
// String gameWebsite = caller.getString(R.string.project_website);
String appInfo = "justCheckers -- Version:" + gameVersion
+ " - Website: " + gameWebsite;
// TODO Clean up...
Logger log = LoggerFactory.getLogger(LoggingAndStatistics.class);
log.info("ApplInfo", appInfo);
}
/**
* Logs information about the device and system, the app is
* running on.
*/
public static void logDeviceAndSystemInfo() {
// System properties.
// String sysList = "SDK version: " + Build.VERSION.RELEASE
// + " - API: " + Build.VERSION.SDK_INT
// + " - Device: " + Build.MANUFACTURER + " " + Build.MODEL;
// TODO Fix
String sysList = "FIXME";
Logger log = LoggerFactory.getLogger(LoggingAndStatistics.class);
log.info("DevSysInfo", sysList);
}
}

View File

@ -1,497 +0,0 @@
/*****************************************************************************
Board.java -- Container for the state of the board of a 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;
/**
* Container for the state of the checker board during a game.
*
* The size of the board is defined by the number of squares along one side,
* since all checker boards are square. The board coordinate system has both
* horizontal and vertical numeric components ranging from 0 to boardSize-1.
* Depicted on-screen, the horizontal component extends to the right and the
* vertical component extends downwards, making the upper left square (0, 0) and
* the lower right square (boardSize-1, boardSize-1).
*
* <b>Navigating through the Board</b> Internally, the checker board is
* organized as a two-dimensional array. So when iterating through the board,
* you first specify the vertical component and then the horizontal component.
* Another way of thinking about is first specifying which row you want to look
* at from top to bottom. Then you specify how across the row you are looking at
* from left to right.
*
* <b>Players Places</b> The light player (the starting player) starts at the
* top of the board. The dark player starts at the bottom of the board.
*
* @author Dorian Pula
* @author Ross Etchells
*/
public class Board {
/** Constant representing a dark king. */
public static final int DARK_KING = 4;
/** Constant representing a dark single man. */
public static final int DARK_PAWN = 3;
/** Constant representing an empty space. */
public static final int EMPTY_SPACE = 0;
// -- Constants ------------------------------------------------------------
/**
* Constant representing an illegal square. That is a white square in
* checkers.
*/
public static final int ILLEGAL_SPACE = -1;
/** Constant representing a light king. */
public static final int LIGHT_KING = 2;
/** Constant representing a light single man. */
public static final int LIGHT_PAWN = 1;
// -- Object Fields --------------------------------------------------------
/** Is the board mirrored or a regular checker board. */
private final boolean amIMirrored;
/**
* Holds the positions of the pieces on the board.
*/
private final int[][] board;
/** The size of the board. */
private final int boardSize;
/** A reference to the rules being used. */
private final Rulebook myRules;
// -- Constructors ---------------------------------------------------------
/**
* Creates a new board for checkers.
*
* @param rules
* The rules for this board.
*/
public Board(Rulebook rules) {
this.myRules = rules;
final int size = this.myRules.getBoardSize();
this.board = new int[size][size];
this.boardSize = size;
this.amIMirrored = this.myRules.isBoardMirrored();
}
// -- Public Methods (Setting Up the Board) --------------------------------
/**
* Clears the board of pieces. Creates a brand new empty board already laid
* out by the rules (regular or mirrored).
*/
public void clearBoard() {
for (int row = 0; this.boardSize > row; row++) {
for (int col = 0; this.boardSize > col; col++) {
// Mirrored has opposite setup to a regular board.
if (row % 2 == 0 && col % 2 == 0) {
if (this.amIMirrored) {
this.board[row][col] = Board.ILLEGAL_SPACE;
} else {
this.board[row][col] = Board.EMPTY_SPACE;
}
} else if (row % 2 == 0 && col % 2 == 1) {
if (this.amIMirrored) {
this.board[row][col] = Board.EMPTY_SPACE;
} else {
this.board[row][col] = Board.ILLEGAL_SPACE;
}
} else if (row % 2 == 1 && col % 2 == 0) {
if (this.amIMirrored) {
this.board[row][col] = Board.EMPTY_SPACE;
} else {
this.board[row][col] = Board.ILLEGAL_SPACE;
}
} else {
if (this.amIMirrored) {
this.board[row][col] = Board.ILLEGAL_SPACE;
} else {
this.board[row][col] = Board.EMPTY_SPACE;
}
}
}
}
}
// -- Get/Set Methods ------------------------------------------------------
/**
* Gets the size of the board. The board size is measured as the number of
* squares down one side of the board.
*
* @return The size of the board.
*/
public int getBoardSize() {
return this.boardSize;
}
/**
* Provides a reference to a 2 dimensional array representation of the
* current board state. This is for use by the user interface. Each
* dimension of the array extends from 0 to boardSize - 1. Note that the
* referenced array is a clone of the internal board representation. Changes
* made to the array will not affect the board state.
*
* @return A 2 dimensional array representing the current state of the
* board.
*/
public int[][] getBoardState() {
final int[][] repBoard = new int[this.boardSize][this.boardSize];
System.arraycopy(this.board, 0, repBoard, 0, this.boardSize);
return repBoard;
}
/**
* Determines whether the piece at board coordinate (row, col) is dark. If
* the coordinates do not exist on the board or are empty, this method will
* return false.
*
* @param row
* The row of the square.
* @param col
* The column of the square.
* @return True if the piece at the specified coordinate is dark. False if
* otherwise.
*/
public boolean isDark(int row, int col) {
if (row >= 0 && row < this.boardSize && col >= 0
&& col < this.boardSize) {
return this.board[row][col] == Board.DARK_KING
|| this.board[row][col] == Board.DARK_PAWN;
}
return false;
}
/**
* Determines whether the piece at board coordinate (row, col) is empty. If
* the coordinates do not exist on the board or is illegal, this method will
* return false.
*
* @param row
* The row of the square.
* @param col
* The column of the square.
* @return True if the piece at the specified coordinate is empty. False if
* otherwise.
*/
public boolean isEmpty(int row, int col) {
if (row >= 0 && row < this.boardSize && col >= 0
&& col < this.boardSize) {
return this.board[row][col] == Board.EMPTY_SPACE;
}
return false;
}
/**
* Determines whether the board coordinate (x, y) is used in the game. In
* most cases, all light spaces on the board will be considered illegal.
* Also, any coordinate which does not exist is also considered illegal.
*
* @param row
* The row of the square.
* @param col
* The column of the square.
* @return True if the specified coordinate is nonexistent or unused in the
* current rules. False if otherwise.
*/
public boolean isIllegalSpace(int row, int col) {
if (row >= 0 && row < this.boardSize && col >= 0
&& col < this.boardSize) {
return this.board[row][col] == Board.ILLEGAL_SPACE;
}
return false;
}
/**
* Determines whether the piece at board coordinate (row, col) is a king. If
* the coordinates do not exist on the board or are empty, this method will
* return false.
*
* @param row
* The row of the square.
* @param col
* The column of the square.
* @return True if the piece at the specified coordinate is a king. False if
* otherwise.
*/
public boolean isKing(int row, int col) {
if (row >= 0 && row < this.boardSize && col >= 0
&& col < this.boardSize) {
return this.board[row][col] == Board.LIGHT_KING
|| this.board[row][col] == Board.DARK_KING;
}
return false;
}
/**
* Returns if a position specified is legal. Returns true if the position is
* on the board, and if the space is not an illegal white space. Returns
* false otherwise.
*
* @param row
* The row coordinate of the position.
* @param col
* The column coordinate of the position.
* @return Returns true if the position is a legal playing position.
*/
public boolean isLegalPosition(int row, int col) {
return row >= 0 && row < this.boardSize && col >= 0
&& col < this.boardSize && !this.isIllegalSpace(row, col);
}
/**
* Determines whether the piece at board coordinate (row, col) is light. If
* the coordinates do not exist on the board or are empty, this method will
* return false.
*
* @param row
* The row of the square.
* @param col
* The column of the square.
* @return True if the piece at the specified coordinate is light. False if
* otherwise.
*/
public boolean isLight(int row, int col) {
if (row >= 0 && row < this.boardSize && col >= 0
&& col < this.boardSize) {
return this.board[row][col] == Board.LIGHT_KING
|| this.board[row][col] == Board.LIGHT_PAWN;
}
return false;
}
/**
* Determines whether the piece at board coordinate (row, col) is a pawn. If
* the coordinates do not exist on the board or are empty, this method will
* return false.
*
* @param row
* The row of the square.
* @param col
* The column of the square.
* @return True if the piece at the specified coordinate is a pawn. False if
* otherwise.
*/
public boolean isPawn(int row, int col) {
if (row >= 0 && row < this.boardSize && col >= 0
&& col < this.boardSize) {
return this.board[row][col] == Board.LIGHT_PAWN
|| this.board[row][col] == Board.DARK_PAWN;
}
return false;
}
// -- Board Updating Methods -----------------------------------------------
/**
* Moves a pieces from one location to another. This method should be called
* from the Game using this Board. This method does not check for rule
* validity but does check for illegal white spaces. Also checks that the
* destination position is empty.
*
* @param sourceRow
* The row from where the piece is moving from.
* @param sourceCol
* The column from where the piece is moving from.
* @param targetRow
* The row to where the piece is moving to.
* @param targetCol
* The column to where the piece is moving to.
*/
protected void movePiece(int sourceRow, int sourceCol, int targetRow,
int targetCol) {
if (this.isLegalPosition(sourceRow, sourceCol)
&& this.isLegalPosition(targetRow, targetCol)
&& this.board[targetRow][targetCol] == Board.EMPTY_SPACE) {
final int piece = this.board[sourceRow][sourceCol];
this.board[targetRow][targetCol] = piece;
this.board[sourceRow][sourceCol] = Board.EMPTY_SPACE;
}
}
/**
* Removes a pieces from the specified location. This method should be
* called from the Game using this Board. This method does not check for
* rule validity but does check for illegal white spaces.
*
* @param row
* The row where the piece is to be removed from.
* @param col
* The column where the piece is to be removed from.
*/
protected void removePiece(int row, int col) {
if (this.isLegalPosition(row, col)) {
this.board[row][col] = Board.EMPTY_SPACE;
}
}
/**
* Setups the board for a new game. There are three different setups for the
* three different types of boards:
*
* <table>
* <tr>
* <b>
* <td>Name</td>
* <td>Size</td>
* <td>Number of Pieces Per Player</td>
* <td>Number of Rows Per Player</td>
* </b>
* </tr>
* <tr>
* <td>Standard</td>
* <td>8 x 8</td>
* <td>12</td>
* <td>3</td>
* </tr>
* <tr>
* <td>International</td>
* <td>10 x 10</td>
* <td>20</td>
* <td>4</td>
* </tr>
* <tr>
* <td>Canadian</td>
* <td>12 x 12</td>
* <td>30</td>
* <td>5</td>
* </tr>
* </table>
*
* The columns containing the players' tokens alternate between columns. The
* dark player traditionally takes the first few upper rows (0-3). The light
* player takes the last of the lower rows (5-7, 6-9 or 7-11).
*
* Note that the suicide checkers variant has a completely different setup,
* and has a setup function of its own: setupNewSuicideGame().
*/
public void setupNewGame() {
this.clearBoard();
if (this.myRules.getCheckersVariant() == Rulebook.SUICIDE_CHECKERS) {
this.setupNewSuicideGame();
} else {
// Used to decide which rows to fill up.
int darkPlayerBottomRow;
int lightPlayerTopRow;
// Figure out the size of the board.
if (this.boardSize == Rulebook.INTERNATIONAL_BOARD_SIZE) {
darkPlayerBottomRow = 3;
lightPlayerTopRow = 6;
} else if (this.boardSize == Rulebook.CANADIAN_BOARD_SIZE) {
darkPlayerBottomRow = 3;
lightPlayerTopRow = 7;
} else { // Default board is 8x8 Standard size.
darkPlayerBottomRow = 2;
lightPlayerTopRow = 5;
}
// Go through the board and set it up.
for (int row = 0; row < this.boardSize; row++) {
for (int col = 0; col < this.boardSize; col++) {
if (row <= darkPlayerBottomRow
&& this.board[row][col] == Board.EMPTY_SPACE) {
this.board[row][col] = Board.DARK_PAWN;
} else if (row >= lightPlayerTopRow
&& this.board[row][col] == Board.EMPTY_SPACE) {
this.board[row][col] = Board.LIGHT_PAWN;
}
}
}
}
}
/**
* Setups a checker board according to the suicide "French" rules.
*/
private void setupNewSuicideGame() {
// TODO: Implement the suicide game setup.
}
// -- Private (Implementation) Methods -------------------------------------
/**
* Returns a string to represent the board state. This string is formatted
* for use as a simple board display in the command window.
*
* <b>Legend</b> ## - White space which the piece can not move on to. __ -
* An empty space. LP - A light pawn. LK - A light king. DP - A dark pawn.
* DK - A dark king.
*
* @return A string representing the current board state.
*/
@Override
public String toString() {
// Prepare for output with a nice looking to banner.
String output = " ";
for (int i = 0; i < this.boardSize; i++) {
if (i < 9) {
output = output + " " + (i + 1);
} else {
output = output + " " + (i + 1);
}
}
output = output + "\n\n";
// Go row by row, printing out the row number and the board's state.
for (int row = 0; row < this.boardSize; row++) {
if (row < 9) {
output = output + " " + (row + 1);
} else {
output = output + " " + (row + 1);
}
// Get current row's state.
for (int col = 0; col < this.boardSize; col++) {
switch (this.board[row][col]) {
case Board.ILLEGAL_SPACE:
output = output + "## ";
break;
case Board.EMPTY_SPACE:
output = output + "__ ";
break;
case Board.LIGHT_PAWN:
output = output + "LP ";
break;
case Board.LIGHT_KING:
output = output + "LK ";
break;
case Board.DARK_PAWN:
output = output + "DP ";
break;
case Board.DARK_KING:
output = output + "DK ";
break;
}
}
output = output + "\n";
}
return output;
}
}

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,295 +0,0 @@
/*****************************************************************************
GameEngine.java -- Logic engine for manipulating the state of a 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;
/**
* @author dpula
*
*/
public class GameEngine {
// TODO: Add a constructor for games already in progress.
// -- Game methods --------------------------------------------------------
private static boolean canJump(Game game, int sourceRow, int sourceCol, int targetRow,
int targetCol) {
// TODO: Implement me.
return false;
}
/**
* Returns if a piece can or cannot move. This move maybe either be a move
* 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
* 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.
*
* @param sourceRow
* The row from where the piece is moving from.
* @param sourceCol
* The column from where the piece is moving from.
* @param targetRow
* The row to where the piece is moving to.
* @param targetCol
* The column to where the piece is moving to.
* @return True if the piece can move. False if the piece can not move.
*/
public static boolean canMove(Game game, int sourceRow, int sourceCol, int targetRow,
int targetCol) {
// A few things to figure out priorities in moving a piece.
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?
// Sanity check.
if (game.getGameBoard().isLegalPosition(sourceRow, sourceCol)
&& game.getGameBoard().isLegalPosition(targetRow, targetCol)) {
realPositions = true;
}
// Is there a jump in progress?
if (realPositions && game.getJumpInProgress() != null) {
// Only allow the piece in movement to be moved.
if (sourceRow == game.getJumpInProgress().getY()
&& sourceCol == game.getJumpInProgress().getX()) {
legalMove = canJump(game, sourceRow, sourceCol, targetRow,
targetCol);
isJump = true;
}
} else if (realPositions) {
// Go with the regular flow, jumps first then "slides".
isJump = canPlayerJump(game);
if (isJump) {
legalMove = canJump(game, sourceRow, sourceCol, targetRow,
targetCol);
} else {
legalMove = canSlide(game, sourceRow, sourceCol, targetRow,
targetCol);
}
}
return legalMove;
}
private static boolean canPlayerJump(Game game) {
// TODO: Implement me.
return false;
}
private static boolean canSlide(Game game, int sourceRow, int sourceCol, int targetRow,
int targetCol) {
boolean legalMove = true;
boolean mustJump = canPlayerJump(game);
// Is the move even on the board?
legalMove = game.getGameBoard().isLegalPosition(sourceRow, sourceCol)
&& game.getGameBoard().isLegalPosition(targetRow, targetCol);
// See if the destination is even empty.
if (legalMove) {
legalMove = game.getGameBoard().isEmpty(targetRow, targetCol);
}
// If yes, then look if right pieces were chosen.
if (legalMove && !mustJump) {
if (game.isLightPlayerTurn()
&& game.getGameBoard().isLight(sourceRow, sourceCol)) {
// To deal with flying kings.
if (game.getGameBoard().isKing(sourceRow, sourceCol)
&& game.getGameRules().canKingsFly()) {
// FIXME: Fix this!
} else {
// if ((Math.abs(targetRow - sourceRow) == 1) && (Math.abs(targetRow - sourceRow) == 1)) {
// legalMove = false;
// }
}
// Is the path clear for that move?
} else if (!game.isLightPlayerTurn()
&& game.getGameBoard().isDark(sourceRow, sourceCol)) {
//TODO: Implement me, sometime.
} else {
legalMove = false;
}
}
return legalMove;
}
private static void checkForVictory(Game game) {
// TODO: Implement me.
}
/**
* 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
* used by the graphical user interface to determine if a piece can be moved
* either for sliding or jumping. The method is aware of whose turn is it to
* move.
*
* @param row
* The row coordinate of the piece to check.
* @param col
* The column coordinate of the piece to check.
* @return Returns true if the piece can slide or jump in this turn.
*/
public static boolean isMovablePiece(Game game, int row, int col) {
// Fields for determining of a piece is movable.
boolean moveUpLeft = true;
boolean moveUpRight = true;
boolean moveDownLeft = true;
boolean moveDownRight = true;
/*
* Checks first if the first colour of piece is being grabbed. Next if
* the piece is blocked by its own pieces. Next if the opponent has
* double blocked off the pieces. Also sanity checks if looking past the
* size of the board.
*/
if (game.isLightPlayerTurn() && game.getGameBoard().isLight(row, col)) { // Light
// player.
// Can piece move normally?
moveDownLeft = canSlide(game, row, col, row + 1, col - 1);
moveDownRight = canSlide(game, row, col, row + 1, col + 1);
if (game.getGameBoard().isKing(row, col)) {
moveUpLeft = canSlide(game, row, col, row - 1, col - 1);
moveUpRight = canSlide(game, row, col, row - 1, col + 1);
} else {
moveUpLeft = false;
moveUpRight = false;
}
// If no slides available try doing the same except for jumps.
if (!moveDownLeft) {
moveDownLeft = canJump(game, row, col, row + 2, col - 2);
} else if (!moveDownRight) {
moveDownRight = canJump(game, row, col, row + 2, col + 2);
} else if (game.getGameBoard().isKing(row, col)
|| game.getGameRules().canPawnsJumpBackwards()) {
if (!moveUpLeft) {
moveUpLeft = canJump(game, row, col, row - 2, col + 2);
} else if (!moveUpRight) {
moveUpRight = canJump(game, row, col, row - 2, col - 2);
}
}
return moveUpLeft || moveUpRight || moveDownLeft || moveDownRight;
} else if (game.isLightPlayerTurn() && game.getGameBoard().isDark(row, col)) { // Dark
// player
// Can piece move normally?
moveUpLeft = canSlide(game, row, col, row - 1, col - 1);
moveUpRight = canSlide(game, row, col, row - 1, col + 1);
if (game.getGameBoard().isKing(row, col)) {
moveDownLeft = canSlide(game, row, col, row + 1, col - 1);
moveDownRight = canSlide(game, row, col, row + 1, col + 1);
} else {
moveDownLeft = false;
moveDownRight = false;
}
// If no slides available try doing the same except for jumps.
if (!moveUpLeft) {
moveUpLeft = canJump(game, row, col, row - 2, col - 2);
} else if (!moveUpRight) {
moveUpRight = canJump(game, row, col, row - 2, col + 2);
} else if (game.getGameBoard().isKing(row, col)
|| game.getGameRules().canPawnsJumpBackwards()) {
if (!moveDownLeft) {
moveDownLeft = canJump(game, row, col, row + 2, col + 2);
} else if (!moveDownRight) {
moveDownRight = canJump(game, row, col, row + 2, col - 2);
}
}
return moveUpLeft || moveUpRight || moveDownLeft || moveDownRight;
} else {
return false; // A wrong coloured piece.
}
}
/**
* Moves a pieces from one location to another. This move maybe either be a
* move or a jump. This method is called by a user interface when a user
* 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.
*
* @param sourceRow
* The row from where the piece is moving from.
* @param sourceCol
* The column from where the piece is moving from.
* @param targetRow
* The row to where the piece is moving to.
* @param targetCol
* The column to where the piece is moving to.
*/
public static void movePiece(Game game, int sourceRow, int sourceCol, int targetRow,
int targetCol) {
// If everything checks out... move the piece!
if (canMove(game, sourceRow, sourceCol, targetRow, targetCol)) {
if (game.getJumpInProgress() != null) {
// TODO: Implement jumping via removing of piece.
game.getGameBoard().movePiece(sourceRow, sourceCol, targetRow,
targetCol);
} else {
game.getGameBoard().movePiece(sourceRow, sourceCol, targetRow,
targetCol);
}
checkForVictory(game);
}
}
}

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,84 +0,0 @@
package org.justcheckers.xml;
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/**
* Holds the justCheckers configuration settings.
* @author Brinick Simmons (brinick@users.sourceforge.net)
*/
final public class ConfigSettings extends Settings{
//---------------------------//
// Class Fields //
//---------------------------//
private static ConfigSettings cs = null;
//---------------------------//
// Class Methods //
//---------------------------//
//======= PUBLIC ============//
/**
* Accessor method for obtaining the one
* and only instance of this class
*/
public static ConfigSettings getInstance(){
if(cs==null) cs = new ConfigSettings(new DefaultConfigSettings());
return cs;
}
/**
* Load the default config settings.
*/
public static void loadDefault(){
cs = new ConfigSettings(new DefaultConfigSettings());
}
//======= PRIVATE CONSTRUCTORS ========//
private ConfigSettings(){
super();
}
private ConfigSettings(DefaultConfigSettings cus){
super(cus.getTextMap(),cus.getAttributeMap());
}
//======= PRIVATE INNER CLASS ============//
/* The default class from which to get settings */
private static class DefaultConfigSettings extends Settings.DefaultSettings{
private String userHome = System.getProperty("user.home");
private String userDir = System.getProperty("user.dir");
private String [][] text =
{
{"configsettings.directory.configFile",userDir+"/config.xml"},
{"configsettings.directory.settings",userHome+"/settings/"},
{"configsettings.directory.skins",userDir+"/skins/"},
{"configsettings.directory.sounds",userDir+"/sounds/"},
{"configsettings.directory.language",userDir+"/language/"},
};
private String [][] attribute =
{
{"configsettings.general.id","3"},
{"configsettings.general.id2","5"},
{"configsettings.language.default","english"},
{"configsettings.appearance.pretty","true"},
};
DefaultConfigSettings(){
super();
super.setFields(text,attribute);
}
}//end of default class
}

View File

@ -1,295 +0,0 @@
package org.justcheckers.xml;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.jdom.Attribute;
import org.jdom.Comment;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/**
* Concrete child class of the XML_IO class. Use its load() and save() methods
* to write XML into/write out XML from, the associated ConfigSettings object.
* @author Brinick Simmons (brinick@users.sourceforge.net)
*/
public class ConfigSettingsIO extends XML_IO{
//---------------------------//
// Class Methods //
//---------------------------//
//---------------------------------------------------------------------
// -- Interface -------------------------------------------------------
//---------------------------------------------------------------------
/**
* Causes the XML data held within the File object referenced by the member
* variable "file" (inherited from XML_IO) to be loaded into the ConfigSettings
* object associated with this class. The reading in of XML data and subsequent
* transformation is dealt with by the inner reader class of this class.
*/
public void load(){
try{
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(getFile());
Element rootElement = doc.getRootElement();
ConfigSettingsIOReader csior = new ConfigSettingsIOReader();
csior.visit(rootElement);
}
// catch(IOException e){
// String msg = "Problem : " + e.getMessage();
// Log.e("ConfigSettingsIO", msg);
// }
catch(JDOMException e){
String msg = "Problem : " + getFile().toString()
+ " is not a well formed XML document";
// TODO Clean up...
Logger log = LoggerFactory.getLogger(UserSettingsIO.class);
log.error("ConfigSettingsIO", msg);
}
}
/**
* Causes the data held within the ConfigSettings object associated with
* this class to be saved as XML format into the File object referenced by
* the member variable "file". Transformation of ConfigSettings data into XML
* format and subsequent writing to file is handled by the inner writer
* class of this class.
*/
public void save(){
try{
ConfigSettingsIOWriter csiow = new ConfigSettingsIOWriter();
Document doc = csiow.createXMLDocument();
XMLOutputter outputter = new XMLOutputter("",true);
PrintWriter pw = new PrintWriter(
new BufferedWriter(
new FileWriter(getFile())));
outputter.output(doc,pw);
}
catch(IOException e){
String msg = "Problem : couldn't output to the given file : "
+ getFile().toString();
// TODO Clean up...
Logger log = LoggerFactory.getLogger(ConfigSettingsIO.class);
log.error("ConfigSettingsIO", msg);
}
}
//---------------------------------------------------------------------
// -- Contructors -----------------------------------------------------
//---------------------------------------------------------------------
/**
* The constructor used to initiate the ConfigSettingsIO
* object with a given file object
* @param fileObject The file object with which
* to initiate this ConfigSettingsIO.
*/
public ConfigSettingsIO(File fileObject){
super(fileObject,ConfigSettings.getInstance());
}
public ConfigSettingsIO(File fileObject, ConfigSettings cs){
super(fileObject,cs);
}
public ConfigSettingsIO(URL urlObject){
super(urlObject, ConfigSettings.getInstance());
}
public ConfigSettingsIO(URL urlObject, ConfigSettings cs){
super(urlObject,cs);
}
///////////////////////////////////
// INNER CLASS : READER //
///////////////////////////////////
private class ConfigSettingsIOReader extends XML_IO.XMLFileReader{
/*
* Loads text information held in an Element object
* into the ConfigSettings object
*/
protected void loadElementIntoSettings(Element e){
String text = e.getTextTrim();
if(text!=null && text.length()!=0){
ConfigSettings.getInstance().setElementText(toFullSettingName(e),text);
}
}
/*
* Loads Attribute information held in an Element object
* into the ConfigSettings object
*/
protected void loadAttributesIntoSettings(Element e){
List attributes = e.getAttributes();
ConfigSettings cs = ConfigSettings.getInstance();
for(int k=0;k<attributes.size();k++){
Attribute current = (Attribute)attributes.get(k);
String total = toFullSettingName(e) + "" + current.getName();
cs.setElementAttribute(total,current.getValue());
}
}
/** Adds the correct number on the end of the settings key.
Thus a.b.c.d becomes a.b.c.d.x where x=1,2,3...Checks if the key
a.b.c.d.1 exists. If so, looks for a.b.c.d.2, etc. in the settings class,
and so on, until it has a new key. This method thus allows multi Elements
with the same name to be stored uniquely. Without this, for example,
game moves would all have the same key e.g. gamesettings.game.move
*/
protected String correctKeyForNumber(String uncorrectedKey){
int i = 1;
String correctedKey = uncorrectedKey + "" + i;
//is there a key with this name?
boolean reachedEnd = (ConfigSettings.getInstance().getElementText(correctedKey) == null);
while(!reachedEnd){
i++;
int lastDotIndex = correctedKey.lastIndexOf('.');
correctedKey = correctedKey.substring(0,lastDotIndex+1) + i;
reachedEnd = (ConfigSettings.getInstance().getElementText(correctedKey) == null);
}
return correctedKey;
}
} //end of inner class ConfigSettingsIOReader
///////////////////////////////////
// INNER CLASS : WRITER //
///////////////////////////////////
private class ConfigSettingsIOWriter extends XML_IO.XMLFileWriter{
/* Creates and returns the Document root Element */
public Element createRootElement(){
ConfigSettings cs = ConfigSettings.getInstance();
Iterator textEntries = cs.getTextEntries().iterator();
Map.Entry me = (Map.Entry)textEntries.next();
String settingKey = (String)me.getKey();
String settingValue = (String)me.getValue();
ArrayList settingKeyTokens = splitSettingKey(settingKey);
return new Element((String)settingKeyTokens.get(0));
}
/* Adds org.jdom.Comment objects to the current Document */
public void addComments(Document doc){
String text = "This file is important. Do not delete it,"
+ " do not displace it, do not rename it. Do any of these things"
+ " and as the universe is our witness we'll fry your ass, your"
+ " hard drive, sleep with your girlfriend (and she'll enjoy it,"
+ " believe us!), have you fired from your job, and transfer your"
+ " bank accounts to our names. Yes; this program is that good.";
doc.addContent(new Comment(text));
}
/* Create the JDOM tree from the ConfigSettings class */
public void addElements(Element rootElement){
ConfigSettings cs = ConfigSettings.getInstance();
Iterator textEntries = cs.getTextEntries().iterator();
//iterator returns Map.Entry objects
while(textEntries.hasNext()){
Map.Entry me = (Map.Entry)textEntries.next();
String settingKey = (String)me.getKey();
String settingValue = (String)me.getValue();
ArrayList settingKeyTokens = splitSettingKey(settingKey);
Element parent = rootElement;
Element child = null;
for(int k=1;k<settingKeyTokens.size();k++){
String childName = (String)settingKeyTokens.get(k);
child = getChildElement(parent,childName);
if(child==null){
child = new Element(childName);
parent.addContent(child);
if(isLastToken(k,settingKeyTokens.size())){
child.addContent(settingValue);
}
}
parent = child;
}
}
}
/* Adds org.jdom.Attribute objects to the DOM tree Elements */
public void addAttributes(Element root){
Iterator attributeEntries =
ConfigSettings.getInstance().getAttributeEntries().iterator();
while(attributeEntries.hasNext()){
Map.Entry me = (Map.Entry)attributeEntries.next();
String settingKey = (String)me.getKey();
String settingValue = (String)me.getValue();
ArrayList settingKeyTokens = splitSettingKey(settingKey);
Element e = getElement(settingKeyTokens,root);
e.setAttribute((String)settingKeyTokens.get(
settingKeyTokens.size()-1),settingValue);
}
}
//Checks whether the token from the StringTokenizer operation
private boolean isLastToken(int k, int listSize){
return (k==listSize-1);
}
//Navigates down the jdom tree until it reaches the element
//to which we wish to attach an attribute. Returns that element.
private Element getElement(ArrayList tokens, Element root){
Element e = root;
for(int k=1;k<tokens.size()-1;k++){
e = e.getChild((String)tokens.get(k));
}
return e;
}
/*
* Does this parent Element already have a child with this name attached?
* If so, return it, else return null
*/
private Element getChildElement(Element parent, String childName){
return parent.getChild(childName);
}
/* Splits a Setting key of the form a.b.c.d into it's
respective parts, delimited by the "." */
private ArrayList splitSettingKey(String key){
ArrayList l = new ArrayList();
StringTokenizer st = new StringTokenizer(key, "",false);
while(st.hasMoreTokens()){
l.add(st.nextToken());
}
return l;
}
}//end of inner class ConfigSettingsIOWriter
}//end of class ConfigSettingsIO

View File

@ -1,68 +0,0 @@
package org.justcheckers.xml;
import java.util.HashMap;
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/**
* Holds the current game settings (Players, moves, etc).
* Currently, only one game may be open at a time.
* Future versions may allow more than one game to be open at
* a given moment.
*
* @author Brinick Simmons (brinick@users.sourceforge.net)
*/
final public class GameSettings extends Settings{
//---------------------------//
// Class Fields //
//---------------------------//
private HashMap text = new HashMap(), attribute = new HashMap();
private static GameSettings gs = null;
//---------------------------//
// Class Methods //
//---------------------------//
//======= PUBLIC ============//
/**
* Accessor method for reaching the one and only instance of this class.
* @return Reference to the GameSettings object
*/
public static GameSettings getInstance(){
if(gs==null) gs = new GameSettings();
return gs;
}
/*
================ NOTE : ===============================================
=======================================================================
For GameSettings, we need in addition to the inherited Settings methods
methods that will be used to fill this object when a new game is started.
To be able to code these required methods (there will be more than the two
I give as example below) we need to agree on a format for games XML files.
public void addMove(CheckersMove cm){...}
public void addPlayer(Player p){...}
...
...
...
=========================================================================
*/
// -- Private Constructors -----------------------------------------------
private GameSettings(){
super();
}
}

View File

@ -1,297 +0,0 @@
package org.justcheckers.xml;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.jdom.Attribute;
import org.jdom.Comment;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/* **************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/**
* Concrete child class of the @link(XML_IO) class. Represents an
* "intelligent" XML file that can read XML data into/write data from
* the @link(GameSettings) information associated with this class.
*
* @author Brinick Simmons (brinick@users.sourceforge.net)
*/
public class GameSettingsIO extends XML_IO{
//---------------------------//
// Class Methods //
//---------------------------//
//---------------------------------------------------------------------
// -- Interface -------------------------------------------------------
//---------------------------------------------------------------------
/**
* Causes the XML data held within the File object referenced by the member
* variable "file" (inherited from XML_IO) to be loaded into the GameSettings
* object associated with this class. The reading in of XML data and subsequent
* transformation is dealt with by the inner reader class of this class.
*/
public void load(){
try{
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(getFile());
Element rootElement = doc.getRootElement();
GameSettingsIOReader gsior = new GameSettingsIOReader();
gsior.visit(rootElement);
}
//catch(IOException e){
// String msg = "Problem : " + e.getMessage();
// Log.e("GameSettingsIO", msg);
//}
catch(JDOMException e){
String msg = "Problem : " + getFile().toString()
+ " is not a well formed XML document";
// TODO Clean up...
Logger log = LoggerFactory.getLogger(GameSettingsIO.class);
log.error("GameSettingsIO", msg);
}
}
/**
* Causes the data held within the GameSettings object associated with
* this class to be saved as XML format into the File object referenced by
* the member variable "file". Transformation of GameSettings data into XML
* format and subsequent writing to file is handled by the inner writer
* class of this class.
*/
public void save(){
try{
GameSettingsIOWriter gsiow = new GameSettingsIOWriter();
Document doc = gsiow.createXMLDocument();
XMLOutputter outputter = new XMLOutputter("",true);
PrintWriter pw = new PrintWriter(
new BufferedWriter(
new FileWriter(getFile())));
outputter.output(doc,pw);
}
catch(IOException e){
String msg = "Problem : couldn't output to the given file : "
+ getFile().toString();
// TODO Clean up...
Logger log = LoggerFactory.getLogger(GameSettingsIO.class);
log.error("GameSettingsIO", msg);
}
}
//---------------------------------------------------------------------
// -- Contructors -----------------------------------------------------
//---------------------------------------------------------------------
/**
* The constructor used to initiate the GameSettingsIO
* object with a given file object
* @param fileObject The file object with which
* to initiate this GameSettingsIO.
*/
public GameSettingsIO(File fileObject){
super(fileObject,GameSettings.getInstance());
}
public GameSettingsIO(File fileObject, GameSettings cs){
super(fileObject,cs);
}
public GameSettingsIO(URL urlObject){
super(urlObject, GameSettings.getInstance());
}
public GameSettingsIO(URL urlObject, GameSettings cs){
super(urlObject,cs);
}
///////////////////////////////////
// INNER CLASS : READER //
///////////////////////////////////
private class GameSettingsIOReader extends XML_IO.XMLFileReader{
/*
* Loads text information held in an Element object
* into the GameSettings object
*/
protected void loadElementIntoSettings(Element e){
String text = e.getTextTrim();
if(text!=null && text.length()!=0){
GameSettings.getInstance().setElementText(toFullSettingName(e),text);
}
}
/*
* Loads Attribute information held in an Element object
* into the GameSettings object
*/
protected void loadAttributesIntoSettings(Element e){
List attributes = e.getAttributes();
GameSettings gs = GameSettings.getInstance();
for(int k=0;k<attributes.size();k++){
Attribute current = (Attribute)attributes.get(k);
String total = toFullSettingName(e) + "" + current.getName();
gs.setElementAttribute(total,current.getValue());
}
}
/** Adds the correct number on the end of the settings key.
Thus a.b.c.d becomes a.b.c.d.x where x=1,2,3...Checks if the key
a.b.c.d.1 exists. If so, looks for a.b.c.d.2, etc. in the settings class,
and so on, until it has a new key. This method thus allows multi Elements
with the same name to be stored uniquely. Without this, for example,
game moves would all have the same key e.g. gamesettings.game.move
*/
protected String correctKeyForNumber(String uncorrectedKey){
int i = 1;
String correctedKey = uncorrectedKey + "" + i;
//is there a key with this name?
boolean reachedEnd = (GameSettings.getInstance().getElementText(correctedKey) == null);
while(!reachedEnd){
i++;
int lastDotIndex = correctedKey.lastIndexOf('.');
correctedKey = correctedKey.substring(0,lastDotIndex+1) + i;
reachedEnd = (GameSettings.getInstance().getElementText(correctedKey) == null);
}
return correctedKey;
}
} //end of inner class GameSettingsIOReader
///////////////////////////////////
// INNER CLASS : WRITER //
///////////////////////////////////
private class GameSettingsIOWriter extends XML_IO.XMLFileWriter{
/* Creates and returns the Document root Element */
public Element createRootElement(){
GameSettings gs = GameSettings.getInstance();
Iterator textEntries = gs.getTextEntries().iterator();
Map.Entry me = (Map.Entry)textEntries.next();
String settingKey = (String)me.getKey();
String settingValue = (String)me.getValue();
ArrayList settingKeyTokens = splitSettingKey(settingKey);
return new Element((String)settingKeyTokens.get(0));
}
/* Adds org.jdom.Comment objects to the current Document */
public void addComments(Document doc){
String text = "This file is important. Do not delete it,"
+ " do not displace it, do not rename it. Do any of these things"
+ " and as the universe is our witness we'll fry your ass, your"
+ " hard drive, sleep with your girlfriend (and she'll enjoy it,"
+ " believe us!), have you fired from your job, and transfer your"
+ " bank accounts to our names. Yes; this program is that good.";
doc.addContent(new Comment(text));
}
/* Create the JDOM tree from the GameSettings class */
public void addElements(Element rootElement){
GameSettings gs = GameSettings.getInstance();
Iterator textEntries = gs.getTextEntries().iterator();
//iterator returns Map.Entry objects
while(textEntries.hasNext()){
Map.Entry me = (Map.Entry)textEntries.next();
String settingKey = (String)me.getKey();
String settingValue = (String)me.getValue();
ArrayList settingKeyTokens = splitSettingKey(settingKey);
Element parent = rootElement;
Element child = null;
for(int k=1;k<settingKeyTokens.size();k++){
String childName = (String)settingKeyTokens.get(k);
child = getChildElement(parent,childName);
if(child==null){
child = new Element(childName);
parent.addContent(child);
if(isLastToken(k,settingKeyTokens.size())){
child.addContent(settingValue);
}
}
parent = child;
}
}
}
/* Adds org.jdom.Attribute objects to the DOM tree Elements */
public void addAttributes(Element root){
Iterator attributeEntries =
GameSettings.getInstance().getAttributeEntries().iterator();
while(attributeEntries.hasNext()){
Map.Entry me = (Map.Entry)attributeEntries.next();
String settingKey = (String)me.getKey();
String settingValue = (String)me.getValue();
ArrayList settingKeyTokens = splitSettingKey(settingKey);
Element e = getElement(settingKeyTokens,root);
e.setAttribute((String)settingKeyTokens.get(
settingKeyTokens.size()-1),settingValue);
}
}
//Checks whether the token from the StringTokenizer operation
private boolean isLastToken(int k, int listSize){
return (k==listSize-1);
}
//Navigates down the jdom tree until it reaches the element
//to which we wish to attach an attribute. Returns that element.
private Element getElement(ArrayList tokens, Element root){
Element e = root;
for(int k=1;k<tokens.size()-1;k++){
e = e.getChild((String)tokens.get(k));
}
return e;
}
/*
* Does this parent Element already have a child with this name attached?
* If so, return it, else return null
*/
private Element getChildElement(Element parent, String childName){
return parent.getChild(childName);
}
/* Splits a Setting key of the form a.b.c.d into it's
respective parts, delimited by the "." */
private ArrayList splitSettingKey(String key){
ArrayList l = new ArrayList();
StringTokenizer st = new StringTokenizer(key, "",false);
while(st.hasMoreTokens()){
l.add(st.nextToken());
}
return l;
}
}//end of inner class GameSettingsIOWriter
}//end of class GameSettingsIO

View File

@ -1,124 +0,0 @@
package org.justcheckers.xml;
import java.util.Set;
import java.util.HashMap;
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/**
* Defines a common template for all classes that
* store some sort of Settings. Text, Attribute and Element
* are references to the XML objects as implemented
* by the JDOM API (http://www.jdom.org).
*
* @author Brinick Simmons (brinick@users.sourceforge.net)
*/
public abstract class Settings{
//---------------------------//
// Class Fields //
//---------------------------//
protected HashMap text = null, attribute = null;
//---------------------------//
// Class Methods //
//---------------------------//
//---------------------------------------------------------------------
// -- Interface -------------------------------------------------------
//---------------------------------------------------------------------
public static void loadDefault(){}
//get/set methods on the HashMaps
public String getElementText(String key){
if(!text.containsKey(key)) return null;
return (String)text.get(key);
}
public void setElementText(String key, String value){
text.put(key,value);
}
public String getElementAttribute(String key){
if(!attribute.containsKey(key)) return null;
return (String)attribute.get(key);
}
public void setElementAttribute(String key, String value){
attribute.put(key,value);
}
public String getSetting(String key){
if(text.containsKey(key)) return getElementText(key);
else if(attribute.containsKey(key)) return getElementAttribute(key);
return null;
}
public Set getTextEntries(){return text.entrySet();}
public Set getAttributeEntries(){return attribute.entrySet();}
//---------------------------------------------------------------------
// -- Constructors ----------------------------------------------------
//---------------------------------------------------------------------
protected Settings(){
text = new HashMap();
attribute = new HashMap();
}
/**
* Initiate the two class HashMap member objects with the parameters
* @param t The HashMap with which to initiate the "text" member
* @param a The HashMap with which to initiate the "attribute" member
*/
protected Settings(HashMap t, HashMap a){
text = t;
attribute = a;
}
////////////////////////////////////
// INNER CLASS : Default Settings //
////////////////////////////////////
/**
* The outer Settings object employs this nested one to obtain default values
* for its member HashMap objects "text" and "attribute".
*/
protected abstract static class DefaultSettings{
//------ Class Fields -----------
protected String [][] text = {};
protected String [][] attribute = {};
//------ Class Methods ----------
protected void setFields(String [][] text, String [][] attribute){
this.text = text;
this.attribute = attribute;
}
public HashMap getTextMap(){
HashMap hm = new HashMap(text.length);
for(int k=0;k<text.length;k++){
hm.put(text[k][0],text[k][1]);
}
return hm;
}
public HashMap getAttributeMap(){
HashMap hm = new HashMap(attribute.length);
for(int k=0;k<attribute.length;k++){
hm.put(attribute[k][0],attribute[k][1]);
}
return hm;
}
}
}

View File

@ -1,92 +0,0 @@
package org.justcheckers.xml;
import java.util.HashMap;
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/**
* Stores the user preferences in the application memory.
* Implements the singleton pattern.
*
* @author Brinick Simmons (brinick@users.sourceforge.net)
*/
final public class UserSettings extends Settings{
//---------------------------//
// Class Fields //
//---------------------------//
private static UserSettings us = null;
private HashMap text = null, attribute = null;
//---------------------------//
// Class Methods //
//---------------------------//
// -- Interface ---------------------------------------------------------
/**
* Accessor method for obtaining the one and only instance of this class
*/
public static UserSettings getInstance(){
if(us==null) loadDefault();
return us;
}
/**
* Load the default user settings.
*/
public static void loadDefault(){
us = new UserSettings(new DefaultUserSettings());
//somehow would have to log that properties have changed
//so that things can be updated e.g. the UI, or whatever
}
// -- Private Constructors -----------------------------------------------
private UserSettings(){
super();
}
private UserSettings(DefaultUserSettings dus){
super(dus.getTextMap(), dus.getAttributeMap());
}
//////////////////////////////////////
// INNER CLASS : DefaultSettings //
//////////////////////////////////////
private static class DefaultUserSettings extends Settings.DefaultSettings{
private String [][] text =
{
{"usersettings.general.splashOnLaunch","true"},
{"usersettings.general.maxActiveGames","3"},
{"usersettings.audio.activateBkgdOnLaunch","false"},
{"usersettings.audio.defaultBkgdSong","song1.wav"},
{"usersettings.audio.appSoundsActive","true"},
{"usersettings.language.current","english"},
{"usersettings.appearance.fullScreenOnLaunch","true"},
{"usersettings.appearance.activePieceSet","pieceset1"},
};
private String [][] attribute =
{
{"usersettings.general.id","3"},
{"usersettings.general.id2","5"},
{"usersettings.language.default","english"},
{"usersettings.appearance.pretty","true"},
};
DefaultUserSettings(){
super();
super.setFields(text,attribute);
}
}
}

View File

@ -1,302 +0,0 @@
package org.justcheckers.xml;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.jdom.Attribute;
import org.jdom.Comment;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/* **************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/**
* Concrete child class of the @link(XML_IO) class. Represents an
* "intelligent" XML file that can read XML data into/write data from
* the @link(UserSettings) information associated with this class.
*
* @author Brinick Simmons (brinick@users.sourceforge.net)
*/
public class UserSettingsIO extends XML_IO {
//---------------------------//
// Class Methods //
//---------------------------//
//---------------------------------------------------------------------
// -- Interface -------------------------------------------------------
//---------------------------------------------------------------------
/**
* Causes the XML data held within the File object referenced by the member
* variable "file" (inherited from XML_IO) to be loaded into the UserSettings
* object associated with this class. The reading in of XML data and subsequent
* transformation is dealt with by the inner reader class of this class.
*/
public void load(){
try{
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(getFile());
Element rootElement = doc.getRootElement();
UserSettingsIOReader usior = new UserSettingsIOReader();
usior.visit(rootElement);
}
// catch(IOException e){
// String msg = "Problem : " + e.getMessage();
// Log.e("UserSettingsIO", msg);
// }
catch(JDOMException e){
String msg = "Problem : " + getFile().toString()
+ " is not a well formed XML document";
// TODO Clean up...
Logger log = LoggerFactory.getLogger(UserSettingsIO.class);
log.error("UserSettingsIO", msg);
}
}
/**
* Causes the data held within the UserSettings object associated with
* this class to be saved as XML format into the File object referenced by
* the member variable "file". Transformation of UserSettings data into XML
* format and subsequent writing to file is handled by the inner writer
* class of this class.
*/
public void save(){
try{
UserSettingsIOWriter usiow = new UserSettingsIOWriter();
Document doc = usiow.createXMLDocument();
XMLOutputter outputter = new XMLOutputter("",true);
PrintWriter pw = new PrintWriter(
new BufferedWriter(
new FileWriter(getFile())));
outputter.output(doc,pw);
}
catch(IOException e){
String msg = "Problem : couldn't output to the given file : "
+ getFile().toString();
// TODO Clean up...
Logger log = LoggerFactory.getLogger(UserSettingsIO.class);
log.error("UserSettingsIO", msg);
}
}
//---------------------------------------------------------------------
// -- Contructors -----------------------------------------------------
//---------------------------------------------------------------------
/**
* The constructor used to initiate the UserSettingsIO
* object with a given file object
* @param fileObject The file object with which
* to initiate this UserSettingsIO.
*/
public UserSettingsIO(File fileObject){
super(fileObject,UserSettings.getInstance());
}
public UserSettingsIO(File fileObject, UserSettings us){
super(fileObject,us);
}
public UserSettingsIO(URL urlObject){
super(urlObject,UserSettings.getInstance());
}
public UserSettingsIO(URL urlObject, UserSettings us){
super(urlObject,us);
}
///////////////////////////////////
// INNER CLASS : READER //
///////////////////////////////////
private class UserSettingsIOReader extends XML_IO.XMLFileReader{
/*
* Loads text information held in an Element object
* into the UserSettings object
*/
protected void loadElementIntoSettings(Element e){
String text = e.getTextTrim();
if(text!=null && text.length()!=0){
String fullName = toFullSettingName(e);
UserSettings.getInstance().setElementText(fullName,text);
System.out.println("element: " + fullName + " = " + text);
}
}
/*
* Loads Attribute information held in an Element object
* into the UserSettings object
*/
protected void loadAttributesIntoSettings(Element e){
List attributes = e.getAttributes();
UserSettings us = UserSettings.getInstance();
for(int k=0;k<attributes.size();k++){
Attribute current = (Attribute)attributes.get(k);
String total = toFullSettingName(e) + "" + current.getName();
us.setElementAttribute(total,current.getValue());
System.out.println("attribute: " + total + " = " + current.getValue());
}
}
/** Adds the correct number on the end of the settings key.
Thus a.b.c.d becomes a.b.c.d.x where x=1,2,3...Checks if the key
a.b.c.d.1 exists. If so, looks for a.b.c.d.2, etc. in the settings class,
and so on, until it has a new key. This method thus allows multi Elements
with the same name to be stored uniquely. Without this, for example,
game moves would all have the same key e.g. gamesettings.game.move
*/
protected String correctKeyForNumber(String uncorrectedKey){
int i = 1;
String correctedKey = uncorrectedKey + "" + i;
//is there a key with this name?
boolean reachedEnd = (UserSettings.getInstance().getElementText(correctedKey) == null);
while(!reachedEnd){
i++;
int lastDotIndex = correctedKey.lastIndexOf('.');
correctedKey = correctedKey.substring(0,lastDotIndex+1) + i;
reachedEnd = (UserSettings.getInstance().getElementText(correctedKey) == null);
}
return correctedKey;
}
} //end of inner class UserSettingsIOReader
///////////////////////////////////
// INNER CLASS : WRITER //
///////////////////////////////////
private class UserSettingsIOWriter extends XML_IO.XMLFileWriter{
/* Creates and returns the Document root Element */
public Element createRootElement(){
UserSettings us = UserSettings.getInstance();
Iterator textEntries = us.getTextEntries().iterator();
Map.Entry me = (Map.Entry)textEntries.next();
String settingKey = (String)me.getKey();
String settingValue = (String)me.getValue();
ArrayList settingKeyTokens = splitSettingKey(settingKey);
return new Element((String)settingKeyTokens.get(0));
}
/* Adds org.jdom.Comment objects to the current Document */
public void addComments(Document doc){
String text = "This file is important. Do not delete it,"
+ " do not displace it, do not rename it. Do any of these things"
+ " and as the universe is our witness we'll fry your ass, your"
+ " hard drive, sleep with your girlfriend (and she'll enjoy it,"
+ " believe us!), have you fired from your job, and transfer your"
+ " bank accounts to our names. Yes; this program is that good.";
doc.addContent(new Comment(text));
}
/* Create the JDOM tree from the UserSettings class */
public void addElements(Element rootElement){
UserSettings us = UserSettings.getInstance();
Iterator textEntries = us.getTextEntries().iterator();
//iterator returns Map.Entry objects
while(textEntries.hasNext()){
Map.Entry me = (Map.Entry)textEntries.next();
String settingKey = (String)me.getKey();
String settingValue = (String)me.getValue();
ArrayList settingKeyTokens = splitSettingKey(settingKey);
Element parent = rootElement;
Element child = null;
for(int k=1;k<settingKeyTokens.size();k++){
String childName = (String)settingKeyTokens.get(k);
child = getChildElement(parent,childName);
if(child==null){
child = new Element(childName);
parent.addContent(child);
if(isLastToken(k,settingKeyTokens.size())){
child.addContent(settingValue);
}
}
parent = child;
}
}
}
/* Adds org.jdom.Attribute objects to the DOM tree Elements */
public void addAttributes(Element root){
Iterator attributeEntries =
UserSettings.getInstance().getAttributeEntries().iterator();
while(attributeEntries.hasNext()){
Map.Entry me = (Map.Entry)attributeEntries.next();
String settingKey = (String)me.getKey();
String settingValue = (String)me.getValue();
ArrayList settingKeyTokens = splitSettingKey(settingKey);
Element e = getElement(settingKeyTokens,root);
e.setAttribute((String)settingKeyTokens.get(
settingKeyTokens.size()-1),settingValue);
}
}
//Checks whether the token from the StringTokenizer operation
private boolean isLastToken(int k, int listSize){
return (k==listSize-1);
}
//Navigates down the jdom tree until it reaches the element
//to which we wish to attach an attribute. Returns that element.
private Element getElement(ArrayList tokens, Element root){
Element e = root;
for(int k=1;k<tokens.size()-1;k++){
e = e.getChild((String)tokens.get(k));
}
return e;
}
/*
* Does this parent Element already have a child with this name attached?
* If so, return it, else return null
*/
private Element getChildElement(Element parent, String childName){
return parent.getChild(childName);
}
/* Splits a Setting key of the form a.b.c.d into it's
respective parts, delimited by the "." */
private ArrayList splitSettingKey(String key){
ArrayList l = new ArrayList();
StringTokenizer st = new StringTokenizer(key, "",false);
while(st.hasMoreTokens()){
l.add(st.nextToken());
}
return l;
}
}//end of inner class UserSettingsIOWriter
}//end of class UserSettingsIO

View File

@ -1,102 +0,0 @@
//********************************************************************
// VisitDOM.java -- Abstract class for traversing XML documents.
// ********************************************************************
// ********************************************************************
// This program 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 2 of the License, or
// (at your option) any later version.
// ********************************************************************
package org.justcheckers.xml;
import java.util.Iterator;
import org.jdom.Element;
import org.jdom.Text;
/**
* An abstract class that provides a framework to do any processing of a
* DOM tree created with the JDOM package ( http://www.jdom.org ). It
* provides a recursive traverse with data processing methods that run
* before traversal, after traversal and at each Element object and Text
* object encountered. The default methods are do-nothing place-holders.
* These methods can be over-ridden in a child class that extends this one,
* doing what ever data processing needs to be done. Other methods and
* fields can also be added to child classes as needed.
*
* @author Dan D'Alimonte
*/
public abstract class VisitDOM {
// -- Interface ---------------------------------------------------------
/**
* Actions to preform before the traversal of the DOM tree begins.
* @param e The root Element of the tree.
*/
protected void preRoot(Element e) {}
/**
* Actions to preform after the traversal has been completed.
* @param e The root Element of the tree.
*/
protected void postRoot(Element e) {}
/**
* Actions to preform when an Element object is encountered in the DOM tree.
* @param e The Element object to process.
*/
protected void elementHandler(Element e) {}
/**
* Actions to preform when a Text object is encountered in the DOM tree.
* @param t The Text object to process.
*/
protected void textHandler(Text t) {}
// -- Contructors -------------------------------------------------------
/**
* Construct a new VisitDOM instance.
*/
public VisitDOM() {}
// -- Public methods ----------------------------------------------------
/**
* Preform the taversal on the DOM tree, visiting each node and
* processing them in turn.
* @param root The root Element of the tree to preform the traversal on.
*/
public void visit(Element root) {
preRoot(root);
elementHandler(root);
recurse(root);
postRoot(root);
}
// -- Protected Methods -------------------------------------------------
/**
* Traverses to children of Elements, calling appropriate data processing
* methods on the child objects, recursing deeper if needed.
* @param e The element whose children are to be processed.
*/
protected void recurse(Element e) {
Iterator iElement = e.getChildren().iterator();
while (iElement.hasNext()) {
Object next = iElement.next();
if (next instanceof Element) {
elementHandler((Element)next);
recurse((Element)next);
}
else if ( next instanceof Text ) {
textHandler((Text)next);
}
}
}
}

View File

@ -1,25 +0,0 @@
package org.justcheckers.xml;
import java.io.File;
import java.io.FileFilter;
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/**
* XMLFileFilter returns only File objects that represent XML files.
*
* @author Brinick Simmons (brinick@users.sourceforge.net)
*
*/
public class XMLFileFilter implements FileFilter{
public boolean accept(File f){
return f.toString().endsWith(".xml");
}
}

View File

@ -1,267 +0,0 @@
package org.justcheckers.xml;
import java.io.File;
import java.net.URL;
import java.util.Iterator;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Text;
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/**
* Abstract version of an "intelligent" XML file. Objects of this class know
* how to read/write the @see(Settings) information they are associated with,
* into justCheckers memory/out to disk. The user creates a child object of
* this class giving the name and location of the File object to be represented
* by this class.
*
* NOTE :
* For the time being, data may only be outputted to XML files stored locally.
*
* @author Brinick Simmons (brinick@users.sourceforge.net)
*/
public abstract class XML_IO{
//---------------------------//
// Class Fields //
//---------------------------//
//protected URL url;
protected File file;
protected Settings settings;
//---------------------------//
// Class Methods //
//---------------------------//
//---------------------------------------------------------------------
// -- Interface -------------------------------------------------------
//---------------------------------------------------------------------
/**
* Causes the XML data held within the File object referenced by the class
* member variable "file" to be loaded into the Settings object associated
* with this class. The reading in of XML data and subsequent transformation
* is dealt with by the inner reader class of this class.
*/
public abstract void load();
/**
* Causes the data held within the Settings object associated with this class
* to be saved as XML format into the File object referenced by the class
* member variable "file". Transformation of Settings data to XML format and
* subsequent writing to File is handled by the inner writer class of this
* class.
*/
public abstract void save();
/** Sets the member variable File object to the parameter object passed in.
* @param f The File object with which to set the class member variable "file"
*/
protected void setFile(File f){file = f;}
/** Gets the member variable File object.
* @return The File object held in the class member variable "file".
*/
protected File getFile(){return file;}
/* Place holder for a later version */
// protected void setFile(URL u){}
// protected URL getFile(){}
/** Sets the member variable Settings object to the parameter object passed in.
* @param s The Settings object with which to set the class member variable "settings"
*/
protected void setSettings(Settings s){settings = s;}
/** Gets the member variable Settings object.
* @return The Settings object held in the class member variable "settings".
*/
protected Settings getSettings(){return settings;}
//---------------------------------------------------------------------
// -- Constructors ----------------------------------------------------
//---------------------------------------------------------------------
protected XML_IO(){}
protected XML_IO(File f, Settings s){file = f; settings=s;}
protected XML_IO(URL u, Settings s){}
///////////////////////////////////
// INNER CLASS : READER //
///////////////////////////////////
/**
* An abstract class that provides a framework to do any processing of a
* DOM tree created with the JDOM package ( http://www.jdom.org ). It
* provides a recursive traverse with data processing methods that run
* before traversal, after traversal and at each Element object and Text
* object encountered. The default methods are do-nothing place-holders.
* These methods can be over-ridden in a child class that extends this one,
* doing what ever data processing needs to be done. Other methods and
* fields can also be added to child classes as needed.
*
* @author Dan D'Alimonte (skwirl@users.sourceforge.net)
*/
protected abstract class XMLFileReader{
// -- Interface ---------------------------------------------------------
/**
* Actions to preform before the traversal of the DOM tree begins.
* @param e The root Element of the tree.
*/
protected void preRoot( Element e ) {}
/**
* Actions to preform after the traversal has been completed.
* @param e The root Element of the tree.
*/
protected void postRoot( Element e ) {}
/**
* Actions to preform when an Element object is encountered in the DOM tree.
* @param e The Element object to process.
*/
protected void elementHandler( Element e ) {
loadElementIntoSettings(e);
loadAttributesIntoSettings(e);
}
protected abstract void loadElementIntoSettings(Element e);
protected abstract void loadAttributesIntoSettings(Element e);
/**
* Actions to preform when a Text object is encountered in the DOM tree.
* @param t The Text object to process.
*/
protected void textHandler( Text t ) {}
// -- Constructors -------------------------------------------------------
/**
* Construct a new VisitDOM instance.
*/
public XMLFileReader() {}
// -- Public methods ----------------------------------------------------
/**
* Preform the traversal on the DOM tree, visiting each node and
* processing them in turn.
* @param root The root Element of the tree to preform the traversal on.
*/
public void visit( Element root ) {
preRoot( root );
elementHandler( root );
recurse( root );
postRoot( root );
}
// -- Protected Methods -------------------------------------------------
/**
* Traverses to children of Elements, calling appropriate data processing
* methods on the child objects, recursing deeper if needed.
* @param e The element whose children are to be processed.
*/
protected void recurse( Element e ) {
Iterator iElement = e.getChildren().iterator();
while ( iElement.hasNext() ) {
Object next = iElement.next();
if ( next instanceof Element ) {
elementHandler( (Element)next );
recurse( (Element)next );
}
else if ( next instanceof Text ) {
textHandler( (Text)next );
}
}
}
/*
* Returns the full path name in the form a.b.c.d
* of an Element object d
*/
protected String toFullSettingName(Element e){
String path = e.getName();
Element currentElement = e;
while(!currentElement.isRootElement()){
currentElement = currentElement.getParent();
path = currentElement.getName() + "" + path;
}
return correctKeyForNumber(path);
}
protected abstract String correctKeyForNumber(String path);
}
///////////////////////////////////
// INNER CLASS : WRITER //
///////////////////////////////////
/**
* Abstract framework for creating a DOM tree
* (using the JDOM API http://www.jdom.org) from an
* in-application memory "Settings" class.
* The default methods are do-nothing place-holders
* that should be over-ridden by a child class.
* @author Brinick Simmons
* @see UserSettings
* @see GameSettings
*/
protected abstract class XMLFileWriter{
/**
* Creates and returns a JDOM Document object
* @return org.jdom.Document object storing Settings information
*/
protected Document createXMLDocument(){
Element root = createRootElement();
Document doc = new Document(root);
addComments(doc);
addElements(root);
addAttributes(root);
return doc;
}
/**
* Creates the root org.jdom.Element for the Document in memory
* @return The newly created root Element
*/
abstract protected Element createRootElement();
/**
* Adds org.jdom.Comment objects to the Document
* @param d The Document to which Comments will be added
*/
protected void addComments(Document d){}
/**
* Builds the tree structure of org.jdom.Element objects in the Document.
* @param root The tree root Element to which all other
* Elements are (in)directly attached.
*/
protected void addElements(Element root){}
/**
* Adds any org.jdom.Attribute objects to the appropriate Element objects.
* @param root The tree root Element.
*/
protected void addAttributes(Element root){}
}
}

View File

@ -1,40 +0,0 @@
/*****************************************************************************
AmericanGameTest.java -- Regression test of a game played according to
American rules.
*****************************************************************************
*****************************************************************************
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.test.game;
/**
* Regression test for a game of checkers played according to American rules.
* American rules are:
* - 8x8 board.
* - Pawns can only move 1 space forward.
* - Kings can move 1 space forward or backwards.
* - The game ends when one player is eliminated or completely blocked.
*
* TestNG version: 5.10
*
* @author Dorian Pula
*
*/
public class AmericanGameTest {
//TODO: Populate with test cases.
}

View File

@ -1,37 +0,0 @@
/*****************************************************************************
GameLogicTest.java -- Unit tests related to the game engine.
*****************************************************************************
*****************************************************************************
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.test.game;
/**
* Test the game engine logic. Tests if the game engine can manipulate the
* state of a game and its board, in accordance to the rules of the game. The
* set of rule change from variant to variant. These tests should check basic
* correctness of the game engine.
*
* TestNG version: 5.10
*
* @author Dorian Pula
*
*/
public class GameLogicTest {
//TODO: Populate with test cases.
}

View File

@ -1,67 +0,0 @@
/*****************************************************************************
GameStateTest.java -- Unit tests related to managing a game's state.
*****************************************************************************
*****************************************************************************
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.test.game;
import org.justcheckers.game.Game;
import org.justcheckers.game.Rulebook;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* Test the game state logic. Tests the NQPOJO (not quite plain old Java
* objects) that handle the state of a game. This includes the Rulebook
* (that dictate what rules will be used for a game), the Board (that represents
* the state of the board, pieces, etc.) and the Game itself.
*
* TestNG version: 5.10
*
* @author dorianpula
*/
public class GameStateTest {
/** A test game of checkers. */
private Game testGame;
/**
* Sets up a rather plain game of checkers. Game is based on the American
* rules, to make life easier.
*/
@BeforeClass
public void setUp() {
this.testGame = new Game();
}
/**
* Test the rulebook of a default initialized game.
*/
@Test
public void testDefaultRulebookSetup() {
Rulebook testRules = this.testGame.getGameRules();
Assert.assertNull(testRules);
//TODO: Test the ruleset that is gets initialized properly.
}
//TODO: Populate with test cases.
}

View File

@ -1,41 +0,0 @@
/*****************************************************************************
InternationalGameTest.java -- Regression test of a game played according to
International rules.
*****************************************************************************
*****************************************************************************
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.test.game;
/**
* Regression test for a game of checkers played according to International
* rules.
* International rules are:
* - 10x10 board.
* - Pawns can move 1 space forward.
* - Kings can move 1 space forward. But can capture backwards.
* - The game ends when one player is eliminated or completely blocked.
*
* TestNG version: 5.10
*
* @author Dorian Pula
*
*/
public class InternationalGameTest {
//TODO: Populate with test cases.
}

View File

@ -1,21 +0,0 @@
/*
Gradle Build for justCheckers - Desktop
---------------------------------------
Author: Dorian Pula (dorian.pula@amber-penguin-software.ca)
License: AGPL v3.
Gradle docs:
http://www.gradle.org/docs/current/userguide/userguide_single.html
*/
apply plugin: 'java'
sourceCompatibility = 1.6
targetCompatibility = 1.6
// Description of the project
description = 'justcheckers-desktop'
version = '0.3'
// TODO Add in build for the desktop client.

7
engine/Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[package]
name = "justcheckers-engine"
version = "0.6.0"
authors = ["Dorian Pula <dorian.pula@amber-penguin-software.ca>"]
edition = "2018"
[dependencies]

201
engine/src/lib.rs Normal file
View File

@ -0,0 +1,201 @@
use std::fmt;
pub enum Piece {
LightPawn,
LightKing,
DarkPawn,
DarkKing,
}
pub enum BoardTile {
Empty,
Piece(Piece),
}
pub enum BoardSize {
American,
International,
Canadian,
}
impl BoardSize {
fn get_size(&self) -> usize {
match &self {
BoardSize::American => 8,
BoardSize::International => 10,
BoardSize::Canadian => 12,
}
}
}
pub struct Board {
dimensions: BoardSize,
tiles: Vec<BoardTile>,
}
impl Board {
pub fn new(size: BoardSize) -> Board {
let board_size = size.get_size();
let width = board_size / 2;
let height = board_size;
let starting_rows = board_size / 2 - 1;
let playing_tiles = (0..width * height)
.map(|tile| {
let row = tile / width;
match row {
r if r < starting_rows => BoardTile::Piece(Piece::LightPawn),
r if r > height - starting_rows - 1 => BoardTile::Piece(Piece::DarkPawn),
_ => BoardTile::Empty,
}
})
.collect();
Board {
dimensions: size,
tiles: playing_tiles,
}
}
fn get_index(&self, row: usize, column: usize) -> usize {
let width = self.dimensions.get_size();
(row * (width / 2) + column) as usize
}
}
static COLUMN_COORDINATE_BORDER: &str = " ABCDEFGHIJKL";
impl fmt::Display for Board {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let width = self.dimensions.get_size();
// Create the top level border.
let (column_border_chars, _) = COLUMN_COORDINATE_BORDER.split_at(width + 1);
writeln!(formatter, "{}", column_border_chars)?;
for row in 0..width {
write!(formatter, "{}", (row + 1).to_string())?;
for col in 0..(width / 2) {
let idx = self.get_index(row, col);
let token = match &self.tiles[idx] {
BoardTile::Piece(x) => match x {
Piece::LightPawn => "",
Piece::LightKing => "",
Piece::DarkPawn => "",
Piece::DarkKing => "",
},
BoardTile::Empty => "",
};
if row % 2 == 0 {
write!(formatter, " {}", token)?;
} else {
write!(formatter, "{} ", token)?;
}
}
write!(formatter, "\n")?;
}
Ok(())
}
}
pub enum GameState {
LightPlayerTurn,
DarkPlayerTurn,
LightPlayerWin,
DarkPlayerWin,
DrawGame,
}
pub struct Game {
board: Board,
state: GameState,
}
impl Game {
pub fn new(size: BoardSize) -> Game {
// TODO: Add the concept of rulesets for the various checkers variants.
Game {
board: Board::new(size),
state: GameState::LightPlayerTurn,
}
}
// TODO: Add in rules for long jump on kings, and forcing to jump as many pieces as possible.
// TODO: only support the minimal setup required for an American game of checkers.
pub fn can_piece_move(&self, row: usize, col: usize) {
// TODO: based on player turn, available jumps and moves.
}
pub fn must_piece_jump(&self, row: usize, col: usize) {
// TODO: based on player turn, available jumps and moves.
}
pub fn change_turns(&mut self) {
// TODO: go to the next turn...
}
}
#[cfg(test)]
mod tests {
use crate::Board;
use crate::BoardSize;
#[test]
fn initial_international_board_setup() {
let expected = " \
ABCDEFGHIJ\n\
1 \n\
2 \n\
3 \n\
4 \n\
5 \n\
6 \n\
7 \n\
8 \n\
9 \n\
10 \n\
";
assert_eq!(Board::new(BoardSize::International).to_string(), expected);
}
#[test]
fn initial_american_board_setup() {
let expected = " \
ABCDEFGH\n\
1 \n\
2 \n\
3 \n\
4 \n\
5 \n\
6 \n\
7 \n\
8 \n\
";
assert_eq!(Board::new(BoardSize::American).to_string(), expected);
}
#[test]
fn initial_canadian_board_setup() {
let expected = " \
ABCDEFGHIJKL\n\
1 \n\
2 \n\
3 \n\
4 \n\
5 \n\
6 \n\
7 \n\
8 \n\
9 \n\
10 \n\
11 \n\
12 \n\
";
assert_eq!(Board::new(BoardSize::Canadian).to_string(), expected);
}
}

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

73
justcheckers.pro Normal file
View File

@ -0,0 +1,73 @@
QT += quick multimedia multimediawidgets svg quickcontrols2
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += main.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
QT_QUICK_CONTROLS_STYLE=universal
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
DISTFILES += \
images/backdrop.jpg \
images/splash.jpg \
images/attack_king.png \
images/attack_pawn.png \
images/defend_king.png \
images/defend_pawn.png \
images/icon.png \
images/idea.png \
images/logo.png \
images/non_play.png \
images/play.png \
assets/credits.md \
assets/license.md \
doc/AUTHORS.txt \
doc/BUGS.txt \
doc/Changelog.txt \
justcheckers/justcheckers.ini \
justcheckers/justcheckers.kv \
COPYING.txt \
Pipfile \
Pipfile.lock \
justcheckers/game/__init__.py \
justcheckers/game/board.py \
justcheckers/game/game.py \
justcheckers/game/game_engine.py \
justcheckers/game/player.py \
justcheckers/game/rules.py \
justcheckers/__init__.py \
justcheckers/app.py \
main.py \
setup.py \
tasks.py \
main.qml \
README.rst \
buildozer.spec \
MenuButton.qml \
Menu.qml \
Board.qml
SUBDIRS += \
justcheckers.pro

1
justcheckers/__init__.py Normal file
View File

@ -0,0 +1 @@
__version__ = '0.3.0'

97
justcheckers/app.py Normal file
View File

@ -0,0 +1,97 @@
"""
Main application for justCheckers
:copyright: Copyright 2004-2017, Dorian Pula <dorian.pula@amber-penguin-software.ca>
:license: GPL v3+
"""
import json
import logging
import os
import sys
from kivy import properties
from kivy.app import App
from kivy.logger import Logger
from kivy.uix.gridlayout import GridLayout
from kivy.uix.relativelayout import RelativeLayout
import justcheckers
LOG = logging.getLogger(__name__)
class JustCheckersApp(App):
title = 'justCheckers'
icon = 'justcheckers/images/icon.png'
use_kivy_settings = False
def on_start(self):
log_system_and_game_info()
super(JustCheckersApp, self).on_start()
def build_config(self, config):
config.setdefaults('Theme', {'theme': 'Sunset', 'background': 'Sunset'})
def build_settings(self, settings):
# TODO: Add turn options for music and volume.
game_settings = [{
"type": "options",
"title": "Board Theme",
"section": "Theme",
"key": "theme",
"options": ["Sunset", "Basic"]
}, {
"type": "options",
"title": "Background",
"section": "Theme",
"key": "background",
"options": ["Sunset", "Basic"]
}]
settings.add_json_panel("justCheckers Settings", self.config, data=json.dumps(game_settings))
class GameBoard(GridLayout):
rows = properties.NumericProperty(8)
cols = properties.NumericProperty(8)
def __init__(self, **kwargs):
super(GameBoard, self).__init__(**kwargs)
for row in range(self.rows):
for col in range(self.cols):
source = 'play'
if row % 2 == 0 and col % 2 == 0:
source = 'non_play'
elif row % 2 == 1 and col % 2 == 1:
source = 'non_play'
self.add_widget(GameTile(tile_state=source, coords=[row, col]))
class GameTile(RelativeLayout):
tile_state = properties.StringProperty()
tile_coords = properties.ListProperty()
tile_image = properties.ObjectProperty()
tile_label = properties.ObjectProperty()
def __init__(self, tile_state='non_play', coords=None, **kwargs):
super(GameTile, self).__init__(**kwargs)
self.tile_state = tile_state
self.coords = coords if coords else [-1, -1]
self.tile_label.text = '{}, {}'.format(self.coords[0], self.coords[1])
self.tile_image.source = 'images/{}.png'.format(self.tile_state)
def log_system_and_game_info():
"""Logs information about the game and system running the game."""
Logger.info('justCheckers -- v{}'.format(justcheckers.__version__))
message = 'I am running on {os}.\nMy screen is {height}x{width}'
root_window = App.get_running_app().root_window
os_sys = sys.platform
if sys.platform == 'posix':
os_name, _, _, _, os_arch = os.uname()
os_sys = '{name} {arch}'.format(name=os_name, arch=os_arch)
Logger.info(message.format(os=os_sys, height=root_window.height, width=root_window.width))

View File

355
justcheckers/game/board.py Normal file
View File

@ -0,0 +1,355 @@
#
# 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
from justcheckers.game import rules
class Square(Enum):
"""Represents the state of a single square on a checkerboard."""
WHITE = -1
EMPTY = 0
LIGHT_PAWN = 1
LIGHT_KING = 2
DARK_PAWN = 3
DARK_KING = 4
class Board(object):
"""
* Container for the state of the checker board during a game.
*
* The size of the board is defined by the number of squares along one side,
* since all checker boards are square. The board coordinate system has both
* horizontal and vertical numeric components ranging from 0 to boardSize-1.
* Depicted on-screen, the horizontal component extends to the right and the
* vertical component extends downwards, making the upper left square (0, 0) and
* the lower right square (boardSize-1, boardSize-1).
*
* <b>Navigating through the Board</b> Internally, the checker board is
* organized as a two-dimensional array. So when iterating through the board,
* you first specify the vertical component and then the horizontal component.
* Another way of thinking about is first specifying which row you want to look
* at from top to bottom. Then you specify how across the row you are looking at
* from left to right.
*
* <b>Players Places</b> The light player (the starting player) starts at the
* top of the board. The dark player starts at the bottom of the board.
*
* @author Dorian Pula
* @author Ross Etchells
"""
def __init__(self, size=rules.Rules.STANDARD_BOARD_SIZE, mirrored=False):
self.board_size = size
self._board = [[Square.EMPTY for y in xrange(0, self.board_size)] for x in xrange(0, self.board_size)]
# /**
# * Clears the board of pieces. Creates a brand new empty board already laid
# * out by the rules (regular or mirrored).
# */
for row in xrange(0, size):
for col in xrange(0, size):
# Mirrored has opposite setup to a regular board.
if (row % 2 == 0) and (col % 2 == 0):
if mirrored:
self._board[row][col] = Square.WHITE
else:
self._board[row][col] = Square.EMPTY
elif (row % 2 == 0) and (col % 2 == 1):
if mirrored:
self._board[row][col] = Square.EMPTY
else:
self._board[row][col] = Square.WHITE
elif (row % 2 == 1) and (col % 2 == 0):
if mirrored:
self._board[row][col] = Square.EMPTY
else:
self._board[row][col] = Square.WHITE
else:
if mirrored:
self._board[row][col] = Square.WHITE
else:
self._board[row][col] = Square.EMPTY
def is_inside_board(self, row, col):
return (0 <= row < self.board_size) and (0 <= col < self.board_size)
def is_dark(self, row, col):
"""
/**
* Determines whether the piece at board coordinate (row, col) is dark. If
* the coordinates do not exist on the board or are empty, this method will
* return false.
*
* @param row
* The row of the square.
* @param col
* The column of the square.
* @return True if the piece at the specified coordinate is dark. False if
* otherwise.
*/
"""
return self.is_inside_board(row, col) and self._board[row][col] in [Square.DARK_KING, Square.DARK_PAWN]
def is_empty(self, row, col):
"""
/**
* Determines whether the piece at board coordinate (row, col) is empty. If
* the coordinates do not exist on the board or is illegal, this method will
* return False.
*
* @param row
* The row of the square.
* @param col
* The column of the square.
* @return True if the piece at the specified coordinate is empty. False if
* otherwise.
*/
"""
return self.is_inside_board(row, col) and self._board[row][col] == Square.EMPTY
def is_illegal_space(self, row, col):
"""
/**
* Determines whether the board coordinate (x, y) is used in the game. In
* most cases, all light spaces on the board will be considered illegal.
* Also, any coordinate which does not exist is also considered illegal.
*
* @param row
* The row of the square.
* @param col
* The column of the square.
* @return True if the specified coordinate is nonexistent or unused in the
* current rules. False if otherwise.
*/
"""
return self.is_inside_board(row, col) and self._board[row][col] == Square.WHITE
# /**
# * Determines whether the piece at board coordinate (row, col) is a king. If
# * the coordinates do not exist on the board or are empty, this method will
# * return False.
# *
# * @param row
# * The row of the square.
# * @param col
# * The column of the square.
# * @return True if the piece at the specified coordinate is a king. False if
# * otherwise.
# */
def is_king(self, row, col):
return self.is_inside_board(row, col) and self._board[row][col] in [Square.LIGHT_KING, Square.DARK_KING]
# /**
# * Returns if a position specified is legal. Returns true if the position is
# * on the board, and if the space is not an illegal white space. Returns
# * False otherwise.
# *
# * @param row
# * The row coordinate of the position.
# * @param col
# * The column coordinate of the position.
# * @return Returns true if the position is a legal playing position.
# */
def is_legal_position(self, row, col):
return self.is_inside_board(row, col) and not self.is_illegal_space(row, col)
# /**
# * Determines whether the piece at board coordinate (row, col) is light. If
# * the coordinates do not exist on the board or are empty, this method will
# * return False.
# *
# * @param row
# * The row of the square.
# * @param col
# * The column of the square.
# * @return True if the piece at the specified coordinate is light. False if
# * otherwise.
# */
def is_light(self, row, col):
return self.is_inside_board(row, col) and self._board[row][col] in [Square.LIGHT_KING, Square.LIGHT_PAWN]
# /**
# * Determines whether the piece at board coordinate (row, col) is a pawn. If
# * the coordinates do not exist on the board or are empty, this method will
# * return False.
# *
# * @param row
# * The row of the square.
# * @param col
# * The column of the square.
# * @return True if the piece at the specified coordinate is a pawn. False if
# * otherwise.
# */
def is_pawn(self, row, col):
return self.is_inside_board(row, col) and self._board[row][col] in [Square.LIGHT_PAWN, Square.DARK_PAWN]
# /**
# * Moves a pieces from one location to another. This method should be called
# * from the Game using this Board. This method does not check for rule
# * validity but does check for illegal white spaces. Also checks that the
# * destination position is empty.
# *
# * @param sourceRow
# * The row from where the piece is moving from.
# * @param sourceCol
# * The column from where the piece is moving from.
# * @param targetRow
# * The row to where the piece is moving to.
# * @param targetCol
# * The column to where the piece is moving to.
# */
def move_piece(self, source_row, source_col, target_row, target_col):
if (self.is_legal_position(source_row, source_col)
and self.is_legal_position(target_row, target_col)
and self._board[target_row][target_col] == Square.EMPTY):
self._board[source_row][source_col], self._board[target_row][target_col] = (
Square.EMPTY, self._board[source_row][source_col])
# /**
# * Removes a pieces from the specified location. This method should be
# * called from the Game using this Board. This method does not check for
# * rule validity but does check for illegal white spaces.
# *
# * @param row
# * The row where the piece is to be removed from.
# * @param col
# * The column where the piece is to be removed from.
# */
def remove_piece(self, row, col):
if self.is_legal_position(row, col):
self._board[row][col] = Square.EMPTY
# /**
# * Setups the board for a new game. There are three different setups for the
# * three different types of boards:
# *
# * <table>
# * <tr>
# * <b>
# * <td>Name</td>
# * <td>Size</td>
# * <td>Number of Pieces Per Player</td>
# * <td>Number of Rows Per Player</td>
# * </b>
# * </tr>
# * <tr>
# * <td>Standard</td>
# * <td>8 x 8</td>
# * <td>12</td>
# * <td>3</td>
# * </tr>
# * <tr>
# * <td>International</td>
# * <td>10 x 10</td>
# * <td>20</td>
# * <td>4</td>
# * </tr>
# * <tr>
# * <td>Canadian</td>
# * <td>12 x 12</td>
# * <td>30</td>
# * <td>5</td>
# * </tr>
# * </table>
# *
# * The columns containing the players' tokens alternate between columns. The
# * dark player traditionally takes the first few upper rows (0-3). The light
# * player takes the last of the lower rows (5-7, 6-9 or 7-11).
# *
# * Note that the suicide checkers variant has a completely different setup,
# * and has a setup function of its own: setupNewSuicideGame().
# */
def setup_new_game(self):
# Used to decide which rows to fill up.
# Figure out the size of the board.
if self.board_size == rules.InternationalRules.INTERNATIONAL_BOARD_SIZE:
dark_player_bottom_row = 3
light_player_top_row = 6
elif self.board_size == rules.CanadianRules.CANADIAN_BOARD_SIZE:
dark_player_bottom_row = 3
light_player_top_row = 7
else:
# Default board is 8x8 Standard size.
dark_player_bottom_row = 2
light_player_top_row = 5
# Go through the board and set it up.
for row in xrange(0, self.board_size):
for col in xrange(0, self.board_size):
if row <= dark_player_bottom_row and self._board[row][col] == Square.EMPTY:
self._board[row][col] = Square.DARK_PAWN
elif row >= light_player_top_row and self._board[row][col] == Square.EMPTY:
self._board[row][col] = Square.LIGHT_PAWN
# /**
# * Setups a checker board according to the suicide "French" rules.
# */
def setup_new_suicide_game(self):
# TODO: Implement the suicide game setup.
pass
def __str__(self):
"""
Override __str__ to get back an elegant unicode representation of the board.
:returns: A text representation of the current state of the board.
"""
# TODO Fix up string building setup. Separate into smaller component functions.
# Prepare for output with a nice looking to banner.
output = " "
for row in xrange(0, self.board_size):
if row < 9:
output = '{} {} '.format(output, row + 1)
else:
output = '{} {}'.format(output, row + 1)
output = output + "\n\n"
output_atom = {
Square.WHITE: u"\u2588\u2588\u2588",
Square.EMPTY: u" ",
Square.LIGHT_PAWN: u" \u2659 ",
Square.LIGHT_KING: u" \u2654 ",
Square.DARK_PAWN: u" \u265F ",
Square.DARK_KING: u" \u265A ",
}
# Go row by row, printing out the row number and the board's state.
for row in xrange(0, self.board_size):
if row < 9:
output = u'{}{} '.format(output, row + 1)
else:
output = u'{}{} '.format(output, row + 1)
# Get current row's state.
for col in xrange(0, self.board_size):
output = output + output_atom[self._board[row][col]]
output = output + "\n"
return output

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

@ -0,0 +1,256 @@
#
# 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!
#
def canJump(game, sourceRow, sourceCol, targetRow, targetCol):
# TODO: Implement me.
# TODO: Make as private method.
return False
# /**
# * Returns if a piece can or cannot move. This move maybe either be a move
# * 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
# * 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.
# *
# * @param sourceRow
# * The row from where the piece is moving from.
# * @param sourceCol
# * The column from where the piece is moving from.
# * @param targetRow
# * The row to where the piece is moving to.
# * @param targetCol
# * The column to where the piece is moving to.
# * @return True if the piece can move. False if the piece can not move.
# */
def canMove(game, sourceRow, sourceCol, targetRow, targetCol):
# // A few things to figure out priorities in moving a piece.
legalMove = False
# // Is the proposed move/jump legal?
realPositions = False
# // Are the positions really on the board?
isJump = False
# // Is this a jump?
# // Sanity check.
if (game.getGameBoard().isLegalPosition(sourceRow, sourceCol)
and game.getGameBoard().isLegalPosition(targetRow, targetCol)):
realPositions = True
# // Is there a jump in progress?
if (realPositions and game.getJumpInProgress() != None):
# // Only allow the piece in movement to be moved.
if (sourceRow == game.getJumpInProgress().getY()
and sourceCol == game.getJumpInProgress().getX()):
legalMove = canJump(game, sourceRow, sourceCol, targetRow,
targetCol)
isJump = True
elif (realPositions):
# // Go with the regular flow, jumps first then "slides".
isJump = canPlayerJump(game)
if isJump:
legalMove = canJump(game, sourceRow, sourceCol, targetRow,
targetCol)
else:
legalMove = canSlide(game, sourceRow, sourceCol, targetRow,
targetCol)
return legalMove
def canPlayerJump(game):
# // TODO: Implement me.
# TODO Make as private method
return False
def canSlide(game, sourceRow, sourceCol, targetRow, targetCol):
# TODO Make private
legalMove = True
mustJump = canPlayerJump(game)
# // Is the move even on the board?
legalMove = game.getGameBoard().isLegalPosition(sourceRow, sourceCol)\
and game.getGameBoard().isLegalPosition(targetRow, targetCol)
# // See if the destination is even empty.
if (legalMove):
legalMove = game.getGameBoard().isEmpty(targetRow, targetCol)
# // If yes, then look if right pieces were chosen.
if (legalMove and not mustJump):
if (game.isLightPlayerTurn() and game.getGameBoard().isLight(sourceRow, sourceCol)):
# // To deal with flying kings.
if (game.getGameBoard().isKing(sourceRow, sourceCol)
and game.getGameRules().canKingsFly()):
# // FIXME: Fix this!
pass
else:
# // if ((Math.abs(targetRow - sourceRow) == 1) && (Math.abs(targetRow - sourceRow) == 1)) {
# // legalMove = false;
# // Is the path clear for that move?
pass
elif (not game.isLightPlayerTurn() and game.getGameBoard().isDark(sourceRow, sourceCol)):
# //TODO: Implement me, sometime.
pass
else:
legalMove = False
return legalMove;
def checkForVictory(game):
# // TODO: Implement me.
pass
# /**
# * 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
# * used by the graphical user interface to determine if a piece can be moved
# * either for sliding or jumping. The method is aware of whose turn is it to
# * move.
# *
# * @param row
# * The row coordinate of the piece to check.
# * @param col
# * The column coordinate of the piece to check.
# * @return Returns True if the piece can slide or jump in this turn.
# */
def isMovablePiece(game, row, col):
# // Fields for determining of a piece is movable.
moveUpLeft = True
moveUpRight = True
moveDownLeft = True
moveDownRight = True
# /*
# * Checks first if the first colour of piece is being grabbed. Next if
# * the piece is blocked by its own pieces. Next if the opponent has
# * double blocked off the pieces. Also sanity checks if looking past the
# * size of the board.
# */
if (game.isLightPlayerTurn() and game.getGameBoard().isLight(row, col)):
# // Light player.
# // Can piece move normally?
moveDownLeft = canSlide(game, row, col, row + 1, col - 1)
moveDownRight = canSlide(game, row, col, row + 1, col + 1)
if (game.getGameBoard().isKing(row, col)):
moveUpLeft = canSlide(game, row, col, row - 1, col - 1)
moveUpRight = canSlide(game, row, col, row - 1, col + 1)
else:
moveUpLeft = False
moveUpRight = False
# // If no slides available try doing the same except for jumps.
if (not moveDownLeft):
moveDownLeft = canJump(game, row, col, row + 2, col - 2)
elif (not moveDownRight):
moveDownRight = canJump(game, row, col, row + 2, col + 2)
elif (game.getGameBoard().isKing(row, col)
or game.getGameRules().canPawnsJumpBackwards()):
if (not moveUpLeft):
moveUpLeft = canJump(game, row, col, row - 2, col + 2)
elif (not moveUpRight):
moveUpRight = canJump(game, row, col, row - 2, col - 2)
return moveUpLeft or moveUpRight or moveDownLeft or moveDownRight
elif (game.isLightPlayerTurn() and game.getGameBoard().isDark(row, col)):
# // Dark player
# // Can piece move normally?
moveUpLeft = canSlide(game, row, col, row - 1, col - 1)
moveUpRight = canSlide(game, row, col, row - 1, col + 1)
if (game.getGameBoard().isKing(row, col)):
moveDownLeft = canSlide(game, row, col, row + 1, col - 1)
moveDownRight = canSlide(game, row, col, row + 1, col + 1)
else:
moveDownLeft = False
moveDownRight = False
# // If no slides available try doing the same except for jumps.
if (not moveUpLeft):
moveUpLeft = canJump(game, row, col, row - 2, col - 2)
elif (not moveUpRight):
moveUpRight = canJump(game, row, col, row - 2, col + 2)
elif (game.getGameBoard().isKing(row, col)
or game.getGameRules().canPawnsJumpBackwards()):
if (not moveDownLeft):
moveDownLeft = canJump(game, row, col, row + 2, col + 2)
elif (not moveDownRight):
moveDownRight = canJump(game, row, col, row + 2, col - 2)
return moveUpLeft or moveUpRight or moveDownLeft or moveDownRight
else:
return False
# // A wrong coloured piece.
# /**
# * Moves a pieces from one location to another. This move maybe either be a
# * move or a jump. This method is called by a user interface when a user
# * 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.
# *
# * @param sourceRow
# * The row from where the piece is moving from.
# * @param sourceCol
# * The column from where the piece is moving from.
# * @param targetRow
# * The row to where the piece is moving to.
# * @param targetCol
# * The column to where the piece is moving to.
# */
def movePiece(game, sourceRow, sourceCol, targetRow, targetCol):
# // If everything checks out... move the piecenot
if (canMove(game, sourceRow, sourceCol, targetRow, targetCol)):
if (game.getJumpInProgress() != None):
# TODO: Implement jumping via removing of piece.
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

@ -0,0 +1,177 @@
#: import justcheckers justcheckers
ScreenManager:
MenuScreen:
GameScreen:
InfoScreen:
<MenuScreen@Screen>:
name: 'menu'
Image:
source: 'images/backdrop.jpg'
allow_stretch: True
BoxLayout:
orientation: "vertical"
Label:
size_hint_y: 0.1
Image:
source: 'images/logo.png'
size_hint_y: 0.25
allow_stretch: True
canvas.before:
Color:
rgba: 1, 1, 1, 0.5
Rectangle:
pos: self.pos
size: self.size
Label:
size_hint_y: 0.1
MainMenuButtonGroup:
size_hint_x: 0.9
pos_hint: {'center_x': 0.5}
Label:
text: "Version {}".format(justcheckers.__version__)
size_hint_y: 0.1
pos_hint: {'center_x': 0.9}
<MainMenuButtonGroup@BoxLayout>:
orientation: "vertical"
Button:
text: "New Game"
size_hint_y: 0.1
on_press:
root.parent.parent.manager.transition.direction = 'left'
root.parent.parent.manager.current = 'game'
Button:
text: "Open Game"
disabled: True
size_hint_y: 0.1
Button:
text: "Save Game"
disabled: True
size_hint_y: 0.1
Button:
text: "About Game"
size_hint_y: 0.1
on_press:
root.parent.parent.manager.transition.direction = 'left'
root.parent.parent.manager.current = 'info'
Button:
text: "Settings"
size_hint_y: 0.1
on_press:
app.open_settings()
Button:
text: "Exit"
size_hint_y: 0.1
on_press:
app.stop()
<GameScreen@Screen>:
name: 'game'
Image:
source: 'images/backdrop.jpg'
allow_stretch: True
BoxLayout:
orientation: "vertical"
Label:
size_hint_y: 0.1
BoxLayout:
orientation: "horizontal"
size_hint_x: 0.9
pos_hint: {'center_x': 0.5}
GameBoard:
id: game_board
size_hint_x: 0.75
BoxLayout:
id: player_stats
size_hint_x: 0.25
orientation: "vertical"
Button:
text: "Player 1"
Button:
text: "Player 2"
Label:
size_hint_y: 0.1
BoxLayout:
orientation: "horizontal"
size_hint_x: 0.9
size_hint_y: 0.1
pos_hint: {'center_x': 0.5}
Button:
text: "Back to Menu"
on_press:
root.manager.transition.direction = 'right'
root.manager.current = 'menu'
Label:
size_hint_y: 0.1
<InfoScreen@Screen>:
name: 'info'
documentation: "credits"
Image:
source: 'images/backdrop.jpg'
allow_stretch: True
BoxLayout:
orientation: "vertical"
Label:
size_hint_y: 0.1
RstDocument:
source: "assets/{}.md".format(root.documentation)
size_hint_y: 0.75
size_hint_x: 0.9
pos_hint: {'center_x': 0.5}
Label:
size_hint_y: 0.1
BoxLayout:
orientation: "horizontal"
size_hint_x: 0.9
size_hint_y: 0.1
pos_hint: {'center_x': 0.5}
Button:
text: "Back to Menu"
on_press:
root.manager.transition.direction = 'right'
root.manager.current = 'menu'
ToggleButton:
id: toggle_credits
text: "Credits"
state: "down" if root.documentation == 'credits' else "normal"
group: "info"
on_state:
if self.state == 'down': root.documentation = 'credits'
ToggleButton
id: toggle_license
text: "License"
group: "info"
state: "down" if root.documentation == 'license' else "normal"
on_state:
if self.state == 'down': root.documentation = 'license'
Label:
size_hint_y: 0.1
<GameBoard@GridLayout>:
rows: 8
cols: 8
# TODO: Make sure the grid height and width is a fraction of the screen.
row_force_default: True
row_default_height: 50
col_force_default: True
col_default_width: 50
<GameTile@RelativeLayout>:
tile_state: "play"
tile_coords: 0, 0
tile_image: image
tile_label: label
Image:
id: image
allow_stretch: True
Label:
id: label
color: [1, 0, 0, 0.75]
font_size: "20sp"

18
main.cpp Normal file
View File

@ -0,0 +1,18 @@
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
#if defined(Q_OS_WIN)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}

5
main.py Normal file
View File

@ -0,0 +1,5 @@
from justcheckers import app
if __name__ == '__main__':
app.JustCheckersApp().run()

22
main.qml Normal file
View File

@ -0,0 +1,22 @@
import QtQuick 2.9
import QtQuick.Controls 2.1
ApplicationWindow {
id: mainWindow
property var appVersion: "0.4.0"
visible: true
width: 540
height: 960
title: qsTr("justCheckers v" + appVersion)
Loader {
id: appPage
source: "Menu.qml"
anchors.fill: parent
property var version: appVersion
}
}

21
qml.qrc Normal file
View File

@ -0,0 +1,21 @@
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>Board.qml</file>
<file>Menu.qml</file>
<file>images/attack_king.png</file>
<file>images/attack_pawn.png</file>
<file>images/backdrop.jpg</file>
<file>images/defend_king.png</file>
<file>images/defend_pawn.png</file>
<file>images/icon.png</file>
<file>images/idea.png</file>
<file>images/logo.png</file>
<file>images/non_play.png</file>
<file>images/play.png</file>
<file>images/splash.jpg</file>
<file>MenuButton.qml</file>
<file>assets/ping.wav</file>
<file>qtquickcontrols2.conf</file>
</qresource>
</RCC>

9
qtquickcontrols2.conf Normal file
View File

@ -0,0 +1,9 @@
[Controls]
Style=Material
[Material]
Theme=Dark
[Material\Font]
Family=Open Sans
PixelSize=32

View File

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

65
setup.py Normal file
View File

@ -0,0 +1,65 @@
#!/usr/bin/env python
# coding=utf-8
import re
from setuptools import setup, find_packages
def gather_requirements(filename='requirements.txt'):
"""
Gather the requirements from a requirements file.
:param filename: The name of the file.
"""
with open(filename) as req_file:
raw_requirements = req_file.readlines()
return [requirement.strip()
for requirement in raw_requirements
if requirement.strip() and not re.match('#|-(?!e)', requirement)]
setup(
name='justcheckers',
version='0.5.0',
url='http://justcheckers.org/',
license='GPL v3',
author='Dorian Pula',
author_email='dorian.pula@gmail.com',
description='An advanced cross-platform checkers game.',
install_requires=gather_requirements(),
extras_requires={
'web': gather_requirements('requirements/web.txt'),
},
packages=find_packages(exclude=['tests']),
include_package_data=True,
entry_points={
'console_scripts': [
'justcheckers = justcheckers.app:main',
]
},
classifiers=[
'Development Status :: 3 - Alpha',
'Environment :: Console',
'Environment:: MacOS',
'Environment :: Web Environment',
'Environment :: Win32 (MS Windows)',
'Environment :: X11 Applications :: Qt',
'Intended Audience:: End Users / Desktop',
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
'Operating System :: MacOS :: MacOS X',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX :: Linux',
'Operating System :: Unix',
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.3',
'Topic :: Games/Entertainment',
'Topic :: Games/Entertainment :: Board Games',
],
)

61
tasks.py Normal file
View File

@ -0,0 +1,61 @@
import os
from os import path
import shutil
from invoke import task, run
@task
def run_game(ctx):
run('python main.py')
@task
def clean(ctx):
"""Clean generated files."""
run('rm *.pyc')
@task
def docs(ctx):
"""Creates the HTML documentation through Sphinx."""
build_dirs = ['docs/_api', 'docs/_build']
for build_dir in build_dirs:
if not path.exists(build_dir):
os.mkdir(build_dir)
run('sphinx-apidoc -o docs/_api rookeries')
run('sphinx-build -b html docs docs/_build')
@task
def clean_docs(ctx):
"""Clean up the generated Sphinx documentation."""
sphinx_api_docs_dir = os.path.join(os.curdir, 'docs', '_api')
if os.path.exists(sphinx_api_docs_dir):
shutil.rmtree(sphinx_api_docs_dir)
sphinx_build_docs_dir = os.path.join(os.curdir, 'docs', '_build')
if os.path.exists(sphinx_build_docs_dir):
shutil.rmtree(sphinx_build_docs_dir)
@task
def test_style(ctx):
"""Test the coding style using Flake8."""
run('flake8')
@task
def build_package(ctx):
"""Prepares the project for packaging."""
run('python setup.py sdist')
@task
def clean_package(ctx):
"""Cleans up generated files after packaging the project."""
packaging_dirs = [os.path.join(os.curdir, packaging) for packaging in ['justcheckers.egg-info', 'dist']]
for packaging in packaging_dirs:
if os.path.exists(packaging):
print("Removing '{}'".format(packaging))
shutil.rmtree(packaging)

View File

@ -1,132 +0,0 @@
/*
Gradle Build for justCheckers - Web
---------------------------------------------
Author: Dorian Pula (dorian.pula@amber-penguin-software.ca)
License: AGPL v3.
Gradle docs:
http://www.gradle.org/docs/current/userguide/userguide_single.html
*/
sourceCompatibility = 1.6
targetCompatibility = 1.6
// Description of the project
description = 'justCheckers'
version = '0.3'
apply plugin: 'war'
apply plugin: 'jetty'
sourceCompatibility = 1.6
targetCompatibility = 1.6
// Description of the project
description = 'justcheckers-web'
version = '0.3'
project.ext {
appName = 'justcheckers-web'
appBaseName = "justcheckers"
hibernateVersion = '3.5.4-Final'
slf4jVersion = '1.7.5'
springVersion = '3.1.3.RELEASE'
}
// Setup build script repositories starting with Maven repositories
repositories {
maven {
url 'http://repo1.maven.org/maven2'
}
}
// Dependency management
dependencies {
compile project(':core')
// Spring Framework + SLF4J
compile ('org.springframework:spring-context:' + project.springVersion) {
exclude module: 'commons-logging'
}
compile 'log4j:log4j:1.2.16'
compile 'org.slf4j:jcl-over-slf4j:' + project.slf4jVersion
compile 'org.slf4j:slf4j-api:' + project.slf4jVersion
compile 'org.slf4j:slf4j-log4j12:' + project.slf4jVersion
compile 'org.springframework:spring-jdbc:' + project.springVersion
compile 'org.springframework:spring-orm:' + project.springVersion
compile 'org.springframework:spring-webmvc:' + project.springVersion
compile 'org.springframework:spring-parent:' + project.springVersion
// xstream
compile 'com.thoughtworks.xstream:xstream:1.4.4'
// Hibernate + C3P0
compile 'org.hibernate:hibernate:' + project.hibernateVersion
compile 'org.hibernate:hibernate-annotations:' + project.hibernateVersion
compile 'org.hibernate:hibernate-c3p0:' + project.hibernateVersion
compile 'javassist:javassist:3.9.0.GA'
// FlexJson
compile 'net.sf.flexjson:flexjson:2.1'
// Javax Servlet and Mail APIs
providedCompile 'javax.servlet:servlet-api:2.5'
}
// At the end of day we just need a JAR and a WAR.
ext.sharedManifest = manifest {
attributes(
'App-Name' : project.appName,
'App-Version' : version,
'Build-User' : System.properties['user.name'],
'Build-Time' : new Date().format('yyyy-MMMM-dd HH:mm:ss'),
'Build-OS' : System.properties['os.name'] + ' - version ' + System.properties['os.version'],
'Build-Sys' : System.properties['os.arch'],
'Java-Version' : System.properties['java.version'],
'Java-Vendor' : System.properties['java.vendor'],
'Java-VM' :
System.properties['java.vm.vendor'] + ' ' + System.properties['java.vm.name'] + ' v'
+ System.properties['java.vm.version'])
}
// Build the JAR.
jar {
enabled = true
includeEmptyDirs = false
manifest = sharedManifest
include '**/**.class'
exclude 'build/**'
}
// Build WAR files that include the JAR file. Add the resources back in.
war {
from 'webapp'
exclude 'WEB-INF/lib'
classpath = project.configurations.runtime - project.configurations.providedRuntime + jar.outputs.files
manifest = sharedManifest
includeEmptyDirs = false
into('WEB-INF/classes') {
from sourceSets.main.resources
}
}
jettyRun {
httpPort = 8080
contextPath = project.appBaseName
webAppSourceDirectory = new File('webapp')
}
// Run embedded Jetty setup.
jettyRunWar {
httpPort = 8080
contextPath = project.appBaseName
}