Skip to content

Commit ecaf3d4

Browse files
committed
Merge branch 'update-dockerfile-yarn'
2 parents 3e99200 + 72935be commit ecaf3d4

File tree

6 files changed

+461
-2
lines changed

6 files changed

+461
-2
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM node:8-jessie
1+
FROM node:10-jessie
22

33
WORKDIR /usr/src
44

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from 'react'
2+
3+
const Score = ({ score, initialLoad, playing }) => {
4+
if (initialLoad) {
5+
return null
6+
}
7+
return (
8+
<h3 style={{ textAlign: 'right' }}>
9+
{playing ? 'Current' : 'Final'} score: {score}
10+
</h3>
11+
)
12+
}
13+
14+
export default Score
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
/*
2+
* Copyright (c) 2002-2018 "Neo4j, Inc"
3+
* Network Engine for Objects in Lund AB [http://neotechnology.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Neo4j is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
import React from 'react'
21+
import styled from 'styled-components'
22+
import {
23+
UP,
24+
DOWN,
25+
LEFT,
26+
RIGHT,
27+
getInitialState,
28+
transitionDirection,
29+
rect,
30+
newFood,
31+
doesCollide,
32+
foodColor,
33+
snakeColor,
34+
maxSpeed
35+
} from './helpers'
36+
37+
const SnakeCanvas = styled.canvas`
38+
border: 1px solid #787878;
39+
&:focus {
40+
outline: none;
41+
}
42+
`
43+
44+
class SnakeFrame extends React.Component {
45+
canvas = React.createRef()
46+
ctx = null
47+
gameState = getInitialState(
48+
this.props.play,
49+
this.props.width,
50+
this.props.height,
51+
this.props.gridSize
52+
)
53+
blockInput = false
54+
componentDidMount () {
55+
this.ctx = this.canvas.current.getContext('2d')
56+
this.canvas.current.addEventListener('keydown', ev => {
57+
const { key } = ev
58+
if (this.blockInput) {
59+
return
60+
}
61+
const allowedKeys = {
62+
ArrowDown: DOWN,
63+
ArrowUp: UP,
64+
ArrowLeft: LEFT,
65+
ArrowRight: RIGHT
66+
}
67+
if (!Object.keys(allowedKeys).includes(key)) {
68+
return
69+
}
70+
this.blockInput = true
71+
this.gameState.snake.direction = transitionDirection(
72+
this.gameState.snake.direction,
73+
allowedKeys[key]
74+
)
75+
})
76+
this.updateCanvas()
77+
}
78+
componentDidUpdate () {
79+
if (this.gameState.play !== this.props.play) {
80+
this.gameState.play = this.props.play
81+
if (this.props.play) {
82+
this.canvas.current.focus()
83+
this.reset()
84+
this.updateCanvas()
85+
}
86+
}
87+
}
88+
reset = () => {
89+
this.gameState = getInitialState(
90+
this.props.play,
91+
this.props.width,
92+
this.props.height,
93+
this.props.gridSize
94+
)
95+
}
96+
drawFood = () => {
97+
this.ctx.fillStyle = foodColor
98+
rect({
99+
ctx: this.ctx,
100+
x: this.gameState.food.x,
101+
y: this.gameState.food.y,
102+
width: this.gameState.snake.width,
103+
height: this.gameState.snake.height
104+
})
105+
}
106+
drawSnake = () => {
107+
this.ctx.fillStyle = snakeColor
108+
const { snake } = this.gameState
109+
snake.body.forEach(part => {
110+
rect({
111+
ctx: this.ctx,
112+
x: part.x,
113+
y: part.y,
114+
width: snake.width,
115+
height: snake.height
116+
})
117+
})
118+
}
119+
drawWorld = () => {
120+
const { color, width, height } = this.gameState.world
121+
this.ctx.fillStyle = color
122+
rect({
123+
ctx: this.ctx,
124+
x: 0,
125+
y: 0,
126+
width: width,
127+
height: height
128+
})
129+
}
130+
calcNextHeadPos = () => {
131+
let { x, y } = this.gameState.snake.body[0]
132+
if (this.gameState.snake.direction === UP) {
133+
y -= this.gameState.step
134+
return { x, y }
135+
}
136+
if (this.gameState.snake.direction === DOWN) {
137+
y += this.gameState.step
138+
return { x, y }
139+
}
140+
if (this.gameState.snake.direction === LEFT) {
141+
x -= this.gameState.step
142+
return { x, y }
143+
}
144+
if (this.gameState.snake.direction === RIGHT) {
145+
x += this.gameState.step
146+
return { x, y }
147+
}
148+
}
149+
growSnake = () => {
150+
this.gameState.snake.body.unshift(this.gameState.snake.body[0])
151+
}
152+
eatMaybe = () => {
153+
let { x, y } = this.gameState.snake.body[0]
154+
const { x: fx, y: fy } = this.gameState.food
155+
if (x === fx && y === fy) {
156+
newFood(this.gameState)
157+
this.growSnake()
158+
this.props.onEat && this.props.onEat(this.gameState.snake.body.length)
159+
this.setNewSpeed()
160+
}
161+
}
162+
setNewSpeed = () => {
163+
const speedLen =
164+
this.gameState.snake.body.length % 5
165+
? this.gameState.speed
166+
: this.gameState.speed - 1
167+
this.gameState.speed = Math.max(speedLen, maxSpeed)
168+
}
169+
updateCanvas = () => {
170+
if (this.gameState.frame % this.gameState.speed) {
171+
this.tick()
172+
return
173+
}
174+
this.blockInput = false
175+
if (!this.gameState.play) {
176+
return
177+
}
178+
if (!this.canvas || !this.canvas.current) {
179+
return
180+
}
181+
if (!this.gameState.play) {
182+
return
183+
}
184+
this.ctx.clearRect(
185+
0,
186+
0,
187+
this.gameState.world.width,
188+
this.gameState.world.height
189+
)
190+
this.drawWorld()
191+
const { x, y } = this.calcNextHeadPos()
192+
if (doesCollide({ x, y }, this.gameState)) {
193+
this.drawFood()
194+
this.drawSnake()
195+
this.props.onDie && this.props.onDie()
196+
return
197+
}
198+
this.gameState.snake.body.unshift({ x, y })
199+
this.gameState.snake.body.pop()
200+
this.drawFood()
201+
this.drawSnake()
202+
this.eatMaybe()
203+
this.tick()
204+
}
205+
tick = () => {
206+
this.gameState.frame++
207+
window.requestAnimationFrame(() => {
208+
this.updateCanvas()
209+
})
210+
}
211+
render () {
212+
return (
213+
<SnakeCanvas
214+
tabIndex='1'
215+
innerRef={this.canvas}
216+
width={this.gameState.world.width}
217+
height={this.gameState.world.height}
218+
/>
219+
)
220+
}
221+
}
222+
export default SnakeFrame
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
export const UP = 'up'
2+
export const DOWN = 'down'
3+
export const LEFT = 'left'
4+
export const RIGHT = 'right'
5+
6+
export const maxSpeed = 4 // Smaller is faster
7+
8+
export const foodColor = '#77AF53'
9+
export const snakeColor = '#FFFFFF'
10+
export const worldColor = '#3C8ABC'
11+
12+
export const transitionDirection = (current, next) => {
13+
if (current === UP && next !== DOWN) {
14+
return next
15+
}
16+
if (current === DOWN && next !== UP) {
17+
return next
18+
}
19+
if (current === LEFT && next !== RIGHT) {
20+
return next
21+
}
22+
if (current === RIGHT && next !== LEFT) {
23+
return next
24+
}
25+
return current
26+
}
27+
28+
export const getInitialState = (
29+
play = false,
30+
width = 600,
31+
height = 400,
32+
gridSize = 20
33+
) => {
34+
let state = {
35+
play,
36+
world: {
37+
color: worldColor,
38+
width,
39+
height
40+
},
41+
snake: {
42+
body: [
43+
{
44+
x: 150 - (150 % gridSize),
45+
y: 150 - (150 % gridSize)
46+
}
47+
],
48+
width: gridSize,
49+
height: gridSize,
50+
direction: RIGHT
51+
},
52+
frame: 0,
53+
speed: 10,
54+
step: gridSize
55+
}
56+
newFood(state)
57+
return state
58+
}
59+
60+
export const newFood = state => {
61+
const size = state.snake.width
62+
let foodX = Math.max(Math.random() * state.world.width - size, 0)
63+
let foodY = Math.max(Math.random() * state.world.height - size, 0)
64+
state.food = {
65+
x: foodX - (foodX % size),
66+
y: foodY - (foodY % size)
67+
}
68+
}
69+
70+
export const doesCollide = ({ x, y }, state) => {
71+
const { body } = state.snake
72+
if (x < 0 || x > state.world.width - state.snake.width) {
73+
return true
74+
}
75+
if (y < 0 || y > state.world.height - state.snake.height) {
76+
return true
77+
}
78+
for (let i = 0; i < body.length; i++) {
79+
const { x: bx, y: by } = body[i]
80+
if (x === bx && y === by) {
81+
return true
82+
}
83+
}
84+
return false
85+
}
86+
87+
export const rect = props => {
88+
const { ctx, x, y, width, height } = props
89+
ctx.fillRect(x, y, width, height)
90+
}

0 commit comments

Comments
 (0)