// Cloned by junhao zhao on 30 Nov 2022 from World "Two Player Draughts" by Graham Bartley
// Please leave this clone trail here.
/*
=============================== Two Player Draughts World ===============================
Written by Graham Edmond Bartley for CA318: Advanced Algorithms and AI Search
----------- General Description -----------
This world models a two player game of English Draughts and all input to control it comes from the keyboard.
English draughts rules are as follows:
- 8 x 8 board size
- 12 white draughts
- 12 black draughts
- black goes first
- "men" draughts can only move diagonally one square forward
- "king" draughts can only move diagonally one square forward or backward
- "men" draughts become "kings" when they reach the furthest line forward they can go
- capture enemy pieces by "jumping" over them
- multiple captures can be executed in a row if possible to do so
- game ends when one player runs out of draughts or can no longer make a valid move
----------- Controls -----------
UP ARROW moves the current selector up one space
DOWN ARROW moves the current selector down one space
LEFT ARROW moves the current selector left one space
RIGHT ARROW moves the current selector right one space
NUMPAD 1 selects the draught at the current selector location
NUMPAD 2 moves the selected draught to the current selector location /
captures the enemy draught at the current selector location and places the selected draught appropriately
----------- Features & Issues -----------
Features:
- 8 x 8 size draughts board
- 12 white draughts & 12 black draughts
- black goes first
- world implements turn changes and tracks number of turns
- player 1 selector is only shown on player 1's turn and likewise for player 2
- "men" draughts can only move diagonally one square forward
- "king" draughts can only move diagonally one square forward or backward
- "men" draughts become "kings" when they reach the furthest line forward they can go
- "king" draughts have a different texture
- capture enemy pieces by selecting to move onto them, world will place you as if you jumped over them
- selectors and draughts cannot move out of bounds (unless no longer in play)
- when draughts are captured, they are placed on either side of the board in a line
- the line of captured draughts wraps around so as not to go off screen
- if all draughts of a particular colour have been captured, the game will end and a message will say that the player with the opposite colour will have won the game
Issues:
- does not implement the functionality of allowing for multiple valid captures in one turn.
- will not directly terminate if no more valid moves can be made but will eventually terminate by time out (after ~16.6 mins total runtime)
----------- Image Sources -----------
kings: https://cdn.pixabay.com/photo/2012/04/18/00/41/chess-36306_960_720.png
border: https://s-media-cache-ak0.pinimg.com/236x/62/15/13/6215134941540ac55f842953fc3fcd88.jpg
world image: https://cnet3.cbsistatic.com/img/vifGx5HKGIWwXx1l7XkPm2ZOd9w=/770x433/2007/07/20/407755d8-f4d7-11e2-8c7c-d4ae52e62bcc/checkers_board.jpg
draughts: https://www.colourbox.com/preview/2253423-draughts-pieces-isolated-on-white-background.jpg
space skybox: http://en.spaceengine.org/forum/21-514-1
*/
// World must define these:
const CLOCKTICK = 100; // speed of run - move things every n milliseconds
const MAXSTEPS = 10000; // length of a run before timing out (16.6 mins)
//---- global constants: -------------------------------------------------------
const gridsize = 10; // number of squares along side of world
const NOBOXES = (gridsize - 2) * (gridsize - 2);
// density of WhiteDraught - number of internal boxes
const squaresize = 1000; // size of square in pixels
const MAXPOS = gridsize * squaresize; // length of one side in pixels
const SKYCOLOR = 0xddffdd; // a number, not a string
const BLANKCOLOR = SKYCOLOR; // make objects this color until texture arrives (from asynchronous file read)
const show3d = false; // Switch between 3d and 2d view (both using Three.js)
const startRadiusConst = MAXPOS * 0.8; // distance from centre to start the camera at
const skyboxConst = MAXPOS * 3; // where to put skybox
const maxRadiusConst = MAXPOS * 10; // maximum distance from camera we will render things
//--- Mind can pick one of these actions -----------------
const ACTION_LEFT = 0;
const ACTION_RIGHT = 1;
const ACTION_UP = 2;
const ACTION_DOWN = 3;
const ACTION_STAYSTILL = 4;
const ACTION_ASELECTDRAUGHT = 5;
const ACTION_AMAKEMOVE = 6;
const ACTION_ESELECTDRAUGHT = 7;
const ACTION_EMAKEMOVE = 8;
// in initial view, (smaller-larger) on i axis is aligned with (left-right)
// in initial view, (smaller-larger) on j axis is aligned with (away from you - towards you)
// contents of a grid square
const GRID_BLANK = 0;
const GRID_WALL = 1;
// who's turn is it?
const AGENT_TURN = 0;
const ENEMY_TURN = 1;
//enemy goes first
var turn = ENEMY_TURN;
//keeps track of the number of draughts that have been captured
var capturedWhiteDraughts = 0;
var capturedBlackDraughts = 0;
//---- start of World class -------------------------------------------------------
function World() {
//-----Draught class---------
function Draught (obj, i, j) {
this.obj = obj;
this.i = i;
this.j = j;
this.isKing = false;
}
// most of World can be private
// regular "var" syntax means private variables:
var BOXHEIGHT; // 3d or 2d box height
var GRID = new Array(gridsize); // can query GRID about whether squares are occupied, will in fact be initialised as a 2D array
var WALLS = new Array(4 * gridsize); // need to keep handles to wall and WhiteDraught objects so can find them later to paint them
var theagent, theenemy;
//12 of each colour draught
var whitedraughts = new Array(12);
var blackdraughts = new Array(12);
//agent position on squares
var ai, aj;
//enemy position on squares
var ei, ej;
//position of selected agent draught
var selectedAgentDraughti = -1;
var selectedAgentDraughtj = -1;
//position of selected enemy draught
var selectedEnemyDraughti = -1;
var selectedEnemyDraughtj = -1;
//keeps track of where to put captured draughts
var capturedWhiteDraughtj = 0;
var capturedBlackDraughtj = 0;
var capturedBlackDraughti = 11;
var capturedWhiteDraughti = -2;
var turns;
var self = this; // needed for private fn to call public fn - see below
// regular "function" syntax means private functions:
function initGrid() {
for (var i = 0; i < gridsize; i++) {
GRID[i] = new Array(gridsize); // each element is an array
for (var j = 0; j < gridsize; j++) {
GRID[i][j] = GRID_BLANK;
}
}
}
function occupied(i, j) // is this square occupied
{ // variable objects
if (GRID[i][j] == GRID_WALL) return true; // fixed objects
return false;
}
//returns true if i,j is out of bounds
function isOutOfBounds(i, j) {
return ((i < 1 || i > 8) || (j < 1 || j > 8));
}
// logically, coordinates are: y=0, x and z all positive (no negative)
// logically my dimensions are all positive 0 to MAXPOS
// to centre everything on origin, subtract (MAXPOS/2) from all dimensions
function translate(x) {
return (x - (MAXPOS / 2));
}
//--- skybox ----------------------------------------------------------------------------------------------
function initSkybox() {
// x,y,z positive and negative faces have to be in certain order in the array
var materialArray = [
(new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture("/uploads/starter/sky_pos_z.jpg"),
side: THREE.BackSide
})),
(new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture("/uploads/starter/sky_neg_z.jpg"),
side: THREE.BackSide
})),
(new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture("/uploads/starter/sky_pos_y.jpg"),
side: THREE.BackSide
})),
(new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture("/uploads/starter/sky_neg_y.jpg"),
side: THREE.BackSide
})),
(new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture("/uploads/starter/sky_pos_x.jpg"),
side: THREE.BackSide
})),
(new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture("/uploads/starter/sky_neg_x.jpg"),
side: THREE.BackSide
})),
];
var skyGeometry = new THREE.CubeGeometry(skyboxConst, skyboxConst, skyboxConst);
var skyMaterial = new THREE.MeshFaceMaterial(materialArray);
var theskybox = new THREE.Mesh(skyGeometry, skyMaterial);
threeworld.scene.add(theskybox); // We are inside a giant cube
}
// --- asynchronous load textures from file ----------------------------------------
// loader return can call private function
function loadTextures() {
//border texture
var loader1 = new THREE.TextureLoader();
loader1.load('/uploads/bartleg3/wood.jpg', function(thetexture) {
thetexture.minFilter = THREE.LinearFilter;
paintWalls(new THREE.MeshBasicMaterial({
map: thetexture
}));
});
//white draught "man" texture
var loader2 = new THREE.TextureLoader();
loader2.load('/uploads/bartleg3/whitedraught.jpg', function(thetexture) {
thetexture.minFilter = THREE.LinearFilter;
paintWhiteDraughts(new THREE.MeshBasicMaterial({
map: thetexture
}));
});
//black draught "man" texture
var loader3 = new THREE.TextureLoader();
loader3.load('/uploads/bartleg3/blackdraught.jpg', function(thetexture) {
thetexture.minFilter = THREE.LinearFilter;
paintBlackDraughts(new THREE.MeshBasicMaterial({
map: thetexture
}));
});
//white draught "king" texture
var loader4 = new THREE.TextureLoader();
loader4.load('/uploads/bartleg3/whiteking.png', function(thetexture) {
thetexture.minFilter = THREE.LinearFilter;
paintWhiteKingDraughts(new THREE.MeshBasicMaterial({
map: thetexture
}));
});
//black draught "king" texture
var loader5 = new THREE.TextureLoader();
loader5.load('/uploads/bartleg3/blackking.png', function(thetexture) {
thetexture.minFilter = THREE.LinearFilter;
paintBlackKingDraughts(new THREE.MeshBasicMaterial({
map: thetexture
}));
});
//player 2 selector texture
var loader6 = new THREE.TextureLoader();
loader6.load('/uploads/bartleg3/p2.png', function(thetexture) {
thetexture.minFilter = THREE.LinearFilter;
theagent.material = new THREE.MeshBasicMaterial({
map: thetexture
});
});
//player 1 selector texture
var loader7 = new THREE.TextureLoader();
loader7.load('/uploads/bartleg3/p1.png', function(thetexture) {
thetexture.minFilter = THREE.LinearFilter;
theenemy.material = new THREE.MeshBasicMaterial({
map: thetexture
});
});
}
// --- add fixed objects ----------------------------------------
function initLogicalWalls() // set up logical walls in data structure, whether doing graphical run or not
{
for (var i = 0; i < gridsize; i++)
for (var j = 0; j < gridsize; j++)
if ((i === 0) || (i == gridsize - 1) || (j === 0) || (j == gridsize - 1)) {
GRID[i][j] = GRID_WALL;
}
}
function initThreeWalls() // graphical run only, set up blank boxes, painted later
{
var t = 0;
for (var i = 0; i < gridsize; i++)
for (var j = 0; j < gridsize; j++)
if (GRID[i][j] == GRID_WALL) {
var shape = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize);
var thecube = new THREE.Mesh(shape);
thecube.material.color.setHex(BLANKCOLOR);
thecube.position.x = translate(i * squaresize); // translate my simple (i,j) block-numbering coordinates to three.js (x,y,z) coordinates
thecube.position.z = translate(j * squaresize);
thecube.position.y = 0;
threeworld.scene.add(thecube);
WALLS[t] = thecube; // save it for later
t++;
}
}
function paintWalls(material) {
for (var i = 0; i < WALLS.length; i++) {
if (WALLS[i]) WALLS[i].material = material;
}
}
// --- enemy functions -----------------------------------
function drawEnemy() // given ei, ej, draw it
{
var x = translate(ei * squaresize);
var z = translate(ej * squaresize);
var y = 0;
theenemy.position.x = x;
theenemy.position.y = y;
theenemy.position.z = z;
threeworld.scene.add(theenemy);
}
function initLogicalEnemy() {
ei = 1;
ej = 1;
}
function initThreeEnemy() {
var shape = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize);
theenemy = new THREE.Mesh(shape);
theenemy.material.color.setHex(BLANKCOLOR);
drawEnemy();
}
function moveLogicalEnemy(a) {
var i = ei;
var j = ej;
if (a == ACTION_LEFT) {
i--;
} else if (a == ACTION_RIGHT) {
i++;
} else if (a == ACTION_UP) {
j--;
} else if (a == ACTION_DOWN) {
j++;
} else if (a == ACTION_ESELECTDRAUGHT) {
enemySelectDraught();
} else if (a == ACTION_EMAKEMOVE) {
enemyMakeMove();
}
if (!occupied(i, j)) {
ei = i;
ej = j;
}
}
//selects the draught on the space currently occupied by the enemy
function enemySelectDraught() {
//if there's a black draught on this space, select it
if (isBlackDraught(ei, ej)) {
selectedEnemyDraughti = ei;
selectedEnemyDraughtj = ej;
}
}
//move the enemy's selected draught to the enemy's selected space
function enemyMakeMove() {
//if the enemy has selected a draught to move
if (selectedEnemyDraughti != -1 && selectedEnemyDraughtj != -1) {
var draught = blackdraughts[getBlackDraught(selectedEnemyDraughti, selectedEnemyDraughtj)];
//variables to hold new coords
var newi = -1;
var newj = -1;
//if the draught being moved is not a king
if (!draught.isKing) {
/*if the space the enemy is moving to doesn't have a black draught on it
and the space is one space forward diagonal of the current space of the draught it is moving*/
if (!isBlackDraught(ei, ej) && ((ei == (selectedEnemyDraughti + 1) || ei == (selectedEnemyDraughti - 1)) && ej == (selectedEnemyDraughtj + 1))) {
//if the enemy is capturing a white draught
if (isWhiteDraught(ei, ej)) {
//check which i direction to move in
if (ei == (selectedEnemyDraughti + 1)) {
newi = ei + 1;
} else {
newi = ei - 1;
}
//always forward since not a king
newj = ej + 1;
//if not moving out of bounds or onto another draught
if (!isOutOfBounds(newi, newj) && !isWhiteDraught(newi, newj) && !isBlackDraught(newi, newj)) {
//capture the white draught
removeWhiteDraught(getWhiteDraught(ei, ej));
draught.i = newi;
draught.j = newj;
//if this black draught has reached the other side, make it a King and load it's new texture
if (draught.j == 8) {
draught.isKing = true;
loadTextures();
}
//reset selection
selectedEnemyDraughti = -1;
selectedEnemyDraughtj = -1;
//turn change
turn = AGENT_TURN;
turns++;
}
} else {
draught.i = ei;
draught.j = ej;
//if this black draught has reached the other side, make it a King and load it's new texture
if (draught.j == 8) {
draught.isKing = true;
loadTextures();
}
//reset selection
selectedEnemyDraughti = -1;
selectedEnemyDraughtj = -1;
//turn change
turn = AGENT_TURN;
turns++;
}
}
//if the draught being moved is a king
} else {
/*if the space the enemy is moving to doesn't have a black draught on it
and the space is one space forward or backward diagonal of the current space of the draught it is moving*/
if (!isBlackDraught(ei, ej) && ((ei == (selectedEnemyDraughti + 1) || ei == (selectedEnemyDraughti - 1)) && (ej == (selectedEnemyDraughtj + 1) || ej == (selectedEnemyDraughtj - 1)))) {
//if the enemy is capturing a white draught
if (isWhiteDraught(ei, ej)) {
//check which i direction to move in
if (ei == (selectedEnemyDraughti + 1)) {
newi = ei + 1;
} else {
newi = ei - 1;
}
//check which j direction to move in
if (ej == (selectedEnemyDraughtj + 1)) {
newj = ej + 1;
} else {
newj = ej - 1;
}
//if not moving out of bounds or onto another draught
if (!isOutOfBounds(newi, newj) && !isWhiteDraught(newi, newj) && !isBlackDraught(newi, newj)) {
//capture the white draught
removeWhiteDraught(getWhiteDraught(ei, ej));
draught.i = newi;
draught.j = newj;
//reset selection
selectedEnemyDraughti = -1;
selectedEnemyDraughtj = -1;
//turn change
turn = AGENT_TURN;
turns++;
}
} else {
draught.i = ei;
draught.j = ej;
//reset selection
selectedEnemyDraughti = -1;
selectedEnemyDraughtj = -1;
//turn change
turn = AGENT_TURN;
turns++;
}
}
}
}
}
// --- agent functions -----------------------------------
function drawAgent() // given ai, aj, draw it
{
var x = translate(ai * squaresize);
var z = translate(aj * squaresize);
var y = 0;
theagent.position.x = x;
theagent.position.y = y;
theagent.position.z = z;
threeworld.scene.add(theagent);
threeworld.follow.copy(theagent.position); // follow vector = agent position (for camera following agent)
}
function initLogicalAgent() {
ai = 8;
aj = 8;
}
function initThreeAgent() {
var shape = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize);
theagent = new THREE.Mesh(shape);
theagent.material.color.setHex(BLANKCOLOR);
drawAgent();
}
// this is called by the infrastructure that gets action a from the Mind
function moveLogicalAgent(a) {
var i = ai;
var j = aj;
if (a == ACTION_LEFT) {
i--;
} else if (a == ACTION_RIGHT) {
i++;
} else if (a == ACTION_UP) {
j--;
} else if (a == ACTION_DOWN) {
j++;
} else if (a == ACTION_ASELECTDRAUGHT) {
agentSelectDraught();
} else if (a == ACTION_AMAKEMOVE) {
agentMakeMove();
}
if (!occupied(i, j)) {
ai = i;
aj = j;
}
}
//selects the draught the agent is on
function agentSelectDraught() {
//if there's a white draught on this space, select it
if (isWhiteDraught(ai, aj)) {
selectedAgentDraughti = ai;
selectedAgentDraughtj = aj;
}
}
//move the selected draught to the selected space
function agentMakeMove() {
/*if you have selected a draught to be moved*/
if (selectedAgentDraughti != -1 && selectedAgentDraughtj != -1) {
var draught = whitedraughts[getWhiteDraught(selectedAgentDraughti, selectedAgentDraughtj)];
//variables to hold new coords
var newi = -1;
var newj = -1;
//if the draught being moved is not a king
if (!draught.isKing) {
/*if the space you're moving to doesn't have a white draught on it,
and the space is one space forward diagonal of the current space of the draught you are moving*/
if (!isWhiteDraught(ai, aj) && ((ai == (selectedAgentDraughti + 1) || ai == (selectedAgentDraughti - 1)) && aj == (selectedAgentDraughtj - 1))) {
//if you are capturing a black draught
if (isBlackDraught(ai, aj)) {
//check which i direction to move in
if (ai == (selectedAgentDraughti + 1)) {
newi = ai + 1;
} else {
newi = ai - 1;
}
//j direction will always be forward because it's not a king
newj = aj - 1;
//if not moving out of bounds or onto another draught
if (!isOutOfBounds(newi, newj) && !isWhiteDraught(newi, newj) && !isBlackDraught(newi, newj)) {
//capture the black draught
removeBlackDraught(getBlackDraught(ai, aj));
draught.i = newi;
draught.j = newj;
//if this white draught has reached the other side, make it a King and load it's new texture
if (draught.j == 1) {
draught.isKing = true;
loadTextures();
}
//reset selection
selectedAgentDraughti = -1;
selectedAgentDraughtj = -1;
//turn change
turn = ENEMY_TURN;
turns++;
}
} else {
draught.i = ai;
draught.j = aj;
//if this white draught has reached the other side, make it a King and load it's new texture
if (draught.j == 1) {
draught.isKing = true;
loadTextures();
}
//reset selection
selectedAgentDraughti = -1;
selectedAgentDraughtj = -1;
//turn change
turn = ENEMY_TURN;
turns++;
}
}
//if the draught being moved is a king
} else {
/*if the space you're moving to doesn't have a white draught on it,
and the space is one space forward or backward diagonal of the current space of the draught you are moving*/
if (!isWhiteDraught(ai, aj) && ((ai == (selectedAgentDraughti + 1) || ai == (selectedAgentDraughti - 1)) && (aj == (selectedAgentDraughtj - 1) || (aj == (selectedAgentDraughtj + 1))))) {
//if you are capturing a black draught
if (isBlackDraught(ai, aj)) {
//check which i direction to move in
if (ai == (selectedAgentDraughti + 1)) {
newi = ai + 1;
} else {
newi = ai - 1;
}
//check which j direction to move in
if (aj == (selectedAgentDraughtj - 1)) {
newj = aj - 1;
} else {
newj = aj + 1;
}
//if not moving out of bounds or onto another draught
if (!isOutOfBounds(newi, newj) && !isWhiteDraught(newi, newj) && !isBlackDraught(newi, newj)) {
//capture the black draught
removeBlackDraught(getBlackDraught(ai, aj));
draught.i = newi;
draught.j = newj;
//reset selection
selectedAgentDraughti = -1;
selectedAgentDraughtj = -1;
//turn change
turn = ENEMY_TURN;
turns++;
}
} else {
draught.i = ai;
draught.j = aj;
//reset selection
selectedAgentDraughti = -1;
selectedAgentDraughtj = -1;
//turn change
turn = ENEMY_TURN;
turns++;
}
}
}
}
}
// user control
// Note that this.takeAction(a) is constantly running at same time, redrawing the screen.
function keyHandler(e) {
//if it's the agent's turn, respond to their input
if (turn == AGENT_TURN) {
if (e.keyCode == 37) moveLogicalAgent(ACTION_LEFT);
if (e.keyCode == 38) moveLogicalAgent(ACTION_UP);
if (e.keyCode == 39) moveLogicalAgent(ACTION_RIGHT);
if (e.keyCode == 40) moveLogicalAgent(ACTION_DOWN);
if (e.keyCode == 97) moveLogicalAgent(ACTION_ASELECTDRAUGHT);
if (e.keyCode == 98) moveLogicalAgent(ACTION_AMAKEMOVE);
}
//if it's the enemy's turn, respond to their input
if (turn == ENEMY_TURN) {
if (e.keyCode == 37) moveLogicalEnemy(ACTION_LEFT);
if (e.keyCode == 38) moveLogicalEnemy(ACTION_UP);
if (e.keyCode == 39) moveLogicalEnemy(ACTION_RIGHT);
if (e.keyCode == 40) moveLogicalEnemy(ACTION_DOWN);
if (e.keyCode == 97) moveLogicalEnemy(ACTION_ESELECTDRAUGHT);
if (e.keyCode == 98) moveLogicalEnemy(ACTION_EMAKEMOVE);
}
}
// --- status: -----------------------------------
function updateStatusBefore(a)
// this is called before anyone has moved on this step, agent has just proposed an action
// update status to show old state and proposed move
{
//if even turn number, then it's agent turn
if (turns % 2 == 0) {
var status = " Turn: <b> " + turns + " </b> Colour: <b>White</b> Controls: <b>Arrow Keys</b> - Move Selector, <b>NUMPAD 1</b> - Select Draught, <b>NUMPAD 2</b> - Make Move";
//otherwise it's enemy turn
} else {
var status = " Turn: <b> " + turns + " </b> Colour: <b>Black</b> Controls: <b>Arrow Keys</b> - Move Selector, <b>NUMPAD 1</b> - Select Draught, <b>NUMPAD 2</b> - Make Move";
}
$("#user_span3").html(status);
}
//--- draught functions --------------------------
//initializes all white draughts in their starting positions on the board
function initLogicalWhiteDraughts() {
whitedraughts[0] = new Draught(null, 1, 8);
whitedraughts[1] = new Draught(null, 3, 8);
whitedraughts[2] = new Draught(null, 5, 8);
whitedraughts[3] = new Draught(null, 7, 8);
whitedraughts[4] = new Draught(null, 2, 7);
whitedraughts[5] = new Draught(null, 4, 7);
whitedraughts[6] = new Draught(null, 6, 7);
whitedraughts[7] = new Draught(null, 8, 7);
whitedraughts[8] = new Draught(null, 1, 6);
whitedraughts[9] = new Draught(null, 3, 6);
whitedraughts[10] = new Draught(null, 5, 6);
whitedraughts[11] = new Draught(null, 7, 6);
}
//initializes the Three objects for all white draughts and draws them in the world
function initThreeWhiteDraughts() {
for (var i = 0; i < whitedraughts.length; i++) {
var shape = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize);
whitedraughts[i].obj = new THREE.Mesh(shape);
whitedraughts[i].obj.material.color.setHex(BLANKCOLOR);
}
drawWhiteDraughts();
}
//paints all white draughts with "men" status
function paintWhiteDraughts(material) {
for (var i = 0; i < whitedraughts.length; i++) {
if (whitedraughts[i].obj && !whitedraughts[i].isKing) whitedraughts[i].obj.material = material;
}
}
//paints all white draughts with "King" status
function paintWhiteKingDraughts(material) {
for (var i = 0; i < whitedraughts.length; i++) {
if (whitedraughts[i].obj && whitedraughts[i].isKing) whitedraughts[i].obj.material = material;
}
}
//draws all white draughts in their current position
function drawWhiteDraughts() {
for (var i = 0; i < whitedraughts.length; i++) {
var x = translate(whitedraughts[i].i * squaresize);
var z = translate(whitedraughts[i].j * squaresize);
var y = 0;
whitedraughts[i].obj.position.x = x;
whitedraughts[i].obj.position.y = y;
whitedraughts[i].obj.position.z = z;
threeworld.scene.add(whitedraughts[i].obj);
}
}
//initializes all black draughts in their starting positions on the board
function initLogicalBlackDraughts() {
blackdraughts[0] = new Draught(null, 2, 3);
blackdraughts[1] = new Draught(null, 4, 3);
blackdraughts[2] = new Draught(null, 6, 3);
blackdraughts[3] = new Draught(null, 8, 3);
blackdraughts[4] = new Draught(null, 1, 2);
blackdraughts[5] = new Draught(null, 3, 2);
blackdraughts[6] = new Draught(null, 5, 2);
blackdraughts[7] = new Draught(null, 7, 2);
blackdraughts[8] = new Draught(null, 2, 1);
blackdraughts[9] = new Draught(null, 4, 1);
blackdraughts[10] = new Draught(null, 6, 1);
blackdraughts[11] = new Draught(null, 8, 1);
}
//initializes the Three objects for all black draughts and draws them in the world
function initThreeBlackDraughts() {
for (var i = 0; i < blackdraughts.length; i++) {
var shape = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize);
blackdraughts[i].obj = new THREE.Mesh(shape);
blackdraughts[i].obj.material.color.setHex(BLANKCOLOR);
}
drawBlackDraughts();
}
//paints all black draughts with "men" status
function paintBlackDraughts(material) {
for (var i = 0; i < blackdraughts.length; i++) {
if (blackdraughts[i].obj && !blackdraughts[i].isKing) blackdraughts[i].obj.material = material;
}
}
//paints all black draughts with "King" status
function paintBlackKingDraughts(material) {
for (var i = 0; i < blackdraughts.length; i++) {
if (blackdraughts[i].obj && blackdraughts[i].isKing) blackdraughts[i].obj.material = material;
}
}
//draws all black draughts in their current position
function drawBlackDraughts() {
for (var i = 0; i < blackdraughts.length; i++) {
var x = translate(blackdraughts[i].i * squaresize);
var z = translate(blackdraughts[i].j * squaresize);
var y = 0;
blackdraughts[i].obj.position.x = x;
blackdraughts[i].obj.position.y = y;
blackdraughts[i].obj.position.z = z;
threeworld.scene.add(blackdraughts[i].obj);
}
}
//returns true if a white draught exists at i,j
function isWhiteDraught(i, j) {
for (var k = 0; k < whitedraughts.length; k++) {
if (whitedraughts[k].i == i) {
if (whitedraughts[k].j == j) {
return true;
}
}
}
return false;
}
//returns true if a black draught exists at i,j
function isBlackDraught(i, j) {
for (var k = 0; k < blackdraughts.length; k++) {
if (blackdraughts[k].i == i) {
if (blackdraughts[k].j == j) {
return true;
}
}
}
return false;
}
//returns the index of a white draught existing at i,j
function getWhiteDraught(i, j) {
for (var k = 0; k < whitedraughts.length; k++) {
if (whitedraughts[k].i == i) {
if (whitedraughts[k].j == j) {
return k;
}
}
}
}
//returns the index of a black draught existing at i,j
function getBlackDraught(i, j) {
for (var k = 0; k < blackdraughts.length; k++) {
if (blackdraughts[k].i == i) {
if (blackdraughts[k].j == j) {
return k;
}
}
}
}
//removes a black draught, located at index, from the board
function removeBlackDraught(index) {
//if out of bounds, move to next column
if (capturedBlackDraughtj > 9) {
capturedBlackDraughtj = 0;
capturedBlackDraughti = 12;
}
blackdraughts[index].i = capturedBlackDraughti;
blackdraughts[index].j = capturedBlackDraughtj;
capturedBlackDraughtj++;
capturedBlackDraughts++;
}
//removes a white draught, located at index, from the board
function removeWhiteDraught(index) {
//if out of bounds, move to next column
if (capturedWhiteDraughtj > 9) {
capturedWhiteDraughtj = 0;
capturedWhiteDraughti = -3;
}
whitedraughts[index].i = capturedWhiteDraughti;
whitedraughts[index].j = capturedWhiteDraughtj;
capturedWhiteDraughtj++;
capturedWhiteDraughts++;
}
//--- public functions / interface / API ----------------------------------------------------------
this.endCondition; // If set to true, run will end.
this.newRun = function() {
// (subtle bug) must reset variables like these inside newRun (in case do multiple runs)
this.endCondition = false;
var agentWon = false;
turns = 1;
// for all runs:
initGrid();
initLogicalWalls();
initLogicalWhiteDraughts();
initLogicalBlackDraughts();
initLogicalAgent();
initLogicalEnemy();
// for graphical runs only:
if (true) {
if (show3d) {
BOXHEIGHT = squaresize;
threeworld.init3d(startRadiusConst, maxRadiusConst, SKYCOLOR);
} else {
BOXHEIGHT = 1;
threeworld.init2d(startRadiusConst, maxRadiusConst, SKYCOLOR);
}
initSkybox();
// Set up objects first:
initThreeWalls();
initThreeWhiteDraughts();
initThreeBlackDraughts();
initThreeAgent();
initThreeEnemy();
// Then paint them with textures - asynchronous load of textures from files.
// The texture file loads return at some unknown future time in some unknown order.
// Because of the unknown order, it is probably best to make objects first and later paint them, rather than have the objects made when the file reads return.
// It is safe to paint objects in random order, but might not be safe to create objects in random order.
loadTextures();
//handle keypresses
document.onkeydown = keyHandler;
}
};
this.getState = function() {
var x = [ai, aj];
return (x);
};
this.takeAction = function(a) {
if (true)
updateStatusBefore(a); // show status line before moves
//input from mind
moveLogicalAgent(a);
if (true) {
//if it's the agent's turn, don't show the enemy
if (turn == AGENT_TURN) {
threeworld.scene.remove(theenemy);
drawAgent();
//otherwise, it's the enemy's turn so don't show the agent
} else {
threeworld.scene.remove(theagent);
drawEnemy();
}
drawWhiteDraughts();
drawBlackDraughts();
}
//if all enemy draughts have been taken
if (capturedBlackDraughts == 12)
{
agentWon = true;
this.endCondition = true;
}
//if all agent draughts have been taken
if (capturedWhiteDraughts == 12) {
agentWon = false;
this.endCondition = true;
}
};
this.endRun = function() {
if (true) {
if (this.endCondition) {
if (agentWon) {
$("#user_span6").html("<br></br> <font color=green> <B> Player 2 has won the game! </B> </font> ");
} else {
$("#user_span6").html("<br></br> <font color=green> <B> Player 1 has won the game! </B> </font> ");
}
}
else
$("#user_span6").html(" <font color=red> <B> Time has run out!. </B> </font> ");
}
};
this.getScore = function() {
return turns;
};
}
//---- end of World class -------------------------------------------------------
//end of Two Player Draughts World