Skip to content

Instantly share code, notes, and snippets.

@studentIvan
Created March 15, 2012 23:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save studentIvan/2047522 to your computer and use it in GitHub Desktop.
Save studentIvan/2047522 to your computer and use it in GitHub Desktop.
Batman Chess
###
* 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 = !@currentPlayer.check
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