Created
March 15, 2012 23:08
-
-
Save studentIvan/2047522 to your computer and use it in GitHub Desktop.
Batman Chess
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### | |
* Batman Chess | |
* By github.com/studentIvan | |
### | |
class Player | |
selectedCell: 0 | |
isComputer: false | |
myTurn: false | |
myColor: 'white' | |
board: 0 | |
check: false # шах | |
myUnits: [] | |
variants: [] | |
setColor: (color) -> @myColor = color | |
getColor: -> @myColor | |
setBoard: (board) -> @board = board | |
startTurn: -> | |
@board.calculateAttackPositions() | |
@myUnits = [] | |
@variants = [] | |
for y in [8..1] | |
for x in [1..8] | |
if @myColor is @board.cell(x, y).figure.color then @myUnits.push(@board.cell(x, y).figure) | |
for unit in @myUnits | |
# everyday i am shuffling | |
for y in [8..1] | |
for x in [1..8] | |
if not (y is unit.posY and x is unit.posX) | |
offsetX = if x > unit.posX then (x - unit.posX) else ((unit.posX - x)*-1) | |
offsetY = if y > unit.posY then (y - unit.posY) else ((unit.posY - y)*-1) | |
state = @board.correctTurnPath(unit, @board.cell(x, y), offsetX, offsetY) | |
if state then @variants.push({unit: unit, x: offsetX, y: offsetY, i: 0, p: 0}) | |
if @variants.length is 0 | |
alert(@board.nextPlayer.getColor() + ' player win') | |
return false | |
if @isComputer | |
return @computerTurn() | |
else | |
@myTurn = true | |
finishTurn: -> | |
@myTurn = false | |
computerTurn: -> | |
targetX = 1 | |
targetY = 1 | |
selectedX = 1 | |
selectedY = 1 | |
enemyColor = @board.nextPlayer.getColor() | |
for variant in @variants | |
targetCell = @board.cell(variant.unit.posX + variant.x, variant.unit.posY + variant.y) | |
variant.i = 110 | |
if targetCell.attacked[enemyColor] then variant.i -= variant.unit.price | |
if targetCell.figure.color is enemyColor then variant.i += targetCell.figure.price | |
# симуляция хода | |
variant.unit.posX += variant.x | |
variant.unit.posY += variant.y | |
for y in [8..1] | |
for x in [1..8] | |
if not (y is variant.unit.posY and x is variant.unit.posX) | |
offsetX = if x > variant.unit.posX then (x - variant.unit.posX) else ((variant.unit.posX - x)*-1) | |
offsetY = if y > variant.unit.posY then (y - variant.unit.posY) else ((variant.unit.posY - y)*-1) | |
if variant.unit.checkAttackCorrect(offsetX, offsetY) | |
if @board.scanPath(variant.unit, offsetX, offsetY) | |
variant.i += Math.floor(@board.cell(variant.unit.posX, variant.unit.posY).figure.price / 10) | |
variant.unit.posX -= variant.x | |
variant.unit.posY -= variant.y | |
max = -120 | |
for variant in @variants | |
if variant.i > max then max = variant.i | |
best = [] | |
for variant in @variants | |
variant.p = if variant.i is max then 100 else Math.floor((variant.i / max) * 100) | |
if variant.p is 100 then best.push(variant) | |
computerTurn = 0 | |
if best.length > 1 | |
z = Math.floor(Math.random() * (best.length + 1)) - 1 | |
computerTurn = best[if z < 1 then 0 else z] | |
else | |
computerTurn = best[0] | |
console.log(@variants) | |
targetX = computerTurn.unit.posX + computerTurn.x | |
targetY = computerTurn.unit.posY + computerTurn.y | |
selectedX = computerTurn.unit.posX | |
selectedY = computerTurn.unit.posY | |
{fX: selectedX, fY: selectedY, tX: targetX, tY: targetY} | |
class AIPlayer extends Player | |
isComputer: true | |
class ChessBoard | |
map: {} | |
side: 400 | |
step: 50 | |
clBlack: '#765' | |
clWhite: '#eee' | |
alphabet: ['_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] | |
whitePlayer: 0 | |
blackPlayer: 0 | |
currentPlayer: 0 | |
nextPlayer: 0 | |
slug: 0 | |
constructor: (side) -> | |
boardCanvas = document.getElementById('chess') | |
if (@rc = boardCanvas.getContext('2d')) | |
if side | |
@side = side | |
@step = Math.floor(@side/8) | |
boardCanvas.height = boardCanvas.width = @side + Math.floor(@side / 10) + 1 | |
@redraw() | |
that = this | |
boardCanvas.onclick = (event) -> | |
eX = if event.clientX? then event.clientX else event.pageX; | |
eY = if event.clientY? then event.clientY else event.pageY; | |
cellX = Math.floor((eX - Math.floor(that.side / 10)) / that.step) + 1; | |
cellY = ((Math.floor((eY - Math.floor(that.side / 10)) / that.step) + 1) - 9) * -1; | |
if (cellX < 1) then cellX = 1 else if (cellX > 8) then cellX = 8 | |
if (cellY < 1) then cellY = 1 else if (cellY > 8) then cellY = 8 | |
that.click(cellX, cellY) | |
@slug = new Figure('hasNoColor', 0, 0) | |
else | |
alert('Your browser not support canvas') | |
isEmptyCell: (cell) -> cell.figure is @slug | |
correctTurnPath: (figure, cell, offsetX, offsetY) -> | |
if (figure.checkMovementCorrect(offsetX, offsetY) and @isEmptyCell(cell)) or | |
(@nextPlayer.getColor() is cell.figure.color and figure.checkAttackCorrect(offsetX, offsetY)) | |
if @currentPlayer.check | |
if @scanPath(figure, offsetX, offsetY) | |
xcell = @cell(figure.posX, figure.posY) | |
tmpFigure = xcell.figure | |
xcell.figure = @slug | |
figure.posX += offsetX | |
figure.posY += offsetY | |
x2cell = @cell(figure.posX, figure.posY) | |
tmp2Figure = x2cell.figure | |
x2cell.figure = figure | |
figure.posX -= offsetX | |
figure.posY -= offsetY | |
@calculateAttackPositions() | |
r = [email protected] | |
x2cell.figure = tmp2Figure | |
xcell.figure = tmpFigure | |
@calculateAttackPositions(false) | |
if r then console.info('avoid') | |
return r | |
else | |
return false | |
else | |
return @scanPath(figure, offsetX, offsetY) | |
else | |
return false | |
scanPath: (figure, offsetX, offsetY) -> | |
# алгоритм поиска препядствий | |
if figure.canPassThrough | |
if figure.debug then console.log('%s can pass through', figure.name) | |
return true | |
else | |
if figure.debug then console.log('start searching algorythm for %s', figure.name) | |
targetX = figure.posX + offsetX | |
targetY = figure.posY + offsetY | |
currentX = figure.posX | |
currentY = figure.posY | |
while not (currentX is targetX and currentY is targetY) | |
if currentX isnt targetX | |
if targetX > currentX then currentX++ | |
if targetX < currentX then currentX-- | |
if currentY isnt targetY | |
if targetY > currentY then currentY++ | |
if targetY < currentY then currentY-- | |
if figure.debug then console.log('currentX is %d of %d, currentY is %d of %d', currentX, targetX, currentY, targetY) | |
if !@isEmptyCell(@cell(currentX, currentY)) | |
return (currentX is targetX and currentY is targetY) | |
return true | |
click: (x, y) -> | |
cell = @cell(x, y) | |
console.log("%s player click on: x %d, y %d (%s) (%s)", | |
@currentPlayer.getColor(), x, y, cell.name, if cell.clear then 'clear' else 'figure') | |
selected = @currentPlayer.selectedCell | |
if (((selected isnt 0) and (selected.name isnt cell.name)) or @currentPlayer.isComputer) | |
figure = selected.figure | |
offsetX = if x > figure.posX then (x - figure.posX) else ((figure.posX - x)*-1) | |
offsetY = if y > figure.posY then (y - figure.posY) else ((figure.posY - y)*-1) | |
if @correctTurnPath(figure, cell, offsetX, offsetY) | |
figure.move(offsetX, offsetY) | |
@currentPlayer.selectedCell = 0 | |
@currentPlayer.finishTurn() | |
result = @nextPlayer.startTurn() | |
tmpPlayer = @currentPlayer | |
@currentPlayer = @nextPlayer | |
@nextPlayer = tmpPlayer | |
if result.tX? | |
@currentPlayer.selectedCell = @cell(result.fX, result.fY) | |
console.log("%s player click on: x %d, y %d (%s) (%s)", | |
@currentPlayer.getColor(), result.fX, result.fY, @currentPlayer.selectedCell.name, 'figure') | |
that = this | |
callback = -> that.click(result.tX, result.tY) | |
setTimeout callback, 1000 | |
else | |
console.log("wrong turn try again") | |
@currentPlayer.selectedCell = 0 | |
else | |
if (!cell.clear and (cell.figure.color is @currentPlayer.getColor())) | |
@currentPlayer.selectedCell = cell | |
cell: (x, y, data) -> | |
if data then @map['x' + x + 'y' + y] = data else return @map['x' + x + 'y' + y] | |
redraw: -> | |
offsetXY = @side / 10 | |
cellBlack = false | |
cursorY = offsetXY | |
@rc.font = Math.floor(@step/4) + 'px sans-serif' | |
for y in [8..1] | |
cursorX = offsetXY | |
@rc.strokeText(y, offsetXY - Math.floor(@step/3.2), cursorY + Math.floor(@step/2)) | |
for x in [1..8] | |
if y is 8 then @rc.strokeText(@alphabet[x], cursorX + Math.floor(@step/2), offsetXY - Math.floor(@step/3.2)) | |
@rc.fillStyle = if cellBlack then @clBlack else @clWhite | |
@cell(x, y, {black: cellBlack, name: @alphabet[x] + y, | |
clear: true, x: cursorX, y: cursorY, figure: @slug, | |
attacked: {'white': false, 'black': false}}) | |
cellBlack = !cellBlack | |
@rc.fillRect(cursorX, cursorY, @step, @step) | |
cursorX += @step | |
cellBlack = !cellBlack | |
cursorY += @step | |
@rc.lineWidth = 2 | |
@rc.strokeStyle = @clBlack | |
@rc.strokeRect(offsetXY, offsetXY, @side-4, @side-4) | |
#console.log("board redrawed") | |
calculateAttackPositions: (lmao) -> | |
y = x = 1 #phpStorm bug | |
@currentPlayer.check = false | |
@nextPlayer.check = false | |
for y in [8..1] | |
for x in [1..8] | |
cell = @cell(x, y) | |
cell.attacked['white'] = false | |
cell.attacked['black'] = false | |
for y in [8..1] | |
for x in [1..8] | |
cell = @cell(x, y) | |
if !@isEmptyCell(cell) | |
figure = cell.figure | |
for fRy in [8..1] | |
for fRx in [1..8] | |
if not (fRy is figure.posY and fRx is figure.posX) | |
offsetX = if fRx > figure.posX then (fRx - figure.posX) else ((figure.posX - fRx)*-1) | |
offsetY = if fRy > figure.posY then (fRy - figure.posY) else ((figure.posY - fRy)*-1) | |
debugOffed = false | |
if figure.debug | |
figure.debug = false | |
debugOffed = true | |
attackState = figure.checkAttackCorrect(offsetX, offsetY) | |
if attackState | |
if @scanPath(figure, offsetX, offsetY) | |
c = @cell(fRx, fRy) | |
c.attacked[figure.color] = true | |
if (c.figure.king) and (c.figure.color isnt figure.color) | |
player = if @currentPlayer.getColor() is c.figure.color then @currentPlayer else @nextPlayer | |
player.check = true | |
if lmao? then console.info('check for %s player', player.getColor()) | |
if debugOffed then figure.debug = true | |
true | |
place: (figure) -> | |
if figure.board is 0 then figure.board = this | |
@clearCell(figure.posX, figure.posY) | |
@rc.strokeStyle = if figure.color is 'white' then 'black' else 'white' | |
@rc.font = @step + 'px sans-serif' | |
@rc.fillStyle = figure.color | |
cell = @cell(figure.posX, figure.posY); | |
@rc.strokeText(figure.symbol(), cell.x, cell.y + @step - (@step / 8)) | |
@rc.fillText(figure.symbol(), cell.x, cell.y + @step - (@step / 8)) | |
cell.clear = false | |
cell.figure = figure | |
true | |
clearCell: (x, y) -> | |
cell = @cell(x, y) | |
@rc.fillStyle = if cell.black then @clBlack else @clWhite | |
@rc.fillRect(cell.x, cell.y, @step, @step) | |
cell.clear = true | |
cell.figure = @slug | |
true | |
move: (figure, offsetX, offsetY) -> | |
@clearCell(figure.posX, figure.posY) | |
figure.posX += offsetX | |
figure.posY += offsetY | |
@place(figure) | |
console.info("%s figure %s moved from %s to %s", figure.color, figure.name, | |
@alphabet[(figure.posX - offsetX)] + (figure.posY - offsetY).toString(), | |
@alphabet[figure.posX] + figure.posY) | |
newGame: (whitePlayer, blackPlayer) -> | |
if !whitePlayer or !blackPlayer then alert('fatal error') | |
console.log("new game started") | |
@whitePlayer = whitePlayer | |
@whitePlayer.setColor('white') | |
@whitePlayer.setBoard(this) | |
@blackPlayer = blackPlayer | |
@blackPlayer.setColor('black') | |
@blackPlayer.setBoard(this) | |
@currentPlayer = @whitePlayer | |
@nextPlayer = @blackPlayer | |
@redraw() | |
for x in [1..8] | |
@place(new Pawn('black', x, 7)) | |
@place(new Pawn('white', x, 2)) | |
@place(new King('black', 5, 8)) | |
@place(new King('white', 5, 1)) | |
@place(new Queen('black', 4, 8)) | |
@place(new Queen('white', 4, 1)) | |
@place(new Rook('black', 1, 8)) | |
@place(new Rook('black', 8, 8)) | |
@place(new Rook('white', 1, 1)) | |
@place(new Rook('white', 8, 1)) | |
@place(new Knight('black', 2, 8)) | |
@place(new Knight('black', 7, 8)) | |
@place(new Knight('white', 2, 1)) | |
@place(new Knight('white', 7, 1)) | |
@place(new Bishop('black', 3, 8)) | |
@place(new Bishop('black', 6, 8)) | |
@place(new Bishop('white', 3, 1)) | |
@place(new Bishop('white', 6, 1)) | |
@currentPlayer.startTurn() | |
true | |
### | |
IR | |
inverse relation | |
<a,b> = <b,a> | |
FF | |
full freedom <a,b> (x, y) | |
+a e A, -a e A, +b e A, -b e A | |
HF | |
half freedom <a,b> (x) | |
+a e A, -a e A, +b e A | |
ER | |
equivalence relation | |
a = b | |
### | |
class Figure | |
price: 0 | |
posX: 0 | |
posY: 0 | |
color: 'black' | |
board: 0 | |
turns: [] | |
attacks: [] | |
canPassThrough: false | |
debug: false | |
king: false | |
constructor: (c, x, y) -> | |
@color = c | |
@posX = x | |
@posY = y | |
turn.status = true for turn in @turns | |
attack.status = true for attack in @attacks | |
for turn in @turns | |
if turn.IR and turn.x isnt turn.y | |
turn.IR = false | |
newTurn = {ER:turn.ER, IR:false, FF:turn.FF, HF:turn.HF} | |
newTurn.x = turn.y | |
newTurn.y = turn.x | |
@turns.push(newTurn) | |
for attack in @attacks | |
if attack.IR and attack.x isnt attack.y | |
attack.IR = false | |
newAttack = {ER:attack.ER, IR:false, FF:attack.FF, HF:attack.HF} | |
newAttack.x = attack.y | |
newAttack.y = attack.x | |
@attacks.push(newAttack) | |
move: (offsetX, offsetY) -> | |
if (@board isnt 0) | |
@board.move(this, offsetX, offsetY) | |
symbol: -> | |
return if @color is 'white' then '\u2659' else '\u265F' | |
checkAttackCorrect: (offsetX, offsetY) -> | |
if @color is 'black' | |
offsetX *= -1 | |
offsetY *= -1 | |
if @debug then console.log('calling checkAttackCorrect') | |
for attack in @attacks | |
if attack.status and attack.x isnt 'u' | |
if (attack.FF or attack.HF) and Math.abs(offsetX) isnt attack.x | |
attack.status = false | |
if @debug then console.log("#1 abs offsetX (%d) is not attack.x (%d)", Math.abs(offsetX), attack.x) | |
else if (!(attack.FF or attack.HF)) | |
if offsetX isnt attack.x | |
attack.status = false | |
if @debug then console.log("#2 offsetX (%d) is not attack.x (%d)", offsetX, attack.x) | |
if attack.status and attack.y isnt 'u' | |
if attack.FF and Math.abs(offsetY) isnt attack.y | |
attack.status = false | |
if @debug then console.log("#3 offsetY (%d) is not attack.y (%d)", offsetY, attack.y) | |
else if (!(attack.FF or attack.HF)) | |
if offsetY isnt attack.y | |
attack.status = false | |
if @debug then console.log("#4 offsetY (%d) is not attack.y (%d)", offsetY, attack.y) | |
if attack.status and attack.ER and Math.abs(offsetX) isnt Math.abs(offsetY) | |
attack.status = false | |
if @debug then console.log("#5 abs offsetX (%d) is not abs offsetY (%d)", Math.abs(offsetX), Math.abs(offsetY)) | |
status = false | |
for attack in @attacks | |
if attack.status then status = true else attack.status = true | |
return status | |
checkMovementCorrect: (offsetX, offsetY) -> | |
if @debug then console.log('calling checkMovementCorrect') | |
if offsetX is 0 and offsetY is 0 | |
return true | |
if @color is 'black' | |
offsetX *= -1 | |
offsetY *= -1 | |
for turn in @turns | |
if turn.status and turn.x isnt 'u' | |
if (turn.FF or turn.HF) and Math.abs(offsetX) isnt turn.x | |
turn.status = false | |
if @debug then console.log("#1 abs offsetX (%d) is not turn.x (%d)", Math.abs(offsetX), turn.x) | |
else if (!(turn.FF or turn.HF)) | |
if offsetX isnt turn.x | |
turn.status = false | |
if @debug then console.log("#2 offsetX (%d) is not turn.x (%d)", offsetX, turn.x) | |
if turn.status and turn.y isnt 'u' | |
if turn.FF and Math.abs(offsetY) isnt turn.y | |
turn.status = false | |
if @debug then console.log("#3 offsetY (%d) is not turn.y (%d)", offsetY, turn.y) | |
else if (!(turn.FF or turn.HF)) | |
if offsetY isnt turn.y | |
turn.status = false | |
if @debug then console.log("#4 offsetY (%d) is not turn.y (%d)", offsetY, turn.y) | |
if turn.status and turn.ER and Math.abs(offsetX) isnt Math.abs(offsetY) | |
turn.status = false | |
if @debug then console.log("#5 abs offsetX (%d) is not abs offsetY (%d)", Math.abs(offsetX), Math.abs(offsetY)) | |
#if @debug then console.log(@turns) | |
status = false | |
for turn in @turns | |
if turn.status then status = true else turn.status = true | |
return status | |
class Pawn extends Figure | |
price: 1 | |
turns: [{x:0, y:1, ER:false, IR:false, FF:false, HF:false}] | |
attacks: [{x:1, y:1, ER:true, IR:false, FF:false, HF:true}] | |
name: 'pawn' | |
symbol: -> | |
return if @color is 'white' then '\u2659' else '\u265F' | |
class Rook extends Figure | |
price: 5 | |
turns: [{x:'u', y:0, ER:false, IR:true, FF:true, HF:false}] | |
attacks: [{x:'u', y:0, ER:false, IR:true, FF:true, HF:false}] | |
name: 'rook' | |
symbol: -> | |
return if @color is 'white' then '\u2656' else '\u265C' | |
class Bishop extends Figure | |
price: 3 | |
turns: [{x:'u', y:'u', ER:true, IR:true, FF:true, HF:false}] | |
attacks: [{x:'u', y:'u', ER:true, IR:true, FF:true, HF:false}] | |
name: 'bishop' | |
symbol: -> | |
return if @color is 'white' then '\u2657' else '\u265D' | |
class King extends Figure | |
price: 100 | |
turns: [{x:1, y:1, ER:true, IR:true, FF:true, HF:false}, {x:0, y:1, ER:false, IR:true, FF:true, HF:false}] | |
attacks: [{x:1, y:1, ER:true, IR:true, FF:true, HF:false}, {x:0, y:1, ER:false, IR:true, FF:true, HF:false}] | |
name: 'king' | |
king: true | |
symbol: -> | |
return if @color is 'white' then '\u2654' else '\u265A' | |
class Queen extends Figure | |
price: 9 | |
turns: [{x:'u', y:'u', ER:true, IR:true, FF:true, HF:false}, {x:0, y:'u', ER:false, IR:true, FF:true, HF:false}] | |
attacks: [{x:'u', y:'u', ER:true, IR:true, FF:true, HF:false}, {x:0, y:'u', ER:false, IR:true, FF:true, HF:false}] | |
name: 'queen' | |
symbol: -> | |
return if @color is 'white' then '\u2655' else '\u265B' | |
class Knight extends Figure | |
price: 3 | |
turns: [{x:2, y:1, ER:false, IR:true, FF:true, HF:false}] | |
attacks: [{x:2, y:1, ER:false, IR:true, FF:true, HF:false}] | |
name: 'knight' | |
canPassThrough: true | |
symbol: -> | |
return if @color is 'white' then '\u2658' else '\u265E' | |
board = new ChessBoard(Math.floor(document.documentElement.clientHeight/1.25)) | |
board.newGame(new Player(), new AIPlayer()) | |
#board.newGame(new Player(), new Player()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment