whisper.cat stuff
This commit is contained in:
409
weboasis/arcade/chess/js/AI/boardui.js
Normal file
409
weboasis/arcade/chess/js/AI/boardui.js
Normal file
@ -0,0 +1,409 @@
|
||||
var g_startOffset = null;
|
||||
var g_selectedPiece = null;
|
||||
var moveNumber = 1;
|
||||
|
||||
var g_allMoves = [];
|
||||
var g_playerWhite = true;
|
||||
var g_changingFen = false;
|
||||
var g_analyzing = false;
|
||||
|
||||
var g_uiBoard;
|
||||
var g_cellSize = 45;
|
||||
|
||||
function UINewGame() {
|
||||
moveNumber = 1;
|
||||
|
||||
var pgnTextBox = document.getElementById("PgnTextBox"); //
|
||||
pgnTextBox.value = "";
|
||||
|
||||
EnsureAnalysisStopped(); // UI (terminate and destroy worker)
|
||||
ResetGame(); // shouldn't work
|
||||
if (InitializeBackgroundEngine()) {
|
||||
g_backgroundEngine.postMessage("go");
|
||||
}
|
||||
g_allMoves = [];
|
||||
RedrawBoard(); //UI
|
||||
|
||||
// if player is black play the first move
|
||||
if (!g_playerWhite) {
|
||||
SearchAndRedraw(); //UI
|
||||
}
|
||||
}
|
||||
|
||||
function EnsureAnalysisStopped() {
|
||||
if (g_analyzing && g_backgroundEngine != null) {
|
||||
g_backgroundEngine.terminate();
|
||||
g_backgroundEngine = null;
|
||||
}
|
||||
}
|
||||
|
||||
function UIAnalyzeToggle() {
|
||||
if (InitializeBackgroundEngine()) {
|
||||
if (!g_analyzing) {
|
||||
g_backgroundEngine.postMessage("analyze");
|
||||
} else {
|
||||
EnsureAnalysisStopped();
|
||||
}
|
||||
g_analyzing = !g_analyzing;
|
||||
document.getElementById("AnalysisToggleLink").innerText = g_analyzing ? "Analysis: On" : "Analysis: Off";
|
||||
} else {
|
||||
alert("Your browser must support web workers for analysis - (chrome4, ff4, safari)");
|
||||
}
|
||||
}
|
||||
|
||||
function UIChangeFEN() {
|
||||
if (!g_changingFen) {
|
||||
var fenTextBox = document.getElementById("FenTextBox");
|
||||
var result = InitializeFromFen(fenTextBox.value);
|
||||
if (result.length != 0) {
|
||||
UpdatePVDisplay(result);
|
||||
return;
|
||||
} else {
|
||||
UpdatePVDisplay('');
|
||||
}
|
||||
g_allMoves = [];
|
||||
|
||||
EnsureAnalysisStopped();
|
||||
InitializeBackgroundEngine();
|
||||
|
||||
g_playerWhite = !!g_toMove;
|
||||
g_backgroundEngine.postMessage("position " + GetFen());
|
||||
|
||||
RedrawBoard();
|
||||
}
|
||||
}
|
||||
|
||||
function UIChangeStartPlayer() {
|
||||
g_playerWhite = !g_playerWhite;
|
||||
RedrawBoard();
|
||||
}
|
||||
|
||||
function UpdatePgnTextBox(move) {
|
||||
var pgnTextBox = document.getElementById("PgnTextBox");
|
||||
if (g_toMove != 0) {
|
||||
pgnTextBox.value += moveNumber + ". ";
|
||||
moveNumber++;
|
||||
}
|
||||
pgnTextBox.value += GetMoveSAN(move) + " ";
|
||||
}
|
||||
|
||||
function UIChangeTimePerMove() {
|
||||
var timePerMove = document.getElementById("TimePerMove");
|
||||
g_timeout = parseInt(timePerMove.value, 10);
|
||||
}
|
||||
|
||||
function FinishMove(bestMove, value, timeTaken, ply) {
|
||||
if (bestMove != null) {
|
||||
UIPlayMove(bestMove, BuildPVMessage(bestMove, value, timeTaken, ply));
|
||||
} else {
|
||||
alert("Checkmate!");
|
||||
}
|
||||
}
|
||||
|
||||
function UIPlayMove(move, pv) {
|
||||
UpdatePgnTextBox(move);
|
||||
|
||||
g_allMoves[g_allMoves.length] = move;
|
||||
MakeMove(move);
|
||||
|
||||
UpdatePVDisplay(pv);
|
||||
|
||||
UpdateFromMove(move);
|
||||
}
|
||||
|
||||
|
||||
// buggy doesn't update the pgn properly
|
||||
function UIUndoMove() {
|
||||
if (g_allMoves.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_backgroundEngine != null) {
|
||||
g_backgroundEngine.terminate();
|
||||
g_backgroundEngine = null;
|
||||
}
|
||||
|
||||
UnmakeMove(g_allMoves[g_allMoves.length - 1]);
|
||||
g_allMoves.pop();
|
||||
|
||||
if (g_playerWhite !== !!g_toMove && g_allMoves.length !== 0) {
|
||||
UnmakeMove(g_allMoves[g_allMoves.length - 1]);
|
||||
g_allMoves.pop();
|
||||
}
|
||||
|
||||
RedrawBoard();
|
||||
}
|
||||
|
||||
function UpdatePVDisplay(pv) {
|
||||
if (pv != null) {
|
||||
var outputDiv = document.getElementById("output");
|
||||
if (outputDiv.firstChild != null) {
|
||||
outputDiv.removeChild(outputDiv.firstChild);
|
||||
}
|
||||
outputDiv.appendChild(document.createTextNode(pv));
|
||||
}
|
||||
}
|
||||
|
||||
function SearchAndRedraw() {
|
||||
if (g_analyzing) {
|
||||
EnsureAnalysisStopped();
|
||||
InitializeBackgroundEngine();
|
||||
g_backgroundEngine.postMessage("position " + GetFen());
|
||||
g_backgroundEngine.postMessage("analyze");
|
||||
return;
|
||||
}
|
||||
|
||||
if (InitializeBackgroundEngine()) {
|
||||
g_backgroundEngine.postMessage("search " + g_timeout);
|
||||
} else {
|
||||
Search(FinishMove, 99, null); // unasynchronous version fall back
|
||||
}
|
||||
}
|
||||
|
||||
var g_backgroundEngineValid = true;
|
||||
var g_backgroundEngine;
|
||||
|
||||
function InitializeBackgroundEngine() {
|
||||
if (!g_backgroundEngineValid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_backgroundEngine == null) {
|
||||
g_backgroundEngineValid = true;
|
||||
try {
|
||||
g_backgroundEngine = new Worker("js/garbochess.js");
|
||||
g_backgroundEngine.onmessage = function (e) {
|
||||
if (e.data.match("^pv") == "pv") {
|
||||
UpdatePVDisplay(e.data.substr(3, e.data.length - 3));
|
||||
} else if (e.data.match("^message") == "message") {
|
||||
EnsureAnalysisStopped();
|
||||
UpdatePVDisplay(e.data.substr(8, e.data.length - 8));
|
||||
} else {
|
||||
UIPlayMove(GetMoveFromString(e.data), null);
|
||||
}
|
||||
}
|
||||
g_backgroundEngine.error = function (e) {
|
||||
alert("Error from background worker:" + e.message);
|
||||
}
|
||||
g_backgroundEngine.postMessage("position " + GetFen());
|
||||
} catch (error) {
|
||||
g_backgroundEngineValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
return g_backgroundEngineValid;
|
||||
}
|
||||
|
||||
function UpdateFromMove(move) {
|
||||
var fromX = (move & 0xF) - 4;
|
||||
var fromY = ((move >> 4) & 0xF) - 2;
|
||||
var toX = ((move >> 8) & 0xF) - 4;
|
||||
var toY = ((move >> 12) & 0xF) - 2;
|
||||
|
||||
if (!g_playerWhite) {
|
||||
fromY = 7 - fromY;
|
||||
toY = 7 - toY;
|
||||
fromX = 7 - fromX;
|
||||
toX = 7 - toX;
|
||||
}
|
||||
|
||||
if ((move & moveflagCastleKing) ||
|
||||
(move & moveflagCastleQueen) ||
|
||||
(move & moveflagEPC) ||
|
||||
(move & moveflagPromotion)) {
|
||||
// more than one piece was moved
|
||||
// or one piece was modified
|
||||
// -> entire redraw
|
||||
RedrawPieces();
|
||||
} else {
|
||||
// simply swap piece parents
|
||||
var fromSquare = g_uiBoard[fromY * 8 + fromX];
|
||||
$(g_uiBoard[toY * 8 + toX])
|
||||
.empty()
|
||||
.append($(fromSquare).children());
|
||||
}
|
||||
}
|
||||
|
||||
function RedrawPieces() {
|
||||
for (y = 0; y < 8; ++y) {
|
||||
for (x = 0; x < 8; ++x) {
|
||||
var td = g_uiBoard[y * 8 + x];
|
||||
var pieceY = g_playerWhite ? y : 7 - y;
|
||||
var piece = g_board[((pieceY + 2) * 0x10) + (g_playerWhite ? x : 7 - x) + 4];
|
||||
var pieceName = null;
|
||||
switch (piece & 0x7) {
|
||||
case piecePawn: pieceName = "pawn"; break;
|
||||
case pieceKnight: pieceName = "knight"; break;
|
||||
case pieceBishop: pieceName = "bishop"; break;
|
||||
case pieceRook: pieceName = "rook"; break;
|
||||
case pieceQueen: pieceName = "queen"; break;
|
||||
case pieceKing: pieceName = "king"; break;
|
||||
}
|
||||
if (pieceName != null) {
|
||||
pieceName += "_";
|
||||
pieceName += (piece & 0x8) ? "white" : "black";
|
||||
}
|
||||
|
||||
if (pieceName != null) {
|
||||
var img = document.createElement("div");
|
||||
$(img).addClass('sprite-' + pieceName);
|
||||
img.style.backgroundImage = "url('img/sprites.png')";
|
||||
img.width = g_cellSize;
|
||||
img.height = g_cellSize;
|
||||
var divimg = document.createElement("div");
|
||||
divimg.appendChild(img);
|
||||
|
||||
$(divimg).draggable({ start: function (e, ui) {
|
||||
if (g_selectedPiece === null) {
|
||||
g_selectedPiece = this;
|
||||
var offset = $(this).closest('table').offset();
|
||||
g_startOffset = {
|
||||
left: e.pageX - offset.left,
|
||||
top: e.pageY - offset.top
|
||||
};
|
||||
} else {
|
||||
return g_selectedPiece == this;
|
||||
}
|
||||
}});
|
||||
|
||||
$(divimg).mousedown(function(e) {
|
||||
if (g_selectedPiece === null) {
|
||||
var offset = $(this).closest('table').offset();
|
||||
g_startOffset = {
|
||||
left: e.pageX - offset.left,
|
||||
top: e.pageY - offset.top
|
||||
};
|
||||
e.stopPropagation();
|
||||
g_selectedPiece = this;
|
||||
g_selectedPiece.style.backgroundImage = "url('img/transpBlue50.png')";
|
||||
} else if (g_selectedPiece === this) {
|
||||
g_selectedPiece.style.backgroundImage = null;
|
||||
g_selectedPiece = null;
|
||||
}
|
||||
});
|
||||
|
||||
$(td).empty().append(divimg);
|
||||
} else {
|
||||
$(td).empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function RedrawBoard() {
|
||||
var div = $("#board")[0];
|
||||
|
||||
var table = document.createElement("table");
|
||||
table.cellPadding = "0px";
|
||||
table.cellSpacing = "0px";
|
||||
$(table).addClass('no-highlight');
|
||||
|
||||
var tbody = document.createElement("tbody");
|
||||
|
||||
g_uiBoard = [];
|
||||
|
||||
var dropPiece = function (e, ui) {
|
||||
// retrive start -> end move
|
||||
var endX = e.pageX - $(table).offset().left;
|
||||
var endY = e.pageY - $(table).offset().top;
|
||||
|
||||
endX = Math.floor(endX / g_cellSize);
|
||||
endY = Math.floor(endY / g_cellSize);
|
||||
|
||||
var startX = Math.floor(g_startOffset.left / g_cellSize);
|
||||
var startY = Math.floor(g_startOffset.top / g_cellSize);
|
||||
|
||||
// convert coordinates to white-space
|
||||
if (!g_playerWhite) {
|
||||
startY = 7 - startY;
|
||||
endY = 7 - endY;
|
||||
startX = 7 - startX;
|
||||
endX = 7 - endX;
|
||||
}
|
||||
|
||||
// gather all possible valid moves
|
||||
var moves = GenerateValidMoves();
|
||||
var move = null;
|
||||
// check if the move is valid
|
||||
for (var i = 0; i < moves.length; i++) {
|
||||
if ((moves[i] & 0xFF) == MakeSquare(startY, startX) &&
|
||||
((moves[i] >> 8) & 0xFF) == MakeSquare(endY, endX)) {
|
||||
move = moves[i];
|
||||
}
|
||||
}
|
||||
|
||||
// convert coordinates back to black-space
|
||||
if (!g_playerWhite) {
|
||||
startY = 7 - startY;
|
||||
endY = 7 - endY;
|
||||
startX = 7 - startX;
|
||||
endX = 7 - endX;
|
||||
}
|
||||
|
||||
// put the html object back to its original position
|
||||
// whether the move is valid or not
|
||||
g_selectedPiece.style.left = 0;
|
||||
g_selectedPiece.style.top = 0;
|
||||
|
||||
if (!(startX == endX && startY == endY) && move != null) {
|
||||
// if the move is valid
|
||||
// we add the move to the png texbox
|
||||
UpdatePgnTextBox(move);
|
||||
|
||||
// we save the move in our worker
|
||||
if (InitializeBackgroundEngine()) {
|
||||
g_backgroundEngine.postMessage(FormatMove(move));
|
||||
}
|
||||
|
||||
// we add the move to the move list
|
||||
g_allMoves[g_allMoves.length] = move;
|
||||
|
||||
// we apply the move
|
||||
MakeMove(move);
|
||||
|
||||
UpdateFromMove(move);
|
||||
|
||||
// update the fen text box
|
||||
var fen = GetFen();
|
||||
document.getElementById("FenTextBox").value = fen;
|
||||
|
||||
setTimeout("SearchAndRedraw()", 0);
|
||||
}
|
||||
// whether the move is valid or not, we remove highlight and clear selection
|
||||
g_selectedPiece.style.backgroundImage = null;
|
||||
g_selectedPiece = null;
|
||||
};
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
var tr = document.createElement("tr");
|
||||
|
||||
for (x = 0; x < 8; ++x) {
|
||||
var td = document.createElement("td");
|
||||
td.style.width = g_cellSize + "px";
|
||||
td.style.height = g_cellSize + "px";
|
||||
td.style.backgroundColor = ((y ^ x) & 1) ? "#D18947" : "#FFCE9E";
|
||||
tr.appendChild(td);
|
||||
g_uiBoard[y * 8 + x] = td;
|
||||
}
|
||||
|
||||
tbody.appendChild(tr);
|
||||
}
|
||||
|
||||
table.appendChild(tbody);
|
||||
|
||||
$('body').droppable({ drop: dropPiece });
|
||||
$(table).mousedown(function(e) {
|
||||
if (g_selectedPiece !== null) {
|
||||
dropPiece(e);
|
||||
}
|
||||
});
|
||||
|
||||
RedrawPieces();
|
||||
|
||||
$(div).empty();
|
||||
div.appendChild(table);
|
||||
|
||||
g_changingFen = true;
|
||||
document.getElementById("FenTextBox").value = GetFen();
|
||||
g_changingFen = false;
|
||||
}
|
2738
weboasis/arcade/chess/js/AI/garbochess.js
Normal file
2738
weboasis/arcade/chess/js/AI/garbochess.js
Normal file
File diff suppressed because it is too large
Load Diff
2538
weboasis/arcade/chess/js/AI/garbochess_unclean.js
Normal file
2538
weboasis/arcade/chess/js/AI/garbochess_unclean.js
Normal file
File diff suppressed because it is too large
Load Diff
116
weboasis/arcade/chess/js/Cell.js
Normal file
116
weboasis/arcade/chess/js/Cell.js
Normal file
@ -0,0 +1,116 @@
|
||||
// ECMAScript 5 strict mode
|
||||
/* jshint globalstrict: true*/
|
||||
/* global THREE,BOARD_SIZE, COLS,ROWS*/
|
||||
"use strict";
|
||||
(function () {
|
||||
var a = "a".charCodeAt(0);
|
||||
function Cell() {
|
||||
this.position = null;
|
||||
this.index = null;
|
||||
this.x = null;
|
||||
this.y = null;
|
||||
var coordinates = null;
|
||||
if( arguments.length === 1) {
|
||||
|
||||
if (typeof(arguments[0]) === "string" && arguments[0].match(/[a-h][1-8]/) ) {
|
||||
// position like "a1", "b4", "e7"
|
||||
this.position = arguments[0];
|
||||
coordinates = getCoordinatesFromPosition(
|
||||
this.position
|
||||
);
|
||||
this.x = coordinates.x;
|
||||
this.y = coordinates.y;
|
||||
this.index = this.x + this.y * COLS;
|
||||
} else if (arguments[0] >= 0 && arguments[0] < ROWS*COLS) {
|
||||
// array index
|
||||
this.index = arguments[0];
|
||||
coordinates = getCoordinatesFromIndex(
|
||||
this.index
|
||||
);
|
||||
this.x = coordinates.x;
|
||||
this.y = coordinates.y;
|
||||
this.position = getPositionFromCoordinates(
|
||||
this.x,this.y
|
||||
);
|
||||
}
|
||||
} else if( arguments.length === 2 &&
|
||||
isValid(arguments[0],arguments[1]) ) {
|
||||
// x and y position (0-based
|
||||
this.x = arguments[0];
|
||||
this.y = arguments[1];
|
||||
this.index = this.x + this.y * COLS;
|
||||
this.position = getPositionFromCoordinates(
|
||||
this.x,this.y
|
||||
);
|
||||
} else {
|
||||
throw arguments[0];
|
||||
}
|
||||
}
|
||||
|
||||
Cell.prototype.toString = function() {
|
||||
return this.position;
|
||||
};
|
||||
|
||||
Cell.prototype.equals = function () {
|
||||
if(arguments.length === 1) {
|
||||
var cell = arguments[0];
|
||||
if(cell instanceof Cell) {
|
||||
// it's a Cell object
|
||||
return cell.position === this.position;
|
||||
} else {
|
||||
// it's a string position
|
||||
return cell === this.position;
|
||||
}
|
||||
} else if (arguments.length === 2) {
|
||||
// it's x,y coordinates
|
||||
return this.x === arguments[0] &&
|
||||
this.y === arguments[1];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Cell.prototype.getWorldPosition = function() {
|
||||
var cs = BOARD_SIZE / ROWS;
|
||||
var middle = (BOARD_SIZE-cs)/2;
|
||||
|
||||
|
||||
return new THREE.Vector3(
|
||||
this.x * cs - middle,
|
||||
0,
|
||||
(this.y * cs - middle)
|
||||
);
|
||||
};
|
||||
|
||||
// private
|
||||
function getPositionFromCoordinates(x,y) {
|
||||
return String.fromCharCode(x+a)+(7-y+1);
|
||||
}
|
||||
|
||||
function getCoordinatesFromPosition(position) {
|
||||
return {
|
||||
x: position.charCodeAt(0) - a,
|
||||
y: 7-(parseInt(position.charAt(1),10)-1)
|
||||
};
|
||||
}
|
||||
|
||||
function getCoordinatesFromIndex(index) {
|
||||
return {
|
||||
x: index%COLS,
|
||||
y: Math.floor(index/COLS) // have to flip y since 3D starts from bottom left
|
||||
};
|
||||
}
|
||||
|
||||
function isValid() {
|
||||
if( arguments.length == 2) {
|
||||
var x = arguments[0];
|
||||
var y = arguments[1];
|
||||
|
||||
return x >= 0 && x < COLS &&
|
||||
y >= 0 && y < ROWS;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
window.Cell = Cell;
|
||||
|
||||
})();
|
596
weboasis/arcade/chess/js/chess.js
Normal file
596
weboasis/arcade/chess/js/chess.js
Normal file
@ -0,0 +1,596 @@
|
||||
// ECMAScript 5 strict mode
|
||||
/* jshint globalstrict: true*/
|
||||
/* jslint newcap: true */
|
||||
/* global THREE, $, document, window, console */
|
||||
/* global LOADING_BAR_SCALE,ROWS,COLS,PIECE_SIZE, BOARD_SIZE, FLOOR_SIZE, WIREFRAME, DEBUG, Cell, WHITE, BLACK, FEEDBACK, SHADOW */
|
||||
/* global textures, geometries, removeLoader */
|
||||
/* global initGUI, initInfo, addToPGN, displayCheck, newGame */
|
||||
/* global initPieceFactory,initCellFactory,createCell,createPiece,createChessBoard, createFloor, createValidCellMaterial,createSelectedMaterial, validCellMaterial, selectedMaterial */
|
||||
/*global Search,FormatSquare,GenerateMove,MakeMove,GetMoveSAN,MakeSquare,UnmakeMove, FormatMove, ResetGame, GetFen, GetMoveFromString, alert, InitializeFromFen, GenerateValidMoves */
|
||||
/*global g_inCheck,g_board,g_pieceList, g_toMove, g_timeout:true,g_maxply:true */
|
||||
/*global moveflagCastleKing, moveflagCastleQueen, moveflagEPC, moveflagPromotion, colorWhite*/
|
||||
/*global moveflagPromoteQueen,moveflagPromoteRook,moveflagPromoteBishop,moveflagPromoteKnight*/
|
||||
/*global piecePawn, pieceKnight, pieceBishop, pieceRook, pieceQueen, pieceKing */
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
|
||||
var camera;
|
||||
// list of valid move after each move
|
||||
// used mostly for cell highlighting
|
||||
var validMoves = null;
|
||||
// chess game variables
|
||||
var g_allMoves = [];
|
||||
// default promotion
|
||||
var promotion = moveflagPromoteQueen;
|
||||
|
||||
var g_playerWhite = false;
|
||||
var g_backgroundEngine;
|
||||
|
||||
// settings for AI level
|
||||
var levels = [
|
||||
{timeout:0,maxply:1},
|
||||
{timeout:12,maxply:20},
|
||||
{timeout:25,maxply:40},
|
||||
{timeout:50,maxply:60},
|
||||
{timeout:100,maxply:80},
|
||||
{timeout:200,maxply:100},
|
||||
{timeout:400,maxply:120},
|
||||
{timeout:800,maxply:140},
|
||||
{timeout:1600,maxply:160},
|
||||
{timeout:3200,maxply:180}
|
||||
];
|
||||
|
||||
|
||||
(function() {
|
||||
// general setup
|
||||
var scene, renderer;
|
||||
var cameraControls, effectController;
|
||||
// for picking
|
||||
var projector;
|
||||
// 3D board representation
|
||||
var chessBoard;
|
||||
// for proper timing
|
||||
var clock = new THREE.Clock();
|
||||
|
||||
var g_backgroundEngineValid = true;
|
||||
|
||||
// array for picking
|
||||
var board3D = [];
|
||||
|
||||
|
||||
// hold current selection
|
||||
var selectedPiece = null;
|
||||
var selectedCell = null;
|
||||
|
||||
// default values for AI level
|
||||
g_timeout = 1600;
|
||||
g_maxply = 49;
|
||||
|
||||
|
||||
/*
|
||||
* BASIC SETUP
|
||||
*/
|
||||
function init() {
|
||||
// initialize everything for 3D
|
||||
|
||||
// CANVAS PARAMETERS
|
||||
var canvasWidth = window.innerWidth;
|
||||
var canvasHeight = window.innerHeight;
|
||||
var canvasRatio = canvasWidth / canvasHeight;
|
||||
|
||||
// RENDERER
|
||||
renderer = new THREE.WebGLRenderer( { antialias: true } );
|
||||
renderer.gammaInput = true;
|
||||
renderer.gammaOutput = true;
|
||||
renderer.setSize(canvasWidth, canvasHeight);
|
||||
|
||||
if ( SHADOW ) {
|
||||
renderer.shadowMapEnabled = true;
|
||||
renderer.shadowMapType = THREE.PCFSoftShadowMap;
|
||||
renderer.shadowMapCascade = true;
|
||||
}
|
||||
|
||||
// black background
|
||||
renderer.setClearColor( 0x000000, 1.0 );
|
||||
document.body.appendChild( renderer.domElement );
|
||||
|
||||
// CAMERA
|
||||
camera = new THREE.PerspectiveCamera( 45, canvasRatio, 1, 40000 );
|
||||
// CONTROLS
|
||||
cameraControls = new THREE.OrbitAndPanControls(camera, renderer.domElement);
|
||||
// limitations
|
||||
cameraControls.minPolarAngle = 0;
|
||||
cameraControls.maxPolarAngle = 80 * Math.PI/180;
|
||||
cameraControls.minDistance = 10;
|
||||
cameraControls.maxDistance = 200;
|
||||
cameraControls.userZoomSpeed = 1.0;
|
||||
// default position behind white
|
||||
// (might want to change that according to color selection)
|
||||
camera.position.set( 0, 100, 100 );
|
||||
|
||||
|
||||
// LIGHTING
|
||||
var spotlight = new THREE.SpotLight( 0xFFFFFF, 1.0);
|
||||
spotlight.position.set( 0, 300, 0 );
|
||||
spotlight.angle = Math.PI / 2;
|
||||
spotlight.exponent = 50.0;
|
||||
spotlight.target.position.set( 0, 0, 0 );
|
||||
|
||||
if ( SHADOW ) {
|
||||
spotlight.castShadow = true;
|
||||
spotlight.shadowDarkness = 0.5;
|
||||
//spotlight.shadowMapWidth = 4096; // yeah crazy testing
|
||||
//spotlight.shadowMapHeight = 4096;
|
||||
spotlight.shadowBias = -0.001;
|
||||
}
|
||||
|
||||
|
||||
var whiteLight = new THREE.PointLight( 0xFFEEDD, 0.2);
|
||||
whiteLight.position.set(0,0,100);
|
||||
var blackLight = new THREE.PointLight( 0xFFEEDD, 0.2);
|
||||
blackLight.position.set(0,0,-100);
|
||||
|
||||
// generate createPiece and createCell functions
|
||||
initPieceFactory();
|
||||
initCellFactory();
|
||||
|
||||
// we let chessBoard in global scope to use it for picking
|
||||
chessBoard = createChessBoard(BOARD_SIZE);
|
||||
var floor = createFloor(FLOOR_SIZE,BOARD_SIZE);
|
||||
|
||||
//floor.position.y = -5*BOARD_SIZE/100;
|
||||
floor.position.y = chessBoard.height;
|
||||
|
||||
// create and fill the scene with default stuff
|
||||
scene = new THREE.Scene();
|
||||
scene.add(floor);
|
||||
scene.add(spotlight);
|
||||
scene.add(whiteLight);
|
||||
scene.add(blackLight);
|
||||
scene.add(chessBoard);
|
||||
|
||||
// to make everything black in the background
|
||||
scene.fog = new THREE.FogExp2( 0x000000, 0.001 );
|
||||
// little reddish to fake a bit of bounce lighting
|
||||
scene.add(new THREE.AmbientLight(0x330000));
|
||||
|
||||
// for picking
|
||||
projector = new THREE.Projector();
|
||||
|
||||
// Menu
|
||||
initGUI();
|
||||
// Check feedback
|
||||
initInfo();
|
||||
|
||||
createValidCellMaterial();
|
||||
createSelectedMaterial();
|
||||
|
||||
// picking event
|
||||
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
|
||||
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
|
||||
|
||||
// avoid stretching
|
||||
window.addEventListener('resize',onResize,false);
|
||||
}
|
||||
|
||||
function onResize() {
|
||||
var canvas = renderer.domElement;
|
||||
var w = window.innerWidth;
|
||||
var h = window.innerHeight;
|
||||
renderer.setSize(w,h);
|
||||
// have to change the projection
|
||||
// else the image will be stretched
|
||||
camera.aspect = w/h;
|
||||
camera.updateProjectionMatrix();
|
||||
}
|
||||
|
||||
function animate() {
|
||||
window.requestAnimationFrame(animate);
|
||||
render();
|
||||
}
|
||||
|
||||
function render() {
|
||||
var delta = clock.getDelta();
|
||||
cameraControls.update(delta);
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
|
||||
function UIPlayMove(move,silent) {
|
||||
// we play the move here by
|
||||
// adding it to the png list (for display)
|
||||
addToPGN(move);
|
||||
// and to the move list (for undos)
|
||||
g_allMoves[g_allMoves.length] = move;
|
||||
// committing the move
|
||||
MakeMove(move);
|
||||
// redrawing
|
||||
// silent flag is used when simulating moves for loading PGN
|
||||
if(!silent) {
|
||||
redrawBoard();
|
||||
}
|
||||
}
|
||||
|
||||
function playMove(piece,cell) {
|
||||
|
||||
if (piece.cell === undefined || cell.name === undefined) {
|
||||
return false;
|
||||
}
|
||||
// get the positions
|
||||
var start = new Cell(piece.cell);
|
||||
var end = new Cell(cell.name);
|
||||
|
||||
var startSquare = MakeSquare(start.y, start.x);
|
||||
var endSquare = MakeSquare(end.y, end.x);
|
||||
|
||||
var move = null;
|
||||
var testPromotion = false;
|
||||
var p = g_board[startSquare];
|
||||
|
||||
if ( ((p & 0x7) === piecePawn) &&
|
||||
(((start.y === 1) && g_playerWhite) ||
|
||||
( (start.y === 6) && !g_playerWhite)) &&
|
||||
(((p & 0x8) && g_playerWhite) ||
|
||||
(!(p & 0x8) && !g_playerWhite))
|
||||
) {
|
||||
testPromotion = true;
|
||||
}
|
||||
|
||||
// check if the move is valid
|
||||
// validMoves is global and reevaluated after each move
|
||||
for (var i = 0; i < validMoves.length; i++) {
|
||||
if (testPromotion) {
|
||||
// for promotion we one valid move per promotion type
|
||||
// so we have to be more specific and create the entire move
|
||||
// with its flag go get it back from validMoves.
|
||||
// else it's alway a Rook promotion (flag 0x00).
|
||||
if(validMoves[i] === GenerateMove(startSquare, endSquare, moveflagPromotion | promotion)) {
|
||||
move = validMoves[i];
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// just checking start and end square allows to cover
|
||||
// all other special moves like "en passant" capture and
|
||||
// castling
|
||||
if ( (validMoves[i] & 0xFF) == startSquare &&
|
||||
((validMoves[i] >> 8) & 0xFF) == endSquare ) {
|
||||
move = validMoves[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!(start.x === end.x && start.y === end.y) && move !== null) {
|
||||
|
||||
// we send the move to our worker
|
||||
if (InitializeBackgroundEngine()) {
|
||||
g_backgroundEngine.postMessage(FormatMove(move));
|
||||
}
|
||||
|
||||
// we play the actual move
|
||||
UIPlayMove(move,false);
|
||||
|
||||
|
||||
// make the engine play (setTimeOut is used probably to wait for the last postMessage to kick in)
|
||||
// maybe creating a callback from the worker would be better (more reliable)
|
||||
setTimeout(SearchAndRedraw, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AI CONTROL
|
||||
*/
|
||||
function EnsureAnalysisStopped() {
|
||||
if (g_backgroundEngine) {
|
||||
g_backgroundEngine.terminate();
|
||||
g_backgroundEngine = null;
|
||||
}
|
||||
}
|
||||
|
||||
function SearchAndRedraw() {
|
||||
// the AI is triggered here
|
||||
if (InitializeBackgroundEngine()) {
|
||||
g_backgroundEngine.postMessage("search " + g_timeout + "," + g_maxply);
|
||||
} else {
|
||||
Search(FinishMove, g_maxply, null); // unasynchronous version fall back
|
||||
}
|
||||
}
|
||||
|
||||
function FinishMove(bestMove, value, timeTaken, ply) {
|
||||
// used by the fallback Search
|
||||
if (bestMove !== null) {
|
||||
UIPlayMove(bestMove,false);
|
||||
}
|
||||
}
|
||||
|
||||
function InitializeBackgroundEngine() {
|
||||
// we initialize the web worker here
|
||||
if (!g_backgroundEngineValid) {
|
||||
return false;
|
||||
}
|
||||
if (!g_backgroundEngine) {
|
||||
g_backgroundEngineValid = true;
|
||||
try {
|
||||
g_backgroundEngine = new Worker("js/AI/garbochess.js");
|
||||
g_backgroundEngine.onmessage = function (e) {
|
||||
if (e.data.match("^pv") == "pv") {
|
||||
// legacy
|
||||
} else if (e.data.match("^message") == "message") {
|
||||
// legacy
|
||||
EnsureAnalysisStopped();
|
||||
} else if (e.data.match("^console: ") == "console: ") {
|
||||
// debugging
|
||||
console.log(e.data.substr(9));
|
||||
} else {
|
||||
// we receive the move from the AI, we play it
|
||||
UIPlayMove(GetMoveFromString(e.data), false);
|
||||
}
|
||||
};
|
||||
g_backgroundEngine.error = function (e) {
|
||||
alert("Error from background worker:" + e.message);
|
||||
};
|
||||
// set up the current board position
|
||||
g_backgroundEngine.postMessage("position " + GetFen());
|
||||
} catch (error) {
|
||||
g_backgroundEngineValid = false;
|
||||
}
|
||||
}
|
||||
// return false for fallback
|
||||
return g_backgroundEngineValid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* BOARD
|
||||
*/
|
||||
|
||||
|
||||
function updateBoard3D() {
|
||||
// list all the pieces
|
||||
board3D = [];
|
||||
for (var y = 0; y < ROWS; y++) {
|
||||
for (var x = 0; x < COLS; x++) {
|
||||
var piece = g_board[MakeSquare(y,x)];
|
||||
var pieceColor = (piece & colorWhite) ? WHITE : BLACK;
|
||||
var pieceName = null;
|
||||
switch (piece & 0x7) {
|
||||
case piecePawn:
|
||||
pieceName = "pawn";
|
||||
break;
|
||||
case pieceKnight:
|
||||
pieceName = "knight";
|
||||
break;
|
||||
case pieceBishop:
|
||||
pieceName = "bishop";
|
||||
break;
|
||||
case pieceRook:
|
||||
pieceName = "rook";
|
||||
break;
|
||||
case pieceQueen:
|
||||
pieceName = "queen";
|
||||
break;
|
||||
case pieceKing:
|
||||
pieceName = "king";
|
||||
break;
|
||||
}
|
||||
|
||||
if (pieceName !== null) {
|
||||
board3D[x+y*COLS] = createPiece(pieceName,pieceColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearBoard() {
|
||||
// remove all pieces from the board
|
||||
var cell;
|
||||
board3D.forEach(function(piece) {
|
||||
scene.remove(piece);
|
||||
cell = new Cell(piece.cell);
|
||||
});
|
||||
}
|
||||
|
||||
function fillBoard() {
|
||||
// place all the pieces on the board
|
||||
var cell;
|
||||
board3D.forEach(function(piece,index) {
|
||||
cell = new Cell(index);
|
||||
piece.position = cell.getWorldPosition();
|
||||
piece.cell = index;
|
||||
scene.add(piece);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function redrawBoard() {
|
||||
validMoves = GenerateValidMoves();
|
||||
clearBoard();
|
||||
updateBoard3D();
|
||||
fillBoard();
|
||||
displayCheck();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* PICKING
|
||||
*/
|
||||
function pickPiece(raycaster) {
|
||||
var intersect = null;
|
||||
var picked = null;
|
||||
// intersect piece
|
||||
var hitList = [];
|
||||
var hit,piece;
|
||||
for (var i in board3D) {
|
||||
if ({}.hasOwnProperty.call(board3D, i)) {
|
||||
piece = board3D[i];
|
||||
intersect = raycaster.intersectObject( piece.children[0], true );
|
||||
|
||||
if (intersect.length > 0) {
|
||||
hit = intersect[0];
|
||||
if (( g_playerWhite && hit.object.parent.color === WHITE ) ||
|
||||
(!g_playerWhite && hit.object.parent.color === BLACK ) ){
|
||||
|
||||
// only pick the right color
|
||||
hitList.push(hit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find the closest
|
||||
hitList.forEach(function(hit) {
|
||||
if (picked === null || picked.distance > hit.distance) {
|
||||
picked = hit;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (picked) {
|
||||
return picked.object.parent;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function pickCell(raycaster) {
|
||||
// here we don't need to test the distance since you can't really
|
||||
// intersect more than one cell at a time.
|
||||
var intersect = raycaster.intersectObject( chessBoard, true );
|
||||
if (intersect.length > 0) {
|
||||
var pickedCell = intersect[0].object;
|
||||
return pickedCell;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getRay(event) {
|
||||
// get the raycaster object from the mouse position
|
||||
var zoomLevel = window.devicePixelRatio | 1.0 ;
|
||||
var canvas = renderer.domElement;
|
||||
var canvasPosition = canvas.getBoundingClientRect();
|
||||
var mouseX = event.clientX*zoomLevel - canvasPosition.left;
|
||||
var mouseY = event.clientY*zoomLevel - canvasPosition.top;
|
||||
|
||||
var mouseVector = new THREE.Vector3(
|
||||
2 * ( mouseX / canvas.width ) - 1,
|
||||
1 - 2 * ( mouseY / canvas.height ));
|
||||
|
||||
return projector.pickingRay( mouseVector.clone(), camera );
|
||||
}
|
||||
|
||||
function onDocumentMouseMove( event ) {
|
||||
|
||||
var canvas = renderer.domElement;
|
||||
var raycaster = getRay(event);
|
||||
var pickedPiece = pickPiece(raycaster);
|
||||
var pickedCell = pickCell(raycaster);
|
||||
|
||||
|
||||
canvas.style.cursor = "default";
|
||||
// we are over one of our piece -> hand
|
||||
if (pickedPiece !== null) {
|
||||
canvas.style.cursor = "pointer";
|
||||
}
|
||||
|
||||
// if a cell is selected, we unselect it by default
|
||||
if (selectedCell !== null) {
|
||||
selectedCell.material = selectedCell.baseMaterial;
|
||||
}
|
||||
|
||||
// if a piece is selected and a cell is picked
|
||||
if(selectedPiece !== null && pickedCell !== null) {
|
||||
var start = new Cell(selectedPiece.cell);
|
||||
var end = new Cell(pickedCell.name);
|
||||
|
||||
var move = null;
|
||||
// we check if it would be a valid move
|
||||
for (var i = 0; i < validMoves.length; i++) {
|
||||
if ( (validMoves[i] & 0xFF) == MakeSquare(start.y, start.x) &&
|
||||
((validMoves[i] >> 8) & 0xFF) == MakeSquare(end.y, end.x)
|
||||
) {
|
||||
move = validMoves[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// then if a piece was clicked and we are on a valide cell
|
||||
// we highlight it and display a hand cursor
|
||||
if (pickedCell !== null && move !==null) {
|
||||
selectedCell = pickedCell;
|
||||
selectedCell.baseMaterial = selectedCell.material;
|
||||
selectedCell.material = validCellMaterial[selectedCell.color];
|
||||
canvas.style.cursor = "pointer";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onDocumentMouseDown( event ) {
|
||||
|
||||
var canvas = renderer.domElement;
|
||||
var raycaster = getRay(event);
|
||||
|
||||
var pickedPiece = pickPiece(raycaster);
|
||||
var pickedCell = pickCell(raycaster);
|
||||
|
||||
if (selectedPiece !== null && pickedCell !== null) {
|
||||
if(playMove(selectedPiece,pickedCell)) {
|
||||
// a move is played, we reset everything
|
||||
// any selectedPiece will disappear
|
||||
// since we redraw everything
|
||||
selectedPiece = null;
|
||||
pickedPiece = null;
|
||||
pickedCell = null;
|
||||
}
|
||||
}
|
||||
|
||||
// when a click happen, any selected piece gets unselected
|
||||
if (selectedPiece !== null) {
|
||||
selectedPiece.children[0].material = selectedPiece.baseMaterial;
|
||||
//selectedPiece.children[1].material = selectedPiece.baseMaterial;
|
||||
}
|
||||
|
||||
// then if a piece was clicked, we select it
|
||||
selectedPiece = pickedPiece;
|
||||
if (selectedPiece !== null) {
|
||||
selectedPiece.baseMaterial = selectedPiece.children[0].material;
|
||||
selectedPiece.children[0].material = selectedMaterial[selectedPiece.color];
|
||||
//selectedPiece.children[1].material = selectedMaterial[selectedPiece.color];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// all resources (meshs and textures) are loaded
|
||||
function onLoaded () {
|
||||
//bar.container.style.display = "none";
|
||||
removeLoader();
|
||||
|
||||
init();
|
||||
if (DEBUG) {
|
||||
window.scene = scene;
|
||||
window.renderer = renderer;
|
||||
}
|
||||
newGame(WHITE);
|
||||
animate();
|
||||
|
||||
//setTimeout(loadFEN('8/Q5P1/8/8/8/8/8/2K1k3 w - -'),2000);
|
||||
|
||||
}
|
||||
|
||||
window.SearchAndRedraw = SearchAndRedraw;
|
||||
window.onLoaded = onLoaded;
|
||||
window.redrawBoard = redrawBoard;
|
||||
window.EnsureAnalysisStopped = EnsureAnalysisStopped;
|
||||
window.InitializeBackgroundEngine = InitializeBackgroundEngine;
|
||||
window.UIPlayMove = UIPlayMove;
|
||||
|
||||
})();
|
420
weboasis/arcade/chess/js/factory.js
Normal file
420
weboasis/arcade/chess/js/factory.js
Normal file
@ -0,0 +1,420 @@
|
||||
// ECMAScript 5 strict mode
|
||||
/* jshint globalstrict: true*/
|
||||
/* global THREE, $, document, window, console */
|
||||
/* global LOADING_BAR_SCALE,ROWS,COLS,PIECE_SIZE, BOARD_SIZE, FLOOR_SIZE, WIREFRAME, DEBUG, Cell, WHITE, BLACK, FEEDBACK, SHADOW */
|
||||
/* global createCell */
|
||||
|
||||
/*
|
||||
* initPieceFactory and initCellFactory need to be called after
|
||||
* all ressources are loaded (geometry and texture)
|
||||
*
|
||||
* they will create the createPiece and createCell function
|
||||
* and keep some texture/material objects in a closure to avoid
|
||||
* unnecessary cloning
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
var geometries = {};
|
||||
var textures = {};
|
||||
function initPieceFactory () {
|
||||
|
||||
// common textures
|
||||
var tiling = 4;
|
||||
var colors = [];
|
||||
for(var c = 0; c<2; c++) {
|
||||
colors[c] = textures['texture/wood-'+c+'.jpg'].clone();
|
||||
colors[c].tile(tiling);
|
||||
}
|
||||
var norm = textures['texture/wood_N.jpg'].clone();
|
||||
norm.tile(tiling);
|
||||
var spec = textures['texture/wood_S.jpg'].clone();
|
||||
spec.tile(tiling);
|
||||
|
||||
function createPiece(name,color) {
|
||||
var size = BOARD_SIZE/COLS * PIECE_SIZE;
|
||||
// container for the piece and its reflexion
|
||||
var piece = new THREE.Object3D();
|
||||
// base material for all the piece (only lightmap changes)
|
||||
var material = new THREE.MeshPhongMaterial({
|
||||
color:0xffffff,
|
||||
specular:0xaaaaaa,
|
||||
shininess:60.0,
|
||||
map:colors[color],
|
||||
normalMap:norm,
|
||||
specularMap:spec,
|
||||
wireframe:WIREFRAME
|
||||
});
|
||||
material.normalScale.set(0.3,0.3);
|
||||
|
||||
// urls of geometry and lightmap
|
||||
var urlJson = '3D/json/'+name+'.json';
|
||||
var urlAO = 'texture/'+name+'-ao.jpg';
|
||||
|
||||
var geo = geometries[urlJson];
|
||||
// no need to clone this texture
|
||||
// since its pretty specific
|
||||
var light = textures[urlAO];
|
||||
light.format = THREE.LuminanceFormat;
|
||||
|
||||
material.lightMap = light;
|
||||
|
||||
var mesh = new THREE.Mesh(geo,material);
|
||||
if (SHADOW) {
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
}
|
||||
mesh.scale.set(size,size,size);
|
||||
// we rotate pieces so they face each other (mostly relevant for knight)
|
||||
mesh.rotation.y += (color == WHITE) ? -Math.PI/2 : Math.PI/2;
|
||||
|
||||
// we create the reflection
|
||||
// it's a cloned with a negative scale on the Y axis
|
||||
var reflexion = mesh.clone();
|
||||
reflexion.scale.y *= -1;
|
||||
reflexion.material = reflexion.material.clone();
|
||||
reflexion.material.side = THREE.BackSide;
|
||||
|
||||
piece.add(mesh);
|
||||
piece.add(reflexion);
|
||||
|
||||
piece.name = name;
|
||||
piece.color = color;
|
||||
|
||||
return piece;
|
||||
}
|
||||
|
||||
// make it global
|
||||
window.createPiece = createPiece;
|
||||
}
|
||||
|
||||
function initCellFactory() {
|
||||
|
||||
var materials = [];
|
||||
var tiling = 2;
|
||||
|
||||
|
||||
// common textures
|
||||
var diff;
|
||||
var norm = textures['texture/wood_N.jpg'].clone();
|
||||
norm.tile(tiling);
|
||||
var spec = textures['texture/wood_S.jpg'].clone();
|
||||
spec.tile(tiling);
|
||||
|
||||
for(var c = 0; c<2; c++) {
|
||||
|
||||
diff = textures['texture/wood-'+c+'.jpg'].clone();
|
||||
diff.tile(tiling);
|
||||
|
||||
//common material
|
||||
materials[c] = new THREE.MeshPhongMaterial({
|
||||
color:0xffffff,
|
||||
specular:[0xAAAAAA,0x444444][c],
|
||||
shininess:30.0,
|
||||
wireframe:WIREFRAME,
|
||||
transparent:true,
|
||||
map:diff,
|
||||
specularMap:spec,
|
||||
normalMap:norm,
|
||||
//blending: THREE.AdditiveBlending,
|
||||
opacity:0.5
|
||||
});
|
||||
//materials[c].normalScale.set(0.5,0.5);
|
||||
}
|
||||
|
||||
function createCell(size,color) {
|
||||
// container for the cell and its reflexion
|
||||
var geo = new THREE.PlaneGeometry(size,size);
|
||||
|
||||
// randomize uv offset to ad a bit of variety
|
||||
var randU = Math.random();
|
||||
var randV = Math.random();
|
||||
|
||||
var uvs = geo.faceVertexUvs[0][0];
|
||||
for (var j = 0; j < uvs.length; j++) {
|
||||
uvs[j].x += randU;
|
||||
uvs[j].y += randV;
|
||||
}
|
||||
|
||||
var cell = new THREE.Mesh(geo,materials[color]);
|
||||
|
||||
if (SHADOW) {
|
||||
cell.receiveShadow = true;
|
||||
}
|
||||
|
||||
// by default PlaneGeometry is vertical
|
||||
cell.rotation.x = -Math.PI/2;
|
||||
cell.color = color;
|
||||
return cell;
|
||||
}
|
||||
|
||||
// make it global
|
||||
window.createCell = createCell;
|
||||
}
|
||||
|
||||
|
||||
function createChessBoard(size) {
|
||||
// contains everything that makes the board
|
||||
var lChessBoard = new THREE.Object3D();
|
||||
|
||||
var cellSize = size/COLS;
|
||||
var square,cell;
|
||||
|
||||
for(var i=0; i< ROWS*COLS; i++) {
|
||||
|
||||
var col = i%COLS;
|
||||
var row = Math.floor(i/COLS);
|
||||
|
||||
cell = new Cell(i);
|
||||
square = createCell(cellSize,1-(i+row)%2);
|
||||
square.position = cell.getWorldPosition();
|
||||
square.name = cell.position;
|
||||
|
||||
lChessBoard.add(square);
|
||||
}
|
||||
|
||||
// some fake inner environment color for reflexion
|
||||
var innerBoard = new THREE.Mesh (
|
||||
geometries['3D/json/innerBoard.json'],
|
||||
new THREE.MeshBasicMaterial({
|
||||
color:0x783e12
|
||||
})
|
||||
);
|
||||
innerBoard.scale.set(size,size,size);
|
||||
|
||||
/// board borders
|
||||
var tiling = 6;
|
||||
var wood = textures['texture/wood-0.jpg'].clone();
|
||||
var spec = textures['texture/wood_S.jpg'].clone();
|
||||
var norm = textures['texture/wood_N.jpg'].clone();
|
||||
wood.tile(tiling);
|
||||
spec.tile(tiling);
|
||||
norm.tile(tiling);
|
||||
|
||||
var geo = geometries['3D/json/board.json'];
|
||||
geo.computeBoundingBox();
|
||||
|
||||
var board = new THREE.Mesh (
|
||||
geo,
|
||||
new THREE.MeshPhongMaterial({
|
||||
color:0xffffff,
|
||||
map:wood,
|
||||
specular: 0xffffff,
|
||||
specularMap: spec,
|
||||
normalMap: norm,
|
||||
shininess: 60,
|
||||
normalScale: new THREE.Vector2(0.2,0.2)
|
||||
})
|
||||
);
|
||||
var hCorrection = 0.62; // yeah I should just create a better geometry
|
||||
board.scale.set(size,size*hCorrection,size);
|
||||
lChessBoard.height = geo.boundingBox.min.y * board.scale.y;
|
||||
|
||||
if (SHADOW) {
|
||||
board.receiveShadow = true;
|
||||
board.castShadow = true;
|
||||
}
|
||||
|
||||
lChessBoard.add(innerBoard);
|
||||
lChessBoard.add(board);
|
||||
|
||||
lChessBoard.name = "chessboard";
|
||||
return lChessBoard;
|
||||
}
|
||||
|
||||
function createFloor(size,chessboardSize) {
|
||||
// The floor is a fake plane with a hole in it to allow
|
||||
// for the fake reflexion trick to work
|
||||
// so we build it vertices by vertices
|
||||
|
||||
// material
|
||||
var tiling = 30*size/1000;
|
||||
var material = new THREE.MeshPhongMaterial({
|
||||
color:0xffffff,
|
||||
wireframe:WIREFRAME ,
|
||||
specular:0xaaaaaa,
|
||||
shininess:30
|
||||
|
||||
});
|
||||
var diff = textures['texture/floor.jpg'];
|
||||
var spec = textures['texture/floor_S.jpg'];
|
||||
var norm = textures['texture/floor_N.jpg'];
|
||||
var light = textures['texture/fakeShadow.jpg'];
|
||||
|
||||
diff.tile(tiling);
|
||||
spec.tile(tiling);
|
||||
norm.tile(tiling);
|
||||
light.format = THREE.RGBFormat;
|
||||
|
||||
material.map = diff;
|
||||
material.normalMap = norm;
|
||||
material.normalScale.set(0.6,0.6);
|
||||
material.specularMap = spec;
|
||||
material.lightMap = light;
|
||||
|
||||
// geometry
|
||||
var halfBoard = chessboardSize/2;
|
||||
var halfSize = size/2;
|
||||
|
||||
var floorGeo = new THREE.Geometry();
|
||||
// outter vertices
|
||||
floorGeo.vertices.push(new THREE.Vector3(-halfSize,0,-halfSize));
|
||||
floorGeo.vertices.push(new THREE.Vector3( halfSize,0,-halfSize));
|
||||
floorGeo.vertices.push(new THREE.Vector3( halfSize,0, halfSize));
|
||||
floorGeo.vertices.push(new THREE.Vector3(-halfSize,0, halfSize));
|
||||
// hole vertices
|
||||
floorGeo.vertices.push(new THREE.Vector3(-halfBoard,0,-halfBoard));
|
||||
floorGeo.vertices.push(new THREE.Vector3( halfBoard,0,-halfBoard));
|
||||
floorGeo.vertices.push(new THREE.Vector3( halfBoard,0, halfBoard));
|
||||
floorGeo.vertices.push(new THREE.Vector3(-halfBoard,0, halfBoard));
|
||||
|
||||
floorGeo.faceVertexUvs[ 0 ] = [];
|
||||
floorGeo.faceVertexUvs[ 1 ] = [];
|
||||
|
||||
/*
|
||||
* vertices uvs-lightmap
|
||||
* 0-----------1 80-----------80
|
||||
* |\ /| |\ /|
|
||||
* | \ / | | \ / |
|
||||
* | \ / | | \ / |
|
||||
* | 4---5 | | 0---0 |
|
||||
* | | | | | | | |
|
||||
* | 7---6 | | 0---0 |
|
||||
* | / \ | | / \ |
|
||||
* | / \ | | / \ |
|
||||
* |/ \| |/ \|
|
||||
* 3-----------2 80-----------80
|
||||
*/
|
||||
|
||||
// all normals just points upward
|
||||
var normal = new THREE.Vector3( 0, 1, 0 );
|
||||
|
||||
// list of vertex index for each face
|
||||
var faces = [
|
||||
[0,4,5,1],
|
||||
[1,5,6,2],
|
||||
[2,6,7,3],
|
||||
[3,7,4,0]
|
||||
];
|
||||
|
||||
faces.forEach( function(f) {
|
||||
var uvs1 = [];
|
||||
var uvs2 = [];
|
||||
var lightU,lightV;
|
||||
f.forEach(function(v,i) {
|
||||
// we linearily transform positions
|
||||
// from a -halfSize-halfSize space
|
||||
// to a 0-1 space
|
||||
uvs1.push(new THREE.Vector2(
|
||||
(floorGeo.vertices[v].x+halfSize)/size,
|
||||
(floorGeo.vertices[v].z+halfSize)/size
|
||||
));
|
||||
lightU = (v < 4) ? 80 : 0;
|
||||
lightV = (i < 2) ? 0 : 1;
|
||||
uvs2.push(new THREE.Vector2(lightU,lightV));
|
||||
});
|
||||
|
||||
// we create a new face folowing the faces list
|
||||
var face = new THREE.Face4(
|
||||
f[0],f[1],f[2],f[3]
|
||||
);
|
||||
|
||||
// and apply normals (without this, no proper lighting)
|
||||
face.normal.copy( normal );
|
||||
face.vertexNormals.push(
|
||||
normal.clone(),
|
||||
normal.clone(),
|
||||
normal.clone(),
|
||||
normal.clone()
|
||||
);
|
||||
|
||||
// add the face to the geometry's faces list
|
||||
floorGeo.faces.push(face);
|
||||
|
||||
// add uv coordinates to uv channels.
|
||||
floorGeo.faceVertexUvs[ 0 ].push(uvs1); // for diffuse/normal
|
||||
floorGeo.faceVertexUvs[ 1 ].push(uvs2); // for lightmap
|
||||
|
||||
});
|
||||
|
||||
// not sure it's needed but since it's in THREE.PlaneGeometry...
|
||||
floorGeo.computeCentroids();
|
||||
|
||||
var floor = new THREE.Mesh(floorGeo,material);
|
||||
|
||||
if(SHADOW) {
|
||||
floor.receiveShadow = true;
|
||||
}
|
||||
|
||||
|
||||
floor.name = "floor";
|
||||
return floor;
|
||||
}
|
||||
|
||||
// special highlighting materials
|
||||
var validCellMaterial = null;
|
||||
function createValidCellMaterial () {
|
||||
validCellMaterial = [];
|
||||
var tiling = 2;
|
||||
|
||||
|
||||
// common textures
|
||||
var diff;
|
||||
var norm = textures['texture/wood_N.jpg'].clone();
|
||||
norm.tile(tiling);
|
||||
var spec = textures['texture/wood_S.jpg'].clone();
|
||||
spec.tile(tiling);
|
||||
|
||||
for(var c = 0; c<2; c++) {
|
||||
|
||||
diff = textures['texture/wood-1.jpg'].clone();
|
||||
diff.tile(tiling);
|
||||
|
||||
//common material
|
||||
validCellMaterial[c] = new THREE.MeshPhongMaterial({
|
||||
color:0x00ff00,
|
||||
specular:0x999999,
|
||||
shininess:60.0,
|
||||
wireframe:WIREFRAME,
|
||||
map:diff,
|
||||
specularMap:spec,
|
||||
normalMap:norm
|
||||
});
|
||||
//materials[c].normalScale.set(0.5,0.5);
|
||||
}
|
||||
}
|
||||
|
||||
var selectedMaterial = null;
|
||||
function createSelectedMaterial() {
|
||||
selectedMaterial = [];
|
||||
var tiling = 4;
|
||||
|
||||
|
||||
// common textures
|
||||
var diff;
|
||||
var norm = textures['texture/wood_N.jpg'].clone();
|
||||
norm.tile(tiling);
|
||||
var spec = textures['texture/wood_S.jpg'].clone();
|
||||
spec.tile(tiling);
|
||||
|
||||
for(var c = 0; c<2; c++) {
|
||||
|
||||
diff = textures['texture/wood-1.jpg'].clone();
|
||||
diff.tile(tiling);
|
||||
|
||||
//common material
|
||||
selectedMaterial[c] = new THREE.MeshPhongMaterial({
|
||||
color:0x00ff00,
|
||||
emissive:0x009900,
|
||||
specular:0x999999,
|
||||
shininess:60.0,
|
||||
wireframe:WIREFRAME,
|
||||
transparent:false,
|
||||
map:diff,
|
||||
specularMap:spec,
|
||||
normalMap:norm
|
||||
//opacity:0.4
|
||||
});
|
||||
selectedMaterial[c].normalScale.set(0.3,0.3);
|
||||
}
|
||||
|
||||
}
|
279
weboasis/arcade/chess/js/geoPieces.js
Normal file
279
weboasis/arcade/chess/js/geoPieces.js
Normal file
@ -0,0 +1,279 @@
|
||||
// ECMAScript 5 strict mode
|
||||
/* jshint globalstrict: true*/
|
||||
/* global THREE,console,BLACK,WHITE,WIREFRAME */
|
||||
"use strict";
|
||||
var pieceMaterial = [];
|
||||
pieceMaterial[BLACK] = new THREE.MeshPhongMaterial({color:0x111111,specular:0xaaaaaa,shininess:30.0,wireframe:WIREFRAME});
|
||||
pieceMaterial[WHITE] = new THREE.MeshPhongMaterial({color:0xdddddd,wireframe:WIREFRAME});
|
||||
function createPawn(size,color) {
|
||||
var pawn = new THREE.Object3D();
|
||||
var baseHeight = size*0.1;
|
||||
var baseRadius = size*0.8;
|
||||
var base = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(baseRadius,baseRadius,baseHeight,32,1),pieceMaterial[color]);
|
||||
base.position.y = baseHeight/2;
|
||||
|
||||
var bodyRadius = size*0.6;
|
||||
var body = new THREE.Mesh(
|
||||
new THREE.SphereGeometry(bodyRadius,32,16),pieceMaterial[color]);
|
||||
body.position.y = baseHeight + bodyRadius;
|
||||
|
||||
var neckHeight = size;
|
||||
var neckRadius = bodyRadius*0.7;
|
||||
var neck = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(0,neckRadius,neckHeight,32,1),pieceMaterial[color]);
|
||||
neck.position.y = baseHeight + bodyRadius*2+neckHeight/2;
|
||||
|
||||
var headRadius = size*0.2;
|
||||
var head = new THREE.Mesh(
|
||||
new THREE.SphereGeometry(headRadius,32,16),pieceMaterial[color]);
|
||||
head.position.y = baseHeight + bodyRadius*2 +neckHeight+headRadius/2;
|
||||
|
||||
pawn.add(head);
|
||||
pawn.add(neck);
|
||||
pawn.add(body);
|
||||
pawn.add(base);
|
||||
pawn.name = "Pawn";
|
||||
return pawn;
|
||||
}
|
||||
|
||||
function createRook(size,color) {
|
||||
var rook = new THREE.Object3D();
|
||||
var baseHeight = size*0.1;
|
||||
var baseRadius = size*0.8;
|
||||
var base = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(baseRadius,baseRadius,baseHeight,32,1),pieceMaterial[color]);
|
||||
base.position.y = baseHeight/2;
|
||||
var bodyRadius = size*0.4;
|
||||
var bodyHeight = size*1.6;
|
||||
var body = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(bodyRadius*1.2,bodyRadius,bodyHeight,32,16),pieceMaterial[color]);
|
||||
body.position.y = baseHeight + bodyHeight/2;
|
||||
|
||||
var wedgeHeight = size*0.5;
|
||||
var wedgeRadius = bodyRadius * 1.5;
|
||||
var wedge = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(wedgeRadius,bodyRadius*1.2,wedgeHeight,32,1),pieceMaterial[color]);
|
||||
|
||||
wedge.position.y = baseHeight + bodyHeight+wedgeHeight/2;
|
||||
|
||||
var teethThickness = size*0.2;
|
||||
var teethHeight = wedgeHeight;
|
||||
var teethTilt = size*0.1;
|
||||
|
||||
var obr = wedgeRadius;
|
||||
var ibr = wedgeRadius-teethThickness;
|
||||
var otr = obr-teethTilt;
|
||||
var itr = ibr-teethTilt;
|
||||
var teethCount = 6;
|
||||
var subdivision = Math.round(32/(teethCount*2));
|
||||
|
||||
var teethGeo = new THREE.TubeGeometry(otr,obr,itr,ibr,teethHeight,subdivision,1,0,2*Math.PI/(teethCount*2));
|
||||
|
||||
for (var i = 0; i < teethCount; i++) {
|
||||
var teeth = new THREE.Mesh(teethGeo,pieceMaterial[color]);
|
||||
teeth.position.y = baseHeight+bodyHeight+wedgeHeight+teethHeight/2;
|
||||
teeth.rotation.y = i*2*Math.PI/teethCount;
|
||||
rook.add(teeth);
|
||||
}
|
||||
|
||||
rook.add(wedge);
|
||||
rook.add(body);
|
||||
rook.add(base);
|
||||
rook.name = "Rook";
|
||||
return rook;
|
||||
}
|
||||
|
||||
function createKnight(size,color) {
|
||||
var knight = new THREE.Object3D();
|
||||
var baseHeight = size*0.1;
|
||||
var baseRadius = size*0.8;
|
||||
var base = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(baseRadius,baseRadius,baseHeight,32,1),pieceMaterial[color]);
|
||||
base.position.y = baseHeight/2;
|
||||
|
||||
var bodyRadius = size*0.6;
|
||||
var body = new THREE.Mesh(
|
||||
new THREE.SphereGeometry(bodyRadius,32,16),pieceMaterial[color]);
|
||||
|
||||
var neckHeight = size*1.2;
|
||||
var neckBottomRadius = bodyRadius*0.6;
|
||||
var neckTopRadius = bodyRadius*0.0;
|
||||
var _neck = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(neckTopRadius,neckBottomRadius,neckHeight,32,1),pieceMaterial[color]);
|
||||
_neck.position.y = bodyRadius+neckHeight/2;
|
||||
var neck = new THREE.Object3D();
|
||||
neck.add(_neck);
|
||||
neck.rotation.z = -Math.PI/32;
|
||||
|
||||
|
||||
var head = new THREE.Object3D();
|
||||
|
||||
var skullRadius = size*0.6;
|
||||
var skull = new THREE.Mesh(
|
||||
new THREE.SphereGeometry(skullRadius,32,16),pieceMaterial[color]);
|
||||
|
||||
var faceHeight = size*1.0;
|
||||
var faceBottomRadius = skullRadius*0.8;
|
||||
var faceTopRadius = skullRadius*0.3;
|
||||
var face = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(faceTopRadius,faceBottomRadius,faceHeight,32,1),pieceMaterial[color]);
|
||||
face.rotation.z = Math.PI/16;
|
||||
face.position.y = skullRadius;
|
||||
|
||||
var noseRadius = size*0.2;
|
||||
var nose = new THREE.Mesh(
|
||||
new THREE.SphereGeometry(noseRadius,32,16),pieceMaterial[color]);
|
||||
nose.position.y = skullRadius +faceHeight+noseRadius/2;
|
||||
|
||||
head.add(skull);
|
||||
head.add(face);
|
||||
//head.add(nose);
|
||||
head.scale.z = 0.5;
|
||||
head.rotation.z = 5*Math.PI/8;
|
||||
head.position.y = bodyRadius+neckHeight;
|
||||
|
||||
|
||||
var horse = new THREE.Object3D();
|
||||
horse.add(body);
|
||||
horse.add(neck);
|
||||
horse.add(head);
|
||||
horse.rotation.z = -Math.PI/32;
|
||||
horse.rotation.y = (color == whiteMat) ? -Math.PI/2 : Math.PI/2;
|
||||
horse.position.y = baseHeight+bodyRadius;
|
||||
|
||||
knight.add(horse);
|
||||
knight.add(base);
|
||||
knight.name = "Knight";
|
||||
return knight;
|
||||
}
|
||||
|
||||
function createBishop(size,color) {
|
||||
var bishop = new THREE.Object3D();
|
||||
var baseHeight = size*0.1;
|
||||
var baseRadius = size*0.8;
|
||||
var base = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(baseRadius,baseRadius,baseHeight,32,1),pieceMaterial[color]);
|
||||
base.position.y = baseHeight/2;
|
||||
|
||||
var bodyRadius = size*0.6;
|
||||
var body = new THREE.Mesh(
|
||||
new THREE.SphereGeometry(bodyRadius,32,16),pieceMaterial[color]);
|
||||
body.position.y = baseHeight + bodyRadius;
|
||||
|
||||
var neckHeight = size*1.7;
|
||||
var neckBottomRadius = bodyRadius*0.3;
|
||||
var neckTopRadius = bodyRadius*0.05;
|
||||
var neck = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(neckTopRadius,neckBottomRadius,neckHeight,32,1),pieceMaterial[color]);
|
||||
neck.position.y = baseHeight + bodyRadius*2+neckHeight/2;
|
||||
|
||||
var headRadius = size*0.2;
|
||||
var head = new THREE.Mesh(
|
||||
new THREE.SphereGeometry(headRadius,32,16),pieceMaterial[color]);
|
||||
head.scale.y = 1.5;
|
||||
head.position.y = baseHeight + bodyRadius*2 +neckHeight+headRadius/2;
|
||||
|
||||
bishop.add(head);
|
||||
bishop.add(neck);
|
||||
bishop.add(body);
|
||||
bishop.add(base);
|
||||
bishop.name = "Bishop";
|
||||
return bishop;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function createQueen(size,color) {
|
||||
var queen = new THREE.Object3D();
|
||||
var baseHeight = size*0.1;
|
||||
var baseRadius = size*0.8;
|
||||
var base = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(baseRadius,baseRadius,baseHeight,32,1),pieceMaterial[color]);
|
||||
base.position.y = baseHeight/2;
|
||||
|
||||
var bodyRadius = size*0.6;
|
||||
var body = new THREE.Mesh(
|
||||
new THREE.SphereGeometry(bodyRadius,32,16),pieceMaterial[color]);
|
||||
body.position.y = baseHeight + bodyRadius;
|
||||
|
||||
var neckHeight = size*2.3;
|
||||
var neckBottomRadius = bodyRadius*0.3;
|
||||
var neckTopRadius = bodyRadius*0.05;
|
||||
var neck = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(neckTopRadius,neckBottomRadius,neckHeight,32,1),pieceMaterial[color]);
|
||||
neck.position.y = baseHeight + bodyRadius*2+neckHeight/2;
|
||||
|
||||
var collarHeight = size* 0.1;
|
||||
var collarRadius = size* 0.4;
|
||||
var collar = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(collarRadius,collarRadius,collarHeight,32,1),pieceMaterial[color]);
|
||||
collar.position.y = baseHeight+bodyRadius*2+neckHeight - size*0.1;
|
||||
|
||||
var headRadius = size*0.2;
|
||||
var head = new THREE.Mesh(
|
||||
new THREE.SphereGeometry(headRadius,32,16),pieceMaterial[color]);
|
||||
head.position.y = baseHeight + bodyRadius*2 +neckHeight+headRadius/2;
|
||||
|
||||
queen.add(head);
|
||||
queen.add(collar);
|
||||
queen.add(neck);
|
||||
queen.add(body);
|
||||
queen.add(base);
|
||||
queen.name = "Queen";
|
||||
return queen;
|
||||
}
|
||||
|
||||
|
||||
function createKing(size,color) {
|
||||
var king = new THREE.Object3D();
|
||||
var baseHeight = size*0.1;
|
||||
var baseRadius = size*0.8;
|
||||
var base = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(baseRadius,baseRadius,baseHeight,32,1),pieceMaterial[color]);
|
||||
base.position.y = baseHeight/2;
|
||||
|
||||
var bodyRadius = size*0.6;
|
||||
var body = new THREE.Mesh(
|
||||
new THREE.SphereGeometry(bodyRadius,32,16),pieceMaterial[color]);
|
||||
body.position.y = baseHeight + bodyRadius;
|
||||
|
||||
var neckHeight = size*2.3;
|
||||
var neckBottomRadius = bodyRadius*0.15;
|
||||
var neckTopRadius = bodyRadius*0.2;
|
||||
var neck = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(neckTopRadius,neckBottomRadius,neckHeight,32,1),pieceMaterial[color]);
|
||||
neck.position.y = baseHeight + bodyRadius*2+neckHeight/2;
|
||||
|
||||
var collarHeight = size* 0.4;
|
||||
var collarBottomRadius = size* 0.25;
|
||||
var collarTopRadius = size* 0.45;
|
||||
var collar = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(collarTopRadius,collarBottomRadius,collarHeight,32,1),pieceMaterial[color]);
|
||||
collar.position.y = baseHeight+bodyRadius*2+neckHeight - size*0.1;
|
||||
|
||||
var cross = new THREE.Object3D();
|
||||
var crossThickness = size*0.2;
|
||||
var crossHeight = size*0.8;
|
||||
var crossGeo = new THREE.CubeGeometry(crossThickness,crossHeight,crossThickness);
|
||||
|
||||
var hCross = new THREE.Mesh(crossGeo,pieceMaterial[color]);
|
||||
hCross.position.y = crossHeight/2;
|
||||
var vCross = new THREE.Mesh(crossGeo,pieceMaterial[color]);
|
||||
vCross.rotation.z = Math.PI/2;
|
||||
vCross.position.y = crossHeight/2;
|
||||
|
||||
cross.add(hCross);
|
||||
cross.add(vCross);
|
||||
cross.position.y = baseHeight+bodyRadius*2 + neckHeight- size*0.1+collarHeight/2;
|
||||
|
||||
|
||||
|
||||
king.add(cross);
|
||||
king.add(collar);
|
||||
king.add(neck);
|
||||
king.add(body);
|
||||
king.add(base);
|
||||
king.name = "King";
|
||||
return king;
|
||||
}
|
545
weboasis/arcade/chess/js/gui.js
Normal file
545
weboasis/arcade/chess/js/gui.js
Normal file
@ -0,0 +1,545 @@
|
||||
|
||||
// ECMAScript 5 strict mode
|
||||
/* jshint globalstrict: true*/
|
||||
/* jslint newcap: true */
|
||||
/* global THREE, $, document, window, console */
|
||||
/* global LOADING_BAR_SCALE,ROWS,COLS,PIECE_SIZE, BOARD_SIZE, FLOOR_SIZE, WIREFRAME, DEBUG, Cell, WHITE, BLACK, FEEDBACK, SHADOW */
|
||||
/* global SearchAndRedraw, UIPlayMove, camera, levels, g_allMoves:true, promotion:true, g_backgroundEngine:true, validMoves, InitializeBackgroundEngine, EnsureAnalysisStopped, newGame, redrawBoard, parsePGN, g_playerWhite:true */
|
||||
/*global Search,FormatSquare,GenerateMove,MakeMove,GetMoveSAN,MakeSquare,UnmakeMove, FormatMove, ResetGame, GetFen, GetMoveFromString, alert, InitializeFromFen, GenerateValidMoves */
|
||||
/*global g_inCheck,g_board,g_pieceList, g_toMove, g_timeout:true,g_maxply:true */
|
||||
/*global moveflagCastleKing, moveflagCastleQueen, moveflagEPC, moveflagPromotion, colorWhite*/
|
||||
/*global moveflagPromoteQueen,moveflagPromoteRook,moveflagPromoteBishop,moveflagPromoteKnight*/
|
||||
/*global piecePawn, pieceKnight, pieceBishop, pieceRook, pieceQueen, pieceKing */
|
||||
"use strict";
|
||||
(function () {
|
||||
|
||||
// jQuery pgn textarea
|
||||
var $pgn;
|
||||
// list of moves in pgn format
|
||||
var g_pgn = [];
|
||||
// jQuery check feedback
|
||||
var $info;
|
||||
|
||||
function initInfo() {
|
||||
// create the DOM element
|
||||
// to display Chc
|
||||
$info = $("<div>")
|
||||
.css("position","absolute")
|
||||
.position({
|
||||
of:$("body"),
|
||||
my:"right top",
|
||||
at:"right top"
|
||||
})
|
||||
.attr("id","info")
|
||||
.appendTo($("body"))
|
||||
.css("left","auto")
|
||||
.css("right","0");
|
||||
}
|
||||
|
||||
|
||||
function initGUI() {
|
||||
var $gui = $("<div>")
|
||||
.css("position","absolute")
|
||||
.position({
|
||||
of:$("body"),
|
||||
my:"left top",
|
||||
at:"left top"
|
||||
})
|
||||
.width(150)
|
||||
.attr("id","gui");
|
||||
|
||||
$("<p>")
|
||||
.text("menu")
|
||||
.appendTo($gui);
|
||||
|
||||
var $menudiv = $("<div>").appendTo($gui);
|
||||
|
||||
var $menu = $("<ul>").appendTo($menudiv);
|
||||
|
||||
makeButton("NewGame",newGameDialog,$menu);
|
||||
makeButton("Undo",undo,$menu);
|
||||
makeButton("Load",loadDialog,$menu);
|
||||
makeButton("Save",save,$menu);
|
||||
|
||||
$("<label>")
|
||||
.text("Promotion:")
|
||||
.append(
|
||||
$("<select>")
|
||||
.width(140)
|
||||
.append(
|
||||
$("<option>")
|
||||
.text("Queen"))
|
||||
.append(
|
||||
$("<option>")
|
||||
.text("Rook"))
|
||||
.append(
|
||||
$("<option>")
|
||||
.text("Bishop"))
|
||||
.append(
|
||||
$("<option>")
|
||||
.text("Knight"))
|
||||
.change( changePromo )
|
||||
.appendTo($menudiv)
|
||||
)
|
||||
.appendTo($menudiv);
|
||||
|
||||
|
||||
$pgn = $("<textarea>")
|
||||
.attr("cols","16")
|
||||
.attr("rows","10")
|
||||
.attr("readonly","readonly")
|
||||
.appendTo($menudiv);
|
||||
|
||||
|
||||
$("body").append($gui);
|
||||
|
||||
$gui.accordion({
|
||||
header: "p",
|
||||
collapsible: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function makeButton(name,callback,parent) {
|
||||
var $item = $("<li>").appendTo(parent);
|
||||
return $("<button>")
|
||||
.button({
|
||||
label:name
|
||||
})
|
||||
.width(140)
|
||||
.click(callback)
|
||||
.appendTo($item);
|
||||
}
|
||||
|
||||
function newGameDialog() {
|
||||
var id = "newgame";
|
||||
var dialogColor = WHITE;
|
||||
var dialogLevel = 0;
|
||||
|
||||
if ($("#"+id).length !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var $newGame = $("<div>")
|
||||
.attr("id",id)
|
||||
.attr("title","New Game")
|
||||
.appendTo($("body"));
|
||||
|
||||
// buttonset div
|
||||
var $radio = $("<p>").appendTo($newGame);
|
||||
// first button for white
|
||||
$('<input type="radio" id="white" name="color" checked="checked">')
|
||||
.click(function() {
|
||||
dialogColor = WHITE;
|
||||
})
|
||||
.appendTo($radio);
|
||||
$('<label for="white">White</label>').appendTo($radio);
|
||||
|
||||
// second button for black
|
||||
$('<input type="radio" id="black" name="color"/>')
|
||||
.click(function() {
|
||||
dialogColor = BLACK;
|
||||
})
|
||||
.appendTo($radio);
|
||||
$('<label for="black">Black</label>').appendTo($radio);
|
||||
// initialize the buttonset
|
||||
$radio.buttonset();
|
||||
|
||||
// level selector
|
||||
|
||||
var $label = $("<label>")
|
||||
.text("AI Strength:");
|
||||
var $levelSelect = $('<select>')
|
||||
.css("display","block")
|
||||
.appendTo($label)
|
||||
.change(function(event) {
|
||||
dialogLevel = $(event.currentTarget).val();
|
||||
});
|
||||
$("<p>").append($label).appendTo($newGame);
|
||||
|
||||
// add as much level configuration we have
|
||||
for (var i = 0; i < levels.length; i++) {
|
||||
$('<option>')
|
||||
.val(i)
|
||||
.text("level "+(i+1))
|
||||
.appendTo($levelSelect);
|
||||
}
|
||||
$newGame.dialog({
|
||||
close:function(event,ui) {
|
||||
$newGame.remove();
|
||||
},
|
||||
buttons: {
|
||||
"Start": function() {
|
||||
newGame(dialogColor,dialogLevel);
|
||||
$(this).remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/*
|
||||
* GAME CONTROL
|
||||
*/
|
||||
function newGame(color,level) {
|
||||
|
||||
// change AI parameters according to level
|
||||
if (levels[level] !== undefined) {
|
||||
g_timeout = levels[level].timeout;
|
||||
g_maxply = levels[level].maxply;
|
||||
}
|
||||
|
||||
EnsureAnalysisStopped();
|
||||
ResetGame();
|
||||
if (InitializeBackgroundEngine()) {
|
||||
g_backgroundEngine.postMessage("go");
|
||||
}
|
||||
|
||||
g_allMoves = [];
|
||||
clearPGN();
|
||||
|
||||
redrawBoard();
|
||||
|
||||
if (color === WHITE) {
|
||||
g_playerWhite = true;
|
||||
camera.position.x = 0;
|
||||
camera.position.z = 100; // camera on white side
|
||||
} else {
|
||||
g_playerWhite = false;
|
||||
SearchAndRedraw();
|
||||
camera.position.x = 0;
|
||||
camera.position.z = -100; // camera on black side
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function changeStartPlayer(event) {
|
||||
g_playerWhite = $(event.currentTarget).val() === "white";
|
||||
redrawBoard();
|
||||
}
|
||||
|
||||
function undo() {
|
||||
if (g_allMoves.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_backgroundEngine !== null) {
|
||||
g_backgroundEngine.terminate();
|
||||
g_backgroundEngine = null;
|
||||
}
|
||||
|
||||
UnmakeMove(g_allMoves[g_allMoves.length - 1]);
|
||||
g_allMoves.pop();
|
||||
g_pgn.pop();
|
||||
g_pgn.pop();
|
||||
updatePGN();
|
||||
|
||||
if (g_playerWhite !== Boolean(g_toMove) && g_allMoves.length !== 0) {
|
||||
UnmakeMove(g_allMoves[g_allMoves.length - 1]);
|
||||
g_allMoves.pop();
|
||||
}
|
||||
|
||||
redrawBoard();
|
||||
}
|
||||
|
||||
|
||||
function loadDialog() {
|
||||
var id = "loadGame";
|
||||
if ($("#"+id).length !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var $loadGame = $("<div>")
|
||||
.attr("id",id)
|
||||
.attr("title","Load Game")
|
||||
.appendTo($("body"));
|
||||
|
||||
$('<input>')
|
||||
.attr("type","file")
|
||||
.change(function(evt) {
|
||||
load(evt);
|
||||
$loadGame.remove();
|
||||
})
|
||||
.appendTo($loadGame);
|
||||
|
||||
$loadGame
|
||||
.dialog({
|
||||
minWidth:420,
|
||||
close:function(event,ui) {
|
||||
$loadGame.remove();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function load(evt) {
|
||||
|
||||
//Retrieve the first (and only!) File from the FileList object
|
||||
var file = evt.target.files[0];
|
||||
|
||||
if (file) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
var contents = e.target.result;
|
||||
loadPGN(contents);
|
||||
};
|
||||
reader.readAsText(file);
|
||||
} else {
|
||||
console.log("Failed to load file");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function loadFEN(fen) {
|
||||
g_allMoves = [];
|
||||
InitializeFromFen(fen);
|
||||
|
||||
EnsureAnalysisStopped();
|
||||
InitializeBackgroundEngine();
|
||||
|
||||
g_playerWhite = !!g_toMove;
|
||||
g_backgroundEngine.postMessage("position " + GetFen());
|
||||
|
||||
redrawBoard();
|
||||
}
|
||||
|
||||
function loadPGN (pgn) {
|
||||
var parsedPGN = parsePGN(pgn);
|
||||
var fen = parsedPGN.fen;
|
||||
var moves = parsedPGN.sequence;
|
||||
|
||||
g_allMoves = [];
|
||||
clearPGN();
|
||||
if (fen !== null) {
|
||||
loadFEN(fen);
|
||||
if (parsedPGN.startColor === BLACK) {
|
||||
g_pgn.push("..");
|
||||
}
|
||||
} else {
|
||||
ResetGame();
|
||||
}
|
||||
|
||||
function Piece(flag,promo) {
|
||||
this.flag = flag;
|
||||
this.promo = promo;
|
||||
}
|
||||
|
||||
|
||||
moves.forEach(function(move) {
|
||||
var i;
|
||||
var formatedMove;
|
||||
var vMoves = GenerateValidMoves();
|
||||
var pieces = {
|
||||
"P": new Piece(piecePawn,null),
|
||||
"N": new Piece(pieceKnight,moveflagPromoteKnight),
|
||||
"B": new Piece(pieceBishop,moveflagPromoteBishop),
|
||||
"R": new Piece(pieceRook,moveflagPromoteRook),
|
||||
"Q": new Piece(pieceQueen,moveflagPromoteQueen),
|
||||
"K": new Piece(pieceKing,null)
|
||||
};
|
||||
|
||||
// get the piece flag
|
||||
var piece = pieces[move.piece].flag; // [P,N,B,R,Q,K]
|
||||
// ge the color flag
|
||||
var color = (move.color === WHITE) ? 0x8 : 0x0;
|
||||
|
||||
// get the from value
|
||||
var startList = [];
|
||||
|
||||
// get all square that has this kind of piece
|
||||
var pieceIdx = (color|piece) << 4;
|
||||
|
||||
while(g_pieceList[pieceIdx] !== 0) {
|
||||
startList.push(new Cell(FormatSquare(g_pieceList[pieceIdx])));
|
||||
pieceIdx++;
|
||||
}
|
||||
|
||||
var from = move.from;
|
||||
if (from !== undefined) {
|
||||
// if we have a precision on the starting square like the columns
|
||||
// or even the position directly
|
||||
// We will filter the startList using it
|
||||
for (i = startList.length - 1; i >= 0; i--) {
|
||||
if( from.length === 1) {
|
||||
// only the row is given
|
||||
|
||||
if (from.match(/[a-h]/) && startList[i].position.charAt(0) !== from) {
|
||||
// different starting row
|
||||
startList.splice(i,1);
|
||||
} else if (from.match(/[1-8]/) && startList[i].position.charAt(1) !== from) {
|
||||
// different starting line
|
||||
startList.splice(i,1);
|
||||
}
|
||||
} else if (from.length === 2) {
|
||||
// the starting coordinate is given
|
||||
// this is then just an extra check
|
||||
if (startList[i].position !== from) {
|
||||
// different starting coordinate
|
||||
startList.splice(i,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// here we should have a list of starting square
|
||||
// only one should make a valid move
|
||||
// paired with the provided destination
|
||||
|
||||
var end = new Cell(move.to);
|
||||
var endSquare = MakeSquare(end.y, end.x);
|
||||
|
||||
var promotion = (move.promotion) ? pieces[move.promotion.substr(1)].promo : undefined; // remove the "="
|
||||
|
||||
|
||||
// take formatedMove and endSquare in a closure
|
||||
function checkMove(start) {
|
||||
var startSquare = MakeSquare(start.y, start.x);
|
||||
if (promotion !== undefined) {
|
||||
// we have a promotion so we need to generate a
|
||||
// specific move and check against it
|
||||
if(vMoves[i] === GenerateMove(startSquare, endSquare, moveflagPromotion | promotion)) {
|
||||
formatedMove = vMoves[i];
|
||||
}
|
||||
} else {
|
||||
// just checking start and end square allows to cover
|
||||
// all other special moves like "en passant" capture and
|
||||
// castling
|
||||
if ( (vMoves[i] & 0xFF) == startSquare &&
|
||||
((vMoves[i] >> 8) & 0xFF) == endSquare ) {
|
||||
formatedMove = vMoves[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// to get the move we will check withing all valide moves
|
||||
// which one match the hints given by the pgn
|
||||
|
||||
for (i = 0; i < vMoves.length; i++) {
|
||||
startList.forEach(checkMove);
|
||||
if (formatedMove) break;
|
||||
}
|
||||
|
||||
if(formatedMove) {
|
||||
UIPlayMove(formatedMove,false);
|
||||
} else {
|
||||
console.log(move);
|
||||
throw "Invalid PGN";
|
||||
}
|
||||
});
|
||||
|
||||
if (g_toMove === colorWhite) {
|
||||
g_playerWhite = true;
|
||||
camera.position.x = 0;
|
||||
camera.position.z = 100;
|
||||
} else {
|
||||
g_playerWhite = false;
|
||||
camera.position.x = 0;
|
||||
camera.position.z = -100;
|
||||
}
|
||||
|
||||
EnsureAnalysisStopped();
|
||||
if (InitializeBackgroundEngine()) {
|
||||
g_backgroundEngine.postMessage("position " + GetFen());
|
||||
}
|
||||
|
||||
redrawBoard();
|
||||
}
|
||||
|
||||
function clearPGN () {
|
||||
$pgn.val("");
|
||||
g_pgn = [];
|
||||
}
|
||||
|
||||
function addToPGN(move) {
|
||||
g_pgn.push(GetMoveSAN(move));
|
||||
updatePGN();
|
||||
}
|
||||
|
||||
function updatePGN() {
|
||||
|
||||
$pgn.val(getPGN());
|
||||
$pgn.scrollTop($pgn[0].scrollHeight);
|
||||
}
|
||||
|
||||
function getPGN() {
|
||||
var str = "";
|
||||
g_pgn.forEach(function(move,i) {
|
||||
if(i%2 === 0) {
|
||||
if (move === "..") {
|
||||
str += ((i/2)+1)+"...";
|
||||
} else {
|
||||
str += ((i/2)+1)+". "+move;
|
||||
}
|
||||
} else {
|
||||
str += " "+move+"\r\n";
|
||||
}
|
||||
});
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function save() {
|
||||
var filename = "chessSave.pgn";
|
||||
var a = document.createElement("a");
|
||||
|
||||
if (typeof a.download === "undefined")
|
||||
{
|
||||
var str = 'data:text/html,' + encodeURIComponent("<p><a download='" + filename + "' href=\"data:application/json," +
|
||||
encodeURIComponent(getPGN()) +
|
||||
"\">Download link</a></p>");
|
||||
window.open(str);
|
||||
} else {
|
||||
// auto download
|
||||
var body = document.body;
|
||||
a.textContent = filename;
|
||||
a.href = "data:application/json," + encodeURIComponent(getPGN());
|
||||
a.download = filename;
|
||||
body.appendChild(a);
|
||||
var clickEvent = document.createEvent("MouseEvent");
|
||||
clickEvent.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
||||
a.dispatchEvent(clickEvent);
|
||||
body.removeChild(a);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function changePromo(event) {
|
||||
var choice = $(event.currentTarget).val();
|
||||
switch(choice) {
|
||||
case "Queen":
|
||||
promotion = moveflagPromoteQueen;
|
||||
break;
|
||||
case "Rook":
|
||||
promotion = moveflagPromoteRook;
|
||||
break;
|
||||
case "Bishop":
|
||||
promotion = moveflagPromoteBishop;
|
||||
break;
|
||||
case "Knight":
|
||||
promotion = moveflagPromoteKnight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function displayCheck() {
|
||||
if (validMoves.length === 0) {
|
||||
$info.text(( g_inCheck ? 'Checkmate' : 'Stalemate' ));
|
||||
} else if (g_inCheck) {
|
||||
$info.text('Check');
|
||||
} else {
|
||||
$info.text('');
|
||||
}
|
||||
if ($info.text() !== '') {
|
||||
$info.show("highlight",{},500);
|
||||
} else {
|
||||
$info.hide();
|
||||
}
|
||||
}
|
||||
|
||||
window.initGUI = initGUI;
|
||||
window.initInfo = initInfo;
|
||||
window.clearPGN = clearPGN;
|
||||
window.addToPGN = addToPGN;
|
||||
window.displayCheck = displayCheck;
|
||||
window.newGame = newGame;
|
||||
|
||||
})();
|
9597
weboasis/arcade/chess/js/jquery/jquery-1.9.1.js
vendored
Normal file
9597
weboasis/arcade/chess/js/jquery/jquery-1.9.1.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
14971
weboasis/arcade/chess/js/jquery/jquery-ui-1.10.3.custom.js
vendored
Normal file
14971
weboasis/arcade/chess/js/jquery/jquery-ui-1.10.3.custom.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
weboasis/arcade/chess/js/jquery/jquery-ui-1.10.3.custom.min.js
vendored
Normal file
7
weboasis/arcade/chess/js/jquery/jquery-ui-1.10.3.custom.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
456
weboasis/arcade/chess/js/lib/OrbitAndPanControls.js
Normal file
456
weboasis/arcade/chess/js/lib/OrbitAndPanControls.js
Normal file
@ -0,0 +1,456 @@
|
||||
/**
|
||||
* @author qiao / https://github.com/qiao
|
||||
* @author mrdoob / http://mrdoob.com
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
* @author WestLangley / https://github.com/WestLangley
|
||||
* @author erich666 / http://erichaines.com
|
||||
*
|
||||
* Not quite correct: sort of assumes a 45 degree field of view.
|
||||
* Currently uses distance to target for offsetting
|
||||
*/
|
||||
|
||||
THREE.OrbitAndPanControls = function ( object, domElement ) {
|
||||
|
||||
this.addEventListener = THREE.EventDispatcher.prototype.addEventListener;
|
||||
this.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener;
|
||||
this.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener;
|
||||
this.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent;
|
||||
|
||||
this.enabled = true;
|
||||
|
||||
this.object = object;
|
||||
this.domElement = ( domElement !== undefined ) ? domElement : document;
|
||||
|
||||
// API
|
||||
|
||||
this.target = new THREE.Vector3();
|
||||
|
||||
this.userZoom = true;
|
||||
this.userZoomSpeed = 1.0;
|
||||
|
||||
this.userRotate = true;
|
||||
this.userRotateSpeed = 1.0;
|
||||
|
||||
this.autoRotate = false;
|
||||
this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
|
||||
|
||||
this.minPolarAngle = 0; // radians
|
||||
this.maxPolarAngle = Math.PI; // radians
|
||||
|
||||
this.minDistance = 0;
|
||||
this.maxDistance = Infinity;
|
||||
|
||||
// internals
|
||||
|
||||
var scope = this;
|
||||
|
||||
var EPS = 0.000001;
|
||||
|
||||
var rotateStart = new THREE.Vector2();
|
||||
var rotateEnd = new THREE.Vector2();
|
||||
var rotateDelta = new THREE.Vector2();
|
||||
|
||||
var panStart = new THREE.Vector2();
|
||||
var panEnd = new THREE.Vector2();
|
||||
var panDelta = new THREE.Vector2();
|
||||
|
||||
var dollyStart = new THREE.Vector2();
|
||||
var dollyEnd = new THREE.Vector2();
|
||||
var dollyDelta = new THREE.Vector2();
|
||||
|
||||
var phiDelta = 0;
|
||||
var thetaDelta = 0;
|
||||
var scale = 1;
|
||||
var pan = new THREE.Vector3();
|
||||
|
||||
var lastPosition = new THREE.Vector3();
|
||||
|
||||
var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
|
||||
var state = STATE.NONE;
|
||||
|
||||
// events
|
||||
|
||||
var changeEvent = { type: 'change' };
|
||||
|
||||
|
||||
this.rotateLeft = function ( angle ) {
|
||||
|
||||
if ( angle === undefined ) {
|
||||
|
||||
angle = getAutoRotationAngle();
|
||||
|
||||
}
|
||||
|
||||
thetaDelta -= angle;
|
||||
|
||||
};
|
||||
|
||||
this.rotateUp = function ( angle ) {
|
||||
|
||||
if ( angle === undefined ) {
|
||||
|
||||
angle = getAutoRotationAngle();
|
||||
|
||||
}
|
||||
|
||||
phiDelta -= angle;
|
||||
|
||||
};
|
||||
|
||||
this.panLeft = function ( distance ) {
|
||||
|
||||
var panOffset = new THREE.Vector3();
|
||||
var te = this.object.matrix.elements;
|
||||
// get X column of matrix
|
||||
panOffset.set( te[0], te[1], te[2] );
|
||||
panOffset.multiplyScalar(-distance);
|
||||
|
||||
pan.add( panOffset );
|
||||
|
||||
};
|
||||
|
||||
this.panUp = function ( distance ) {
|
||||
|
||||
var panOffset = new THREE.Vector3();
|
||||
var te = this.object.matrix.elements;
|
||||
// get Y column of matrix
|
||||
panOffset.set( te[4], te[5], te[6] );
|
||||
panOffset.multiplyScalar(distance);
|
||||
|
||||
pan.add( panOffset );
|
||||
};
|
||||
|
||||
this.dollyIn = function ( dollyScale ) {
|
||||
|
||||
if ( dollyScale === undefined ) {
|
||||
|
||||
dollyScale = getZoomScale();
|
||||
|
||||
}
|
||||
|
||||
scale /= dollyScale;
|
||||
|
||||
};
|
||||
|
||||
this.dollyOut = function ( dollyScale ) {
|
||||
|
||||
if ( dollyScale === undefined ) {
|
||||
|
||||
dollyScale = getZoomScale();
|
||||
|
||||
}
|
||||
|
||||
scale *= dollyScale;
|
||||
|
||||
};
|
||||
|
||||
this.update = function () {
|
||||
|
||||
var position = this.object.position;
|
||||
var offset = position.clone().sub( this.target );
|
||||
|
||||
// angle from z-axis around y-axis
|
||||
|
||||
var theta = Math.atan2( offset.x, offset.z );
|
||||
|
||||
// angle from y-axis
|
||||
|
||||
var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
|
||||
|
||||
if ( this.autoRotate ) {
|
||||
|
||||
this.rotateLeft( getAutoRotationAngle() );
|
||||
|
||||
}
|
||||
|
||||
theta += thetaDelta;
|
||||
phi += phiDelta;
|
||||
|
||||
// restrict phi to be between desired limits
|
||||
phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
|
||||
|
||||
// restrict phi to be betwee EPS and PI-EPS
|
||||
phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
|
||||
|
||||
var radius = offset.length() * scale;
|
||||
|
||||
// restrict radius to be between desired limits
|
||||
radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
|
||||
|
||||
// move target to panned location
|
||||
this.target.add( pan );
|
||||
|
||||
offset.x = radius * Math.sin( phi ) * Math.sin( theta );
|
||||
offset.y = radius * Math.cos( phi );
|
||||
offset.z = radius * Math.sin( phi ) * Math.cos( theta );
|
||||
|
||||
position.copy( this.target ).add( offset );
|
||||
|
||||
this.object.lookAt( this.target );
|
||||
|
||||
thetaDelta = 0;
|
||||
phiDelta = 0;
|
||||
scale = 1;
|
||||
pan.set(0,0,0);
|
||||
|
||||
if ( lastPosition.distanceTo( this.object.position ) > 0 ) {
|
||||
|
||||
this.dispatchEvent( changeEvent );
|
||||
|
||||
lastPosition.copy( this.object.position );
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
function getAutoRotationAngle() {
|
||||
|
||||
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
|
||||
|
||||
}
|
||||
|
||||
function getZoomScale() {
|
||||
|
||||
return Math.pow( 0.95, scope.userZoomSpeed );
|
||||
|
||||
}
|
||||
|
||||
function onMouseDown( event ) {
|
||||
|
||||
if ( scope.enabled === false ) { return; }
|
||||
|
||||
if ( !scope.userRotate ) { return; }
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
if ( event.button === 0 ) {
|
||||
|
||||
state = STATE.ROTATE;
|
||||
|
||||
rotateStart.set( event.clientX, event.clientY );
|
||||
|
||||
} /*else if ( event.button === 2 ) {
|
||||
|
||||
state = STATE.PAN;
|
||||
|
||||
panStart.set( event.clientX, event.clientY );
|
||||
|
||||
}*/ else if ( event.button === 2 ) {
|
||||
|
||||
state = STATE.DOLLY;
|
||||
|
||||
dollyStart.set( event.clientX, event.clientY );
|
||||
|
||||
}
|
||||
|
||||
document.addEventListener( 'mousemove', onMouseMove, false );
|
||||
document.addEventListener( 'mouseup', onMouseUp, false );
|
||||
|
||||
}
|
||||
|
||||
function onMouseMove( event ) {
|
||||
|
||||
if ( scope.enabled === false ) { return; }
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
if ( state === STATE.ROTATE ) {
|
||||
|
||||
rotateEnd.set( event.clientX, event.clientY );
|
||||
rotateDelta.subVectors( rotateEnd, rotateStart );
|
||||
|
||||
scope.rotateLeft( 2 * Math.PI * rotateDelta.x / scope.domElement.width * scope.userRotateSpeed );
|
||||
scope.rotateUp( Math.PI * rotateDelta.y / scope.domElement.height * scope.userRotateSpeed );
|
||||
|
||||
rotateStart.copy( rotateEnd );
|
||||
|
||||
} else if ( state === STATE.PAN ) {
|
||||
|
||||
panEnd.set( event.clientX, event.clientY );
|
||||
panDelta.subVectors( panEnd, panStart );
|
||||
|
||||
var position = scope.object.position;
|
||||
var offset = position.clone().sub( scope.target );
|
||||
var targetDistance = offset.length();
|
||||
if ( scope.object.fov !== undefined )
|
||||
{
|
||||
// half of the fov is center to top of screen
|
||||
targetDistance *= Math.tan( (scope.object.fov/2) * Math.PI / 180.0 );
|
||||
}
|
||||
|
||||
// we actually don't use screenWidth, since perspective camera is fixed to screen height
|
||||
scope.panLeft( 2 * panDelta.x * targetDistance / scope.domElement.height );
|
||||
scope.panUp( 2 * panDelta.y * targetDistance / scope.domElement.height );
|
||||
|
||||
panStart.copy( panEnd );
|
||||
|
||||
} else if ( state === STATE.DOLLY ) {
|
||||
|
||||
dollyEnd.set( event.clientX, event.clientY );
|
||||
dollyDelta.subVectors( dollyEnd, dollyStart );
|
||||
|
||||
if ( dollyDelta.y > 0 ) {
|
||||
|
||||
scope.dollyIn();
|
||||
|
||||
} else {
|
||||
|
||||
scope.dollyOut();
|
||||
|
||||
}
|
||||
|
||||
dollyStart.copy( dollyEnd );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onMouseUp( /* event */ ) {
|
||||
|
||||
if ( scope.enabled === false ) { return; }
|
||||
|
||||
if ( ! scope.userRotate ) { return; }
|
||||
|
||||
document.removeEventListener( 'mousemove', onMouseMove, false );
|
||||
document.removeEventListener( 'mouseup', onMouseUp, false );
|
||||
|
||||
state = STATE.NONE;
|
||||
}
|
||||
|
||||
function onMouseWheel( event ) {
|
||||
|
||||
if ( scope.enabled === false ) { return; }
|
||||
|
||||
if ( ! scope.userZoom ) { return; }
|
||||
|
||||
var delta = 0;
|
||||
|
||||
if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
|
||||
|
||||
delta = event.wheelDelta;
|
||||
|
||||
} else if ( event.detail ) { // Firefox
|
||||
|
||||
delta = - event.detail;
|
||||
|
||||
}
|
||||
|
||||
if ( delta > 0 ) {
|
||||
|
||||
scope.dollyOut();
|
||||
|
||||
} else {
|
||||
|
||||
scope.dollyIn();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function touchstart( event ) {
|
||||
|
||||
if ( scope.enabled === false ) { return; }
|
||||
|
||||
/* TODO, innards of mouse begin here
|
||||
switch ( event.touches.length ) {
|
||||
|
||||
case 1:
|
||||
state = STATE.TOUCH_ROTATE;
|
||||
|
||||
rotateStart.set( event.clientX, event.clientY );
|
||||
_state = STATE.TOUCH_ROTATE;
|
||||
_rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
state = STATE.TOUCH_DOLLY;
|
||||
|
||||
dollyStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
||||
|
||||
// classier would be to take both points for a multitouch stretch thing:
|
||||
//var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
|
||||
//var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
|
||||
//_touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
|
||||
break;
|
||||
|
||||
case 3:
|
||||
state = STATE.TOUCH_PAN;
|
||||
|
||||
panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
||||
break;
|
||||
|
||||
default:
|
||||
state = STATE.NONE;
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
function touchmove( event ) {
|
||||
|
||||
if ( scope.enabled === false ) { return; }
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
/* TODO, innards of mouse move here
|
||||
switch ( event.touches.length ) {
|
||||
|
||||
case 1:
|
||||
_rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
|
||||
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
|
||||
_touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy )
|
||||
break;
|
||||
|
||||
case 3:
|
||||
_panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
||||
break;
|
||||
|
||||
default:
|
||||
_state = STATE.NONE;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
function touchend( event ) {
|
||||
|
||||
if ( scope.enabled === false ) { return; }
|
||||
|
||||
/* from trackball. I don't think we need anything.
|
||||
switch ( event.touches.length ) {
|
||||
|
||||
case 1:
|
||||
_rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
_touchZoomDistanceStart = _touchZoomDistanceEnd = 0;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
_panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
||||
break;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
state = STATE.NONE;
|
||||
}
|
||||
|
||||
this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
|
||||
this.domElement.addEventListener( 'mousedown', onMouseDown, false );
|
||||
this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
|
||||
this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
|
||||
|
||||
this.domElement.addEventListener( 'touchstart', touchstart, false );
|
||||
this.domElement.addEventListener( 'touchend', touchend, false );
|
||||
this.domElement.addEventListener( 'touchmove', touchmove, false );
|
||||
|
||||
};
|
36506
weboasis/arcade/chess/js/lib/three.js
Normal file
36506
weboasis/arcade/chess/js/lib/three.js
Normal file
File diff suppressed because it is too large
Load Diff
710
weboasis/arcade/chess/js/lib/three.min.js
vendored
Normal file
710
weboasis/arcade/chess/js/lib/three.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
308
weboasis/arcade/chess/js/loading.js
Normal file
308
weboasis/arcade/chess/js/loading.js
Normal file
@ -0,0 +1,308 @@
|
||||
// ECMAScript 5 strict mode
|
||||
/* jshint globalstrict: true*/
|
||||
/* global THREE, $, document, window, console */
|
||||
/* global onLoaded, LOADING_BAR_SCALE,ROWS,COLS,PIECE_SIZE, BOARD_SIZE, FLOOR_SIZE, WIREFRAME, DEBUG, Cell, WHITE, BLACK, FEEDBACK, SHADOW */
|
||||
"use strict";
|
||||
|
||||
var geometries = {};
|
||||
var textures = {};
|
||||
|
||||
|
||||
(function() {
|
||||
|
||||
var $bar,$tips;
|
||||
var glow;
|
||||
|
||||
function loadResources () {
|
||||
// counter
|
||||
var loaded = 0;
|
||||
// list of all mesh and texture
|
||||
var resources = [
|
||||
'3D/json/knight.json',
|
||||
'3D/json/king.json',
|
||||
'3D/json/queen.json',
|
||||
'3D/json/bishop.json',
|
||||
'3D/json/rook.json',
|
||||
'3D/json/pawn.json',
|
||||
'3D/json/board.json',
|
||||
'3D/json/innerBoard.json',
|
||||
'texture/wood-0.jpg',
|
||||
'texture/wood-1.jpg',
|
||||
'texture/wood_N.jpg',
|
||||
'texture/wood_S.jpg',
|
||||
'texture/knight-ao.jpg',
|
||||
'texture/rook-ao.jpg',
|
||||
'texture/king-ao.jpg',
|
||||
'texture/bishop-ao.jpg',
|
||||
'texture/queen-ao.jpg',
|
||||
'texture/pawn-ao.jpg',
|
||||
'texture/floor.jpg',
|
||||
'texture/floor_N.jpg',
|
||||
'texture/floor_S.jpg',
|
||||
'texture/fakeShadow.jpg'
|
||||
];
|
||||
|
||||
// for loading mesh
|
||||
function loadJSON (url) {
|
||||
var loader = new THREE.JSONLoader();
|
||||
loader.load(url, function(geometry) {
|
||||
|
||||
geometries[url] = geometry;
|
||||
|
||||
loaded++;
|
||||
checkLoad();
|
||||
});
|
||||
}
|
||||
|
||||
// for loading texture
|
||||
function loadImage(url) {
|
||||
THREE.ImageUtils.loadTexture(
|
||||
url,
|
||||
THREE.UVMapping(),
|
||||
function(texture) {
|
||||
textures[url] = texture;
|
||||
loaded++;
|
||||
checkLoad();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// load all the resources from the list
|
||||
resources.forEach(function(url) {
|
||||
switch ( url.split('.').pop() ) {
|
||||
case 'json' :
|
||||
loadJSON(url);
|
||||
break;
|
||||
case 'jpg' :
|
||||
loadImage(url);
|
||||
break;
|
||||
default:
|
||||
throw 'invalid resource';
|
||||
}
|
||||
});
|
||||
|
||||
// control the progressBar
|
||||
// and fire the onLoaded call back on completion
|
||||
function checkLoad () {
|
||||
$bar.update(loaded/resources.length);
|
||||
if (loaded === resources.length) {
|
||||
setTimeout(onLoaded,0.1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function initGlow() {
|
||||
// create and set the green glow in the background
|
||||
var size = window.innerWidth*LOADING_BAR_SCALE*1.8;
|
||||
glow = document.createElement('canvas');
|
||||
glow.width = size;
|
||||
glow.height = size;
|
||||
document.body.appendChild(glow);
|
||||
var ctx = glow.getContext('2d');
|
||||
|
||||
// make it oval
|
||||
glow.style.width = size + "px";
|
||||
glow.style.height = Math.round(size/2) + "px";
|
||||
|
||||
|
||||
var requestId;
|
||||
function animate() {
|
||||
var dt = getDelta();
|
||||
update(dt);
|
||||
requestId = window.requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
function update(dt) {
|
||||
|
||||
ctx.clearRect(0,0,size,size);
|
||||
|
||||
// for the pulse effect
|
||||
var cycle = Math.cos(Date.now()/1000 * Math.PI);
|
||||
var maxRadius = size/2.5;
|
||||
|
||||
function lerp(a,b,p) {
|
||||
return a + (b-a)*p;
|
||||
}
|
||||
|
||||
var amplitude = maxRadius * 0.015;
|
||||
var sizeOffset = cycle*amplitude;
|
||||
var radius = maxRadius - amplitude + sizeOffset;
|
||||
var saturation = lerp(70,100,(cycle+1)/2);
|
||||
|
||||
|
||||
var grd = ctx.createRadialGradient(size/2, size/2, 0, size/2, size/2, radius);
|
||||
// fake a non linear gradient
|
||||
grd.addColorStop(0, 'hsla(90,'+saturation+'%,50%,0.5)');
|
||||
grd.addColorStop(0.125,'hsla(90,'+saturation+'%,50%,0.3828125)');
|
||||
grd.addColorStop(0.25, 'hsla(90,'+saturation+'%,50%,0.28125)');
|
||||
grd.addColorStop(0.375,'hsla(90,'+saturation+'%,50%,0.1953125)');
|
||||
grd.addColorStop(0.5, 'hsla(90,'+saturation+'%,50%,0.125)');
|
||||
grd.addColorStop(0.75, 'hsla(90,'+saturation+'%,50%,0.03125)');
|
||||
grd.addColorStop(1, 'hsla(90,'+saturation+'%,50%,0.0)');
|
||||
|
||||
// draw the gradient
|
||||
ctx.rect(0,0,size,size);
|
||||
ctx.fillStyle = grd;
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
glow.remove = function() {
|
||||
window.cancelAnimationFrame(requestId);
|
||||
this.parentNode.removeChild(this);
|
||||
};
|
||||
|
||||
var oldTime;
|
||||
function getDelta() {
|
||||
var now = Date.now();
|
||||
if (oldTime === undefined) {
|
||||
oldTime = now;
|
||||
}
|
||||
var delta = (now - oldTime)/1000;
|
||||
oldTime = now;
|
||||
return delta;
|
||||
}
|
||||
|
||||
animate();
|
||||
}
|
||||
|
||||
|
||||
function initTips() {
|
||||
// list of tips
|
||||
var tips = [
|
||||
"Aggregating wood fibers",
|
||||
"Generating pieces census report",
|
||||
"Testing board resistance",
|
||||
"Generating Matrix 8x8",
|
||||
"Answering Queen's request",
|
||||
"Carving a princess for the knight",
|
||||
"Sanding the Bishop",
|
||||
"Enrolling Pawns",
|
||||
"Generating cheat sheet",
|
||||
"Mating the king",
|
||||
"Planting virtual trees",
|
||||
"Asking Deep Blue for advice",
|
||||
"Nominating Bishops",
|
||||
"Dubbing Knights",
|
||||
"Crowning the King",
|
||||
"Waxing chessboard",
|
||||
"Evaluating the idea of an hexagonal board, and rejecting it",
|
||||
"Gathering extra vertices (just in case)",
|
||||
"Trimming edges",
|
||||
"Intimidating opponent",
|
||||
"Learning the rules"
|
||||
];
|
||||
|
||||
//jQuery object for tips
|
||||
$tips = $('<div>')
|
||||
.attr("id","tips")
|
||||
.css("color","white")
|
||||
.appendTo($('body'));
|
||||
|
||||
// how often tips changes (in ms)
|
||||
var tipTiming = 5000;
|
||||
|
||||
|
||||
$tips.update = function() {
|
||||
var self = this;
|
||||
if( tips.length > 0 ) {
|
||||
var index = Math.floor(Math.random() * tips.length);
|
||||
|
||||
var sentence = tips[index];
|
||||
tips.splice(index,1);
|
||||
$(this).text(sentence+"...");
|
||||
}
|
||||
this.timer = setTimeout(function(){self.update();},tipTiming);
|
||||
};
|
||||
|
||||
// this little ugliness is just to clear the timer
|
||||
// automagically on .remove()
|
||||
var tipsRemove = $tips.remove;
|
||||
$tips.remove = function() {
|
||||
clearTimeout(this.timer);
|
||||
tipsRemove.call(this);
|
||||
};
|
||||
$tips.update();
|
||||
|
||||
}
|
||||
|
||||
function initBar() {
|
||||
// jQuery progress bar
|
||||
$bar = $('<div>')
|
||||
.attr("id","progressbar")
|
||||
.css("width",(LOADING_BAR_SCALE*100)+"%")
|
||||
.appendTo($('body'));
|
||||
|
||||
// jQuery progress bar label
|
||||
var $label = $('<div>')
|
||||
.attr("id","progress-label")
|
||||
.appendTo($bar);
|
||||
|
||||
// setting up the progressbar
|
||||
$bar.progressbar({
|
||||
value:false,
|
||||
change: function() {
|
||||
$label.text($bar.progressbar("value") + "%");
|
||||
}
|
||||
});
|
||||
|
||||
// avoid rounded corners
|
||||
$bar.removeClass('ui-corner-all');
|
||||
$bar.children().removeClass('ui-corner-all');
|
||||
$bar.children().removeClass('ui-corner-left');
|
||||
|
||||
|
||||
// that's where the progression happens
|
||||
$bar.update = function(p) {
|
||||
p = Math.round(p*100);
|
||||
$bar.progressbar( "value", p );
|
||||
// somehow need to constantly remove it
|
||||
$bar.children().removeClass('ui-corner-right');
|
||||
};
|
||||
|
||||
$bar.update(0);
|
||||
|
||||
}
|
||||
|
||||
function centering() {
|
||||
$bar.position({
|
||||
of:window,
|
||||
my:"center center",
|
||||
at:"center center"
|
||||
});
|
||||
$tips.position({
|
||||
of:$bar,
|
||||
my:"center bottom",
|
||||
at:"center top-10"
|
||||
});
|
||||
$(glow).position({
|
||||
of:window,
|
||||
my:"center center",
|
||||
at:"center center"
|
||||
});
|
||||
|
||||
window.addEventListener('resize',centering );
|
||||
}
|
||||
|
||||
function removeLoader() {
|
||||
$bar.remove();
|
||||
$tips.remove();
|
||||
glow.remove();
|
||||
window.removeEventListener('resize',centering );
|
||||
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
// the page is loaded
|
||||
// start the resource loader
|
||||
initGlow();
|
||||
initTips();
|
||||
initBar();
|
||||
centering();
|
||||
|
||||
loadResources();
|
||||
//$bar.update(1);
|
||||
};
|
||||
|
||||
window.removeLoader = removeLoader;
|
||||
})();
|
122
weboasis/arcade/chess/js/pgnParser.js
Normal file
122
weboasis/arcade/chess/js/pgnParser.js
Normal file
@ -0,0 +1,122 @@
|
||||
// ECMAScript 5 strict mode
|
||||
/* jshint globalstrict: true*/
|
||||
/* global WHITE,BLACK */
|
||||
"use strict";
|
||||
(function() {
|
||||
/*
|
||||
var WHITE = 1;
|
||||
var BLACK = 0;
|
||||
*/
|
||||
function Move(piece,color,from,to,promotion,result,str) {
|
||||
this.piece = piece ? piece : "P";
|
||||
this.color = color;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.promotion = promotion;
|
||||
this.result = result;
|
||||
this.str = str;
|
||||
}
|
||||
|
||||
String.prototype.removeBrackets = function(open,close) {
|
||||
var count = 0;
|
||||
var newString = "";
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
var c = this.charAt(i);
|
||||
if (c === open) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
if (c === close) {
|
||||
count--;
|
||||
continue;
|
||||
}
|
||||
if (count === 0) {
|
||||
newString += c;
|
||||
}
|
||||
}
|
||||
return newString;
|
||||
};
|
||||
|
||||
function parsePGN(pgn) {
|
||||
var moves = {};
|
||||
moves.fen = null;
|
||||
moves.sequence = [];
|
||||
moves.startColor = WHITE;
|
||||
|
||||
var color = WHITE;
|
||||
|
||||
//var re_fen = /[pnbrqkPNBRQK1-8]+(\/[pnbrqkPNBRQK1-8]+){7} +[wb] +([KQ]{1,2}|-) *([kq]{1,2}|-)( +(([a-h][1-8])|-))? +\d+ +\d+/
|
||||
var re_fen = /\[FEN *" *([pnbrqkPNBRQK1-8]+(?:\/[pnbrqkPNBRQK1-8]+){7} +([wb]) +(?:[KQ]{1,2}|-) *(?:[kq]{1,2}|-)(?: +(?:(?:[a-h][1-8])|-))? +\d+ +\d+) *" *\]/;
|
||||
var match = pgn.match(re_fen);
|
||||
if (match) {
|
||||
moves.fen = match[1];
|
||||
color = match[2] === "w" ? WHITE : BLACK;
|
||||
moves.startColor = color;
|
||||
}
|
||||
|
||||
var cleanPGN = pgn
|
||||
.removeBrackets("[","]") // removes metadata
|
||||
.removeBrackets("{","}") // removes comments
|
||||
.removeBrackets("(",")") // removes comments
|
||||
.replace(/\$\d+/g,'') // removes this thing
|
||||
.replace(/\d+\.{1,3}/g,'') // removes move numbers
|
||||
.replace(/\s+/g,' ') // replaces multiple whitespaces by simple spaces
|
||||
.trim() // removes front and back whitespaces
|
||||
.replace(/(0-1)$/g,'') // result black won
|
||||
.replace(/(1-0)$/g,'') // result white won
|
||||
.replace(/(1\/2-1\/2)$/g,'') // result draw
|
||||
.replace(/(\*)$/g,'') // result ongoing
|
||||
.trim()
|
||||
.split(' '); // split moves
|
||||
|
||||
// regex for basic moves
|
||||
// |pieces | |src col/row| |dest col/row| promo |check|
|
||||
var re_pieceMove =/^([NBRQK])?([a-h]?[1-8]?)?x?([a-h][1-8])(=[NBRQK])?([+#])?/;
|
||||
// regex for castling
|
||||
var re_castling = "(O-O(?:-O)?)([+#])?";
|
||||
var castling = {
|
||||
"O-O" : {
|
||||
from:['e8','e1'],
|
||||
to:['g8','g1']
|
||||
},
|
||||
"O-O-O": {
|
||||
from:['e8','e1'],
|
||||
to:['c8','c1']
|
||||
}
|
||||
};
|
||||
|
||||
cleanPGN.forEach(function(move) {
|
||||
var info=[];
|
||||
|
||||
info = move.match(re_pieceMove);
|
||||
if(info) {
|
||||
moves.sequence.push(new Move(
|
||||
info[1],
|
||||
color,
|
||||
info[2],
|
||||
info[3],
|
||||
info[4],
|
||||
info[5],
|
||||
move
|
||||
));
|
||||
}
|
||||
|
||||
info = move.match(re_castling);
|
||||
if(info) {
|
||||
moves.sequence.push(new Move(
|
||||
"K",
|
||||
color,
|
||||
castling[info[1]].from[color],
|
||||
castling[info[1]].to[color],
|
||||
undefined,
|
||||
info[2],
|
||||
move
|
||||
));
|
||||
}
|
||||
color = 1-color;
|
||||
});
|
||||
|
||||
return moves;
|
||||
}
|
||||
window.parsePGN = parsePGN;
|
||||
})();
|
27
weboasis/arcade/chess/js/three-extend.js
Normal file
27
weboasis/arcade/chess/js/three-extend.js
Normal file
@ -0,0 +1,27 @@
|
||||
// ECMAScript 5 strict mode
|
||||
/* jshint globalstrict: true*/
|
||||
/* global SHADOW,onOBJLoaded,THREE,console,BLACK,WHITE,WIREFRAME */
|
||||
|
||||
/*
|
||||
* few extension or modification to some three.js functionnality
|
||||
* often to avoid some repetitive tasks
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
(function () {
|
||||
var clone = THREE.Texture.prototype.clone;
|
||||
THREE.Texture.prototype.clone = function( texture ) {
|
||||
var newTexture = clone.call(this,texture);
|
||||
// The purpose of all this is to automagically switch this
|
||||
// property to true after cloning.
|
||||
// Since it originally doesn't do it by default
|
||||
newTexture.needsUpdate = true;
|
||||
return newTexture;
|
||||
};
|
||||
|
||||
THREE.Texture.prototype.tile = function( factor ) {
|
||||
// because I do that a lot (:
|
||||
this.wrapS = this.wrapT = THREE.RepeatWrapping;
|
||||
this.repeat.set(factor,factor);
|
||||
};
|
||||
})();
|
Reference in New Issue
Block a user