-
Notifications
You must be signed in to change notification settings - Fork 0
/
snake.js
61 lines (52 loc) · 1.64 KB
/
snake.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
const base = require('./base')
Object.getOwnPropertyNames(base).map(p => global[p] = base[p])
// Constants
const NORTH = { x: 0, y:-1 }
const SOUTH = { x: 0, y: 1 }
const EAST = { x: 1, y: 0 }
const WEST = { x:-1, y: 0 }
// Point operations
const pointEq = p1 => p2 => p1.x == p2.x && p1.y == p2.y
// Booleans
const willEat = state => pointEq(nextHead(state))(state.apple)
const willCrash = state => state.snake.find(pointEq(nextHead(state)))
const validMove = move => state =>
state.moves[0].x + move.x != 0 || state.moves[0].y + move.y != 0
// Next values based on state
const nextMoves = state => state.moves.length > 1 ? dropFirst(state.moves) : state.moves
const nextApple = state => willEat(state) ? rndPos(state) : state.apple
const nextHead = state => state.snake.length == 0
? { x: 2, y: 2 }
: {
x: mod(state.cols)(state.snake[0].x + state.moves[0].x),
y: mod(state.rows)(state.snake[0].y + state.moves[0].y)
}
const nextSnake = state => willCrash(state)
? []
: (willEat(state)
? [nextHead(state)].concat(state.snake)
: [nextHead(state)].concat(dropLast(state.snake)))
// Randomness
const rndPos = table => ({
x: rnd(0)(table.cols - 1),
y: rnd(0)(table.rows - 1)
})
// Initial state
const initialState = () => ({
cols: 20,
rows: 14,
moves: [EAST],
snake: [],
apple: { x: 16, y: 2 },
})
const next = spec({
rows: prop('rows'),
cols: prop('cols'),
moves: nextMoves,
snake: nextSnake,
apple: nextApple
})
const enqueue = (state, move) => validMove(move)(state)
? merge(state)({ moves: state.moves.concat([move]) })
: state
module.exports = { EAST, NORTH, SOUTH, WEST, initialState, enqueue, next, }