-
-
Save alexey-krivoshapko/c49f8cff44b018307c73ac7ad66543d9 to your computer and use it in GitHub Desktop.
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
import { getBoardAsString, getXYByPosition, getElementByXY, getBoardSize, getHeadPosition } from './utils'; | |
import {ELEMENT, COMMANDS} from './constants'; | |
export class Bot { | |
constructor() { | |
this.init(); | |
} | |
run(board) { | |
this.update(board); | |
for (let i = 0; i < this.data.length; i++) { | |
let p = this.data[i]; | |
this.enemiesLength += this.enemiesElements().indexOf(p) > -1; | |
this.playersLength += this.playersElements().indexOf(p) > -1; | |
} | |
for (let i = 0; i < this.data.length; i++) { | |
let p = this.data[i]; | |
if (this.needed(p)) { | |
let x = i % this.size; | |
let y = Math.floor(i / this.size); | |
this.targets.push({ | |
x: x, | |
y: y, | |
l: Math.abs(x - this.head.position.x) + Math.abs(y - this.head.position.y), | |
c: p, | |
}); | |
} | |
if (this.debug) { | |
let state = this.validate(this.data[i], i); | |
this.updateBoard(state); | |
} | |
} | |
if (this.debug) { | |
this.debugInfo(); | |
} | |
return this; | |
} | |
update(board) { | |
this.board = ''; | |
this.data = board; | |
this.targets = []; | |
this.target = null; | |
this.enemiesLength = 0; | |
this.playersLength = 0; | |
this.size = getBoardSize(board); | |
this.setHead(); | |
} | |
init() { | |
this.board = ''; | |
this.data = ''; | |
this.debug = true; | |
this.targets = []; | |
this.target = null; | |
this.prevHead = {x:14, y:14}; | |
this.enemiesLength = 0; | |
this.playersLength = 0; | |
this.command = COMMANDS.RIGHT; | |
this.size = getBoardSize(board); | |
this.head = { | |
head: 'head', | |
sing: ELEMENT.HEAD_RIGHT, | |
position: { | |
x: 0, | |
y: 0 | |
}, | |
evil: 0, | |
fly: 0, | |
}; | |
} | |
setHead() { | |
let head_p = getHeadPosition(this.data); | |
let head_c = getElementByXY(this.data, head_p); | |
let head = function() { | |
if (head_c === ELEMENT.HEAD_EVIL) { | |
return 'evil'; | |
} else if(head_c === ELEMENT.HEAD_FLY) { | |
return 'fly'; | |
} else { | |
return 'head'; | |
} | |
}(); | |
let evil = function(this_head) { | |
if (this_head !== head && head === 'evil') { | |
return 10; | |
} else { | |
return Math.max(this_head.evil - 1, 0); | |
} | |
}(this.head); | |
let fly = function(this_head) { | |
if (this_head !== head && head === 'fly') { | |
return 10; | |
} else { | |
return Math.max(this_head.fly - 1, 0); | |
} | |
}(this.head); | |
this.head = { | |
head: head, | |
sing: head_c, | |
position: { | |
x: head_p.x, | |
y: head_p.y | |
}, | |
evil: evil, | |
fly: fly, | |
}; | |
} | |
debugInfo() { | |
console.log(getBoardAsString(this.board)); | |
console.log({ | |
head: this.head, | |
// size: this.size, | |
// command: this.command, | |
playersLength: this.playersLength, | |
enemiesLength: this.enemiesLength, | |
isBiggest: this.isBiggest(), | |
target: this.target | |
}); | |
} | |
updateBoard(state) { | |
this.board += (state ? '⛉' : '⛊'); | |
} | |
validate(point, i) { | |
return this.nearOpen(i) && this.allowed(point); | |
} | |
nearOpen(i) { | |
let rate = 0; | |
let position = getXYByPosition(this.data, i); | |
let allowed = { t: 0, r: 0, b: 0, l: 0 }; | |
allowed.t = this.nearRate(position, 'top'); | |
rate += allowed.t; | |
allowed.r = this.nearRate(position, 'right'); | |
rate += allowed.r; | |
allowed.b = this.nearRate(position, 'bottom'); | |
rate += allowed.b; | |
allowed.l = this.nearRate(position, 'left'); | |
rate += allowed.l; | |
if (rate < 2) { | |
return false; | |
} else if (rate > 2) { | |
return true; | |
} else { | |
// return true; | |
let reverseRate = 0; | |
if (allowed.t) { | |
reverseRate += this.nearRate({x: position.x, y: position.y - 2}, 'top'); | |
reverseRate += this.nearRate({x: position.x, y: position.y - 2}, 'right'); | |
reverseRate += this.nearRate({x: position.x, y: position.y - 2}, 'left'); | |
} | |
if (allowed.r) { | |
reverseRate += this.nearRate({x: position.x + 2, y: position.y}, 'top'); | |
reverseRate += this.nearRate({x: position.x + 2, y: position.y}, 'right'); | |
reverseRate += this.nearRate({x: position.x + 2, y: position.y}, 'bottom'); | |
} | |
if (allowed.b) { | |
reverseRate += this.nearRate({x: position.x, y: position.y + 2}, 'bottom'); | |
reverseRate += this.nearRate({x: position.x, y: position.y + 2}, 'right'); | |
reverseRate += this.nearRate({x: position.x, y: position.y + 2}, 'left'); | |
} | |
if (allowed.l) { | |
reverseRate += this.nearRate({x: position.x - 2, y: position.y}, 'top'); | |
reverseRate += this.nearRate({x: position.x - 2, y: position.y}, 'right'); | |
reverseRate += this.nearRate({x: position.x - 2, y: position.y}, 'bottom'); | |
} | |
return reverseRate > 3; | |
} | |
} | |
getCommand() { | |
let command = ''; | |
let head = getHeadPosition(this.data); | |
this.targets.sort(function (a, b) { | |
return a.l - b.l; | |
}); | |
console.log(this.targets[0]); | |
let target = this.targets[0] || {x: 14, y: 14}; | |
let commands = [ | |
COMMANDS.UP, | |
COMMANDS.RIGHT, | |
COMMANDS.DOWN, | |
COMMANDS.LEFT, | |
COMMANDS.ACT, | |
]; | |
let index = head.x + head.y * this.size; | |
if (head.x < target.x && head.x >= this.prevHead.x) { | |
commands.unshift(COMMANDS.RIGHT); | |
} else if (head.x > target.x && head.x <= this.prevHead.x) { | |
commands.unshift(COMMANDS.LEFT); | |
} else if (head.y < target.y && head.y >= this.prevHead.y) { | |
commands.unshift(COMMANDS.DOWN); | |
} else if (head.y > target.y && head.y <= this.prevHead.y) { | |
commands.unshift(COMMANDS.UP); | |
} | |
if (this.needed(this.data[index + 1])) { | |
commands.unshift(COMMANDS.RIGHT); | |
} else if (this.needed(this.data[index - 1])) { | |
commands.unshift(COMMANDS.LEFT); | |
} else if (this.needed(this.data[index + this.size])) { | |
commands.unshift(COMMANDS.DOWN); | |
} else if (this.needed(this.data[index - this.size])) { | |
commands.unshift(COMMANDS.UP); | |
} | |
for (let i = 0; i < commands.length; i++) { | |
if (commands[i] === COMMANDS.UP && this.validate(this.data[index - this.size], index - this.size)) { | |
command = COMMANDS.UP; | |
break; | |
} else if (commands[i] === COMMANDS.RIGHT && this.validate(this.data[index + 1], index + 1)) { | |
command = COMMANDS.RIGHT; | |
break; | |
} else if (commands[i] === COMMANDS.DOWN && this.validate(this.data[index + this.size], index + this.size)) { | |
command = COMMANDS.DOWN; | |
break; | |
} else if (commands[i] === COMMANDS.LEFT && this.validate(this.data[index - 1], index - 1)) { | |
command = COMMANDS.LEFT; | |
break; | |
} | |
} | |
this.prevHead = head; | |
if (this.isBiggest() && this.command === command) { | |
command = COMMANDS.ACT; | |
} else { | |
this.command = command; | |
} | |
return command; | |
} | |
nearRate(position, direction) { | |
let coordinates = { x: position.x, y: position.y }; | |
switch (direction) { | |
case ('top') : coordinates = { x: position.x, y: position.y - 1 }; break; | |
case ('right') : coordinates = { x: position.x + 1, y: position.y }; break; | |
case ('bottom') : coordinates = { x: position.x, y: position.y + 1 }; break; | |
case ('left') : coordinates = { x: position.x - 1, y: position.y }; break; | |
} | |
return Number(this.allowed(getElementByXY(this.data, coordinates))); | |
} | |
allowed(point) { | |
let allowed = [ELEMENT.NONE].concat(ELS.HEAD, ELS.BODY, ELS.TAIL, ELS.ALLOW); | |
return allowed.indexOf(point) > -1; | |
} | |
needed(point) { | |
let elements = []; | |
if(this.isBiggest()) { | |
if (this.head.evil) { | |
return this.enemiesElements().indexOf(point) > -1; | |
} else if(this.data.indexOf(ELEMENT.FURY_PILL) > -1) { | |
elements = elements.concat([ELEMENT.FURY_PILL, ELEMENT.STONE], ELS.ENEMY_HEAD); | |
} else { | |
elements = elements.concat(ELS.ENEMY_HEAD); | |
} | |
} else { | |
elements = elements.concat(ELS.ALLOW); | |
} | |
return elements.indexOf(point) > -1; | |
} | |
enemiesElements() { | |
return [].concat(ELS.ENEMY_HEAD, ELS.ENEMY_BODY, ELS.ENEMY_TAIL); | |
} | |
playersElements() { | |
return [].concat(ELS.HEAD, ELS.BODY, ELS.TAIL); | |
} | |
isBiggest(count = 2) { | |
return this.enemiesLength + count < this.playersLength; | |
} | |
} | |
const ELS = { | |
'HEAD': [ | |
ELEMENT.HEAD_DOWN, | |
ELEMENT.HEAD_LEFT, | |
ELEMENT.HEAD_RIGHT, | |
ELEMENT.HEAD_UP, | |
ELEMENT.HEAD_DEAD, | |
ELEMENT.HEAD_EVIL, | |
ELEMENT.HEAD_FLY, | |
ELEMENT.HEAD_SLEEP, | |
], | |
'TAIL': [ | |
ELEMENT.TAIL_END_DOWN, | |
ELEMENT.TAIL_END_LEFT, | |
ELEMENT.TAIL_END_UP, | |
ELEMENT.TAIL_END_RIGHT, | |
ELEMENT.TAIL_INACTIVE, | |
], | |
'BODY': [ | |
ELEMENT.BODY_HORIZONTAL, | |
ELEMENT.BODY_VERTICAL, | |
ELEMENT.BODY_LEFT_DOWN, | |
ELEMENT.BODY_LEFT_UP, | |
ELEMENT.BODY_RIGHT_DOWN, | |
ELEMENT.BODY_RIGHT_UP, | |
], | |
'ENEMY_HEAD': [ | |
ELEMENT.ENEMY_HEAD_DOWN, | |
ELEMENT.ENEMY_HEAD_LEFT, | |
ELEMENT.ENEMY_HEAD_RIGHT, | |
ELEMENT.ENEMY_HEAD_UP, | |
ELEMENT.ENEMY_HEAD_DEAD, | |
ELEMENT.ENEMY_HEAD_EVIL, | |
ELEMENT.ENEMY_HEAD_FLY, | |
ELEMENT.ENEMY_HEAD_SLEEP, | |
], | |
'ENEMY_TAIL': [ | |
ELEMENT.ENEMY_TAIL_END_DOWN, | |
ELEMENT.ENEMY_TAIL_END_LEFT, | |
ELEMENT.ENEMY_TAIL_END_UP, | |
ELEMENT.ENEMY_TAIL_END_RIGHT, | |
ELEMENT.ENEMY_TAIL_INACTIVE, | |
], | |
'ENEMY_BODY': [ | |
ELEMENT.ENEMY_BODY_HORIZONTAL, | |
ELEMENT.ENEMY_BODY_VERTICAL, | |
ELEMENT.ENEMY_BODY_LEFT_DOWN, | |
ELEMENT.ENEMY_BODY_LEFT_UP, | |
ELEMENT.ENEMY_BODY_RIGHT_DOWN, | |
ELEMENT.ENEMY_BODY_RIGHT_UP, | |
], | |
'ALLOW': [ | |
ELEMENT.APPLE, | |
ELEMENT.FLYING_PILL, | |
ELEMENT.FURY_PILL, | |
ELEMENT.GOLD, | |
], | |
'ENEMY__': [], | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks!