|
|
|
const SIZE = 100
|
|
|
|
const MAP = new Int8Array(SIZE * SIZE) // State of the Map
|
|
|
|
const isFree = ({ x, y }) => MAP[y * SIZE + x] === 0 // 0 = block free
|
|
|
|
const isOccupied = ({ x, y }) => MAP[y * SIZE + x] === 1 // 1 = block occupied
|
|
|
|
const inBounds = n => n < SIZE && n >= 0
|
|
|
|
const isInBounds = ({ x, y }) => inBounds(x) && inBounds(y)
|
|
|
|
const pickRandom = arr => arr[Math.floor(Math.random() * arr.length)]
|
|
|
|
|
|
|
|
// ok check if we can move on this block
|
|
|
|
const ok = (x = -1, y = -1) => {
|
|
|
|
const coords = typeof x !== 'number' ? x : { x, y }
|
|
|
|
return isFree(coords) && isInBounds(coords)
|
|
|
|
}
|
|
|
|
|
|
|
|
const isAlley = (card, x, y) => {
|
|
|
|
switch (card) {
|
|
|
|
case 0:
|
|
|
|
if (ok(x, y - 1) && !ok(x + 1, y - 1) && !ok(x - 1, y - 1)) {
|
|
|
|
while (ok(x, y - 1) && !hasLateralWalls(0, x, y)) {
|
|
|
|
y--
|
|
|
|
if (hasLateralWalls(0, x, y)) return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
case 1:
|
|
|
|
if (ok(x + 1, y) && !ok(x + 1, y + 1) && !ok(x + 1, y - 1)) {
|
|
|
|
while (ok(x + 1, y) && !hasLateralWalls(1, x, y)) {
|
|
|
|
x++
|
|
|
|
if (hasLateralWalls(1, x, y)) return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
case 2:
|
|
|
|
if (ok(x, y + 1) && !ok(x + 1, y + 1) && !ok(x - 1, y + 1)) {
|
|
|
|
while (ok(x, y + 1) && !hasLateralWalls(2, x, y)) {
|
|
|
|
y++
|
|
|
|
if (hasLateralWalls(2, x, y)) return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
case 3:
|
|
|
|
if (ok(x - 1, y) && !ok(x - 1, y + 1) && !ok(x - 1, y - 1)) {
|
|
|
|
while (ok(x - 1, y) && !hasLateralWalls(3, x, y)) {
|
|
|
|
x--
|
|
|
|
if (hasLateralWalls(3, x, y)) return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const hasLateralWalls = (card, x, y) => {
|
|
|
|
switch (card) {
|
|
|
|
case 0: return !(ok(x + 1, y) || ok(x - 1, y) || ok(x, y - 1))
|
|
|
|
case 1: return !(ok(x, y - 1) || ok(x, y + 1) || ok(x + 1, y))
|
|
|
|
case 2: return !(ok(x + 1, y) || ok(x - 1, y) || ok(x, y + 1))
|
|
|
|
case 3: return !(ok(x, y - 1) || ok(x, y + 1) || ok(x - 1, y))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const goDirection = (ai, card) =>
|
|
|
|
ok(ai.coords[card]) &&
|
|
|
|
!isAlley(card, ai.x, ai.y) &&
|
|
|
|
ai.coords[card]
|
|
|
|
|
|
|
|
const findEnemy = state =>
|
|
|
|
state.ais.filter(p => state.ai.name !== p.name)[0]
|
|
|
|
|
|
|
|
const seekEnemy = state => {
|
|
|
|
if (state.ais.length === 1) return
|
|
|
|
const enemy = findEnemy(state)
|
|
|
|
const xPla = state.ai.x
|
|
|
|
const yPla = state.ai.y
|
|
|
|
const xOpo = enemy.x
|
|
|
|
const yOpo = enemy.y
|
|
|
|
const xDif = xPla - xOpo
|
|
|
|
const yDif = yPla - yOpo
|
|
|
|
|
|
|
|
return (
|
|
|
|
(Math.abs(xDif) > Math.abs(yDif) &&
|
|
|
|
goDirection(state.ai, xPla < xOpo ? 1 : 3)) ||
|
|
|
|
goDirection(state.ai, yPla < yOpo ? 2 : 0)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const walk = state =>
|
|
|
|
seekEnemy(state) ||
|
|
|
|
goDirection(state.ai, 0) ||
|
|
|
|
goDirection(state.ai, 1) ||
|
|
|
|
goDirection(state.ai, 2) ||
|
|
|
|
goDirection(state.ai, 3)
|
|
|
|
|
|
|
|
const addToMap = ({ x, y }) => (MAP[y * SIZE + x] = 1)
|
|
|
|
const update = state => {
|
|
|
|
state.ais.forEach(addToMap)
|
|
|
|
return walk(state)
|
|
|
|
}
|