Skip to content

Instantly share code, notes, and snippets.

@maximvl maximvl/python.red
Last active Aug 22, 2017

Embed
What would you like to do?
python game
Red [
author: {Maxim Velesyuk}
description: {
A Snake Game / basic version
specification by Edward de Jong, version 1
The game runs at 6 frames per second, and the snake moves one cell per frame. If the snake moves into the apple the length is increased by one, a crunch sound is emitted, and the apple is moved to a new cell. If the snake crosses over itself, then a beep is emitted and the part of the snake from that cell onward is erased. The snake wraps around the board in all four directions.
The playing board, drawn solid black, is subdivided into square cells of 42 points at the screen resolution. Since the window size will not be an even number of cells, the cells are stretched slightly so that all screen space is used by the grid. At the start, the snake is set to length 1 and positioned at cell (4,4). The apple, which is the goal of the snake to eat, is one cell drawn as a circle in HTML color crimson, and is placed at a random location on the board.
At the start of the game the snake is paused. As soon as an arrow key is pressed, the snake begins to move in that direction, and leaves a trail behind. Initially the trail is limited to 5 cells total. If the snake moves into the Apple, the snake's length grows by 1. Once the apple is eaten, it is immediately respawned into a random new cell. The apple may end up on occasion placed inside the body of the snake, however, the snake only is considered to have eaten the apple if the head moves onto the apple. The snake cells are drawn as 40 point squares with 2pts on the right and bottom to create a separation. The snake cells are drawn in alternating colors lime green and lawn green. The head of the snake is drawn as a rounded rectangle with a corner radius of 8 pt and a border of 2 pt dark green. The remaining cells of the snake are drawn as a rounded rectangle with 2 pt corner radius. If the snake cells had to be reduced from 42 pt due to window size limitations, then the radii and border thickness are reduced accordingly.
The only input to the game is the keyboard. The arrow keys change the direction of the snake, however, to prevent frustration the player is not allowed to move the snake head back into itself. So if the snake is traveling east, any attempted movement west is ignored. A command to move in the direction already in motion is ignored. To permit fast maneuvers the direction inputs are queued, so that the player can do WEST - SOUTH - EAST to perform a 180 degree turn in 3 consecutive frames. Pressing the space bar pauses or resumes the game.
As the snake grows and shrinks, the current size and high score is reported at the top of the screen as a topmost layer at 30% opacity, centered in 28 pt black text, for example: "8 high:22".
The default starting window size is 700 x 700 interior pixels. If the user resizes the window, the game is reset back to the starting state.
Note: since the window size will not usually be an even multiple of 42 points, the cells are slightly stretched to not have any dead space leftover. If the given window size is too small to accommodate at least 10 cells in both directions, the cellsize is reduced. So the program must first figure out how many the proper cell size such that at least 10 cells can fit in the X and Y directions, but no larger than 42 pts in size, then divide the width and height by the number of cells in each direction, and then pad the cells by the leftover amount so that the cell grid fills the space perfectly.
External resources:
 crunch.mp3 sound
 beep.mp3 sound
 you are given a window size in pixels, and the resolution of the device.
o device resolution might vary from 86 dpi (desktop), to 500+ dpi (mobile)
}
]
nope: no
yup: yes
window-size: 400x400
grid-size: 40x40
tile-size: window-size / grid-size
frame-rate: 6
game: object [
init: does [
snake: copy [4x4 4x3 4x2 4x1 4x0]
snake-tail: last snake
apple-pos: random grid-size - 1x1
direction: random/only [north south east west]
speed: 1
score: 0
window/rate: frame-rate
finished: paused: nope
]
snake: none
snake-tail: none
apple-pos: none
direction: none
speed: none
score: none
paused: yup
finished: yup
step: func [] [
insert snake (switch direction [
north [ 0x-1 ]
east [ 1x0 ]
south [ 0x1 ]
west [ -1x0 ]
]) + snake/1
case [
snake/1/x >= grid-size/x [ snake/1/x: 0 ]
snake/1/x < 0 [ snake/1/x: grid-size/x - 1 ]
snake/1/y >= grid-size/y [ snake/1/y: 0 ]
snake/1/y < 0 [ snake/1/y: grid-size/y - 1 ]
]
either apple-pos = snake/1 [
apple-pos: random grid-size - 1x1
if zero? ((length? snake) % 3) [
window/rate: window/rate + 3
speed: speed + 1
]
score: score + speed
] [
snake-tail: take/last snake
]
if find next snake snake/1 [ finished: paused: yup ]
]
opposites: #(south north north south east west west east)
set-direction: func [new] [
if direction <> (opposites/(new)) [ direction: new ]
]
color-switch: yup
snake-color: does [
color-switch: not color-switch
either color-switch [ 50.205.50 ] [ 124.252.0 ]
]
background: black
apple-color: crimson
]
window: make face! [
type: 'window
title: "Python"
size: window-size
rate: frame-rate
pane: reduce [
make face! [
type: 'base
size: window-size
image: make image! window-size
]
]
actors: object [
on-time: func [face /local image center tail-top-left apple-pos ws] [
if not game/paused [
image: face/pane/1/image
game/step
apple-pos: (game/apple-pos * tile-size) + (tile-size / 2)
ws: window-size
ws/y: 0
system/words/draw image compose [
fill-pen (game/background)
pen off
box (ws - 100x0) (ws + 50)
pen white
text (ws - 100x0) "score: " text (ws - 50x0) (to-string game/score)
text (ws - 100x-20) "speed: " text (ws - 50x-20) (to-string game/speed)
pen off
fill-pen (game/apple-color)
circle (apple-pos) (tile-size/x / 2)
]
snake: game/snake
forall snake [
center: (snake/1 * tile-size) + (tile-size / 2)
tail-top-left: game/snake-tail * tile-size
system/words/draw image compose [
pen off fill-pen (game/background) box (tail-top-left) (tail-top-left + tile-size)
fill-pen (game/snake-color) circle (center) (tile-size/x / 2)
]
]
show face
]
]
on-key: func [face event /local snake] [
if game/finished [
window/pane/1/image/rgb: game/background
game/init
exit
]
switch event/key [
up [ game/set-direction 'north ]
right [ game/set-direction 'east ]
down [ game/set-direction 'south ]
left [ game/set-direction 'west ]
#" " [ game/paused: not game/paused ]
]
]
on-resize: func [face event] [
window/pane/1/size: window/size
]
]
]
draw-grid: func [/local tmp pos] [
tmp: 0x0
while [tmp/x < grid-size/x] [
while [tmp/y < grid-size/y] [
pos: tmp * tile-size
draw window/pane/1/image compose [fill-pen (game/background) box (pos) (pos + tile-size) ]
tmp/y: tmp/y + 1
]
tmp/x: tmp/x + 1
tmp/y: 0
]
]
draw-grid
system/view/auto-sync?: no
view/flags/no-wait window [resize]
do-events
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.