Initiall development.
This commit is contained in:
+20
@@ -0,0 +1,20 @@
|
|||||||
|
# general things to ignore
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
*.egg-info/
|
||||||
|
*.egg
|
||||||
|
*.py[cod]
|
||||||
|
__pycache__/
|
||||||
|
*.so
|
||||||
|
*~
|
||||||
|
|
||||||
|
# due to using tox and pytest
|
||||||
|
.tox
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# editor ignores
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# package ignores
|
||||||
|
sensehatsnake/config.py
|
||||||
|
data/database.json
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
language: python
|
||||||
|
|
||||||
|
env:
|
||||||
|
- TOXENV=py27
|
||||||
|
- TOXENV=py33
|
||||||
|
- TOXENV=py34
|
||||||
|
|
||||||
|
install: pip install tox
|
||||||
|
|
||||||
|
script: tox
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email: false
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Bradley Cornford <me@bradleycornford.co.uk>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Include the license file
|
||||||
|
include LICENSE.txt
|
||||||
|
|
||||||
|
# Include the data files
|
||||||
|
recursive-include data *
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# Raspberry Pi Python sense hat snake
|
||||||
|
|
||||||
|
A project to create a Snake game on a Raspberry Pi using a Sense Hat.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
This package requires the following system packages to be installed:
|
||||||
|
|
||||||
|
- python-pip
|
||||||
|
- python-dev
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Begin by installing this packages requirements:
|
||||||
|
|
||||||
|
pip install -e .
|
||||||
|
|
||||||
|
Finally copy the example configuration file `example.config.py`, and save it as `config.py`
|
||||||
|
|
||||||
|
cp sensehatsnake/example.config.py sensehatsnake/config.py
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
You can now configure Sense-Hat-Snake in a few simple steps. Open `sensehatsnake/config.py` and update the options as needed.
|
||||||
|
|
||||||
|
- `columns` - The number of columns the board has.
|
||||||
|
- `rows` - The number of rows the board has.
|
||||||
|
- `fps` - The games frames per second.
|
||||||
|
- `countdown` - The game countdown in seconds.
|
||||||
|
- `interval` - The game tick interval in milliseconds.
|
||||||
|
- `score_increment` - The number to increment score by in game.
|
||||||
|
- `level_increment` - The score when to increment the level by in game.
|
||||||
|
- `interval_increment` - The number to reduce the game tick interval by in milliseconds.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
It's really as simple as running the main file
|
||||||
|
|
||||||
|
sudo python sensehatsnake/main.py
|
||||||
|
|
||||||
|
### License
|
||||||
|
|
||||||
|
Sense-Hat-Snake is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"_default": {"1": {"score": 0}, "2": {"score": 0}, "3": {"score": 1}, "4": {"score": 0}, "5": {"score": 0}, "6": {"score": 0}, "7": {"score": 0}, "8": {"score": 0}}}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
game = {
|
||||||
|
'columns': 8,
|
||||||
|
'rows': 8,
|
||||||
|
'fps': 30,
|
||||||
|
'countdown': 5,
|
||||||
|
'interval': 800,
|
||||||
|
'score_increment': 1,
|
||||||
|
'level_increment': 8,
|
||||||
|
'interval_increment': 50
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
|
||||||
|
class Apple:
|
||||||
|
COORDINATES = None
|
||||||
|
|
||||||
|
X = None
|
||||||
|
Y = None
|
||||||
|
|
||||||
|
def __init__(self, coordinates, x=0, y=0):
|
||||||
|
print("[Apple][info] Initialising Apple")
|
||||||
|
|
||||||
|
self.COORDINATES = coordinates
|
||||||
|
self.X = x
|
||||||
|
self.Y = y
|
||||||
|
|
||||||
|
def set_coordinates(self, coordinates):
|
||||||
|
print("[Apple][info] Setting Apple coordinates")
|
||||||
|
|
||||||
|
self.COORDINATES = coordinates
|
||||||
|
|
||||||
|
def set_x(self, x):
|
||||||
|
print("[Apple][info] Setting Apple X position")
|
||||||
|
|
||||||
|
self.X = x
|
||||||
|
|
||||||
|
def set_y(self, y):
|
||||||
|
print("[Apple][info] Setting Apple Y position")
|
||||||
|
|
||||||
|
self.Y = y
|
||||||
|
|
||||||
|
def set_position(self, coordinates):
|
||||||
|
print("[Apple][info] Setting Apple X, Y position")
|
||||||
|
|
||||||
|
x, y = coordinates
|
||||||
|
|
||||||
|
self.X = x
|
||||||
|
self.Y = y
|
||||||
|
|
||||||
|
def coordinates(self):
|
||||||
|
print("[Apple][info] Getting Apple coordinates")
|
||||||
|
|
||||||
|
return self.COORDINATES
|
||||||
|
|
||||||
|
def x(self):
|
||||||
|
print("[Apple][info] Getting Apple X position")
|
||||||
|
|
||||||
|
return self.X
|
||||||
|
|
||||||
|
def y(self):
|
||||||
|
print("[Apple][info] Getting Apple Y position")
|
||||||
|
|
||||||
|
return self.Y
|
||||||
|
|
||||||
|
def position(self):
|
||||||
|
print("[Apple][info] Getting Apple X, Y position")
|
||||||
|
|
||||||
|
return (self.X, self.Y)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
print("[Apple][info] Clearing Apple")
|
||||||
|
|
||||||
|
self.COORDINATES = None
|
||||||
|
self.X = None
|
||||||
|
self.Y = None
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
print("[Apple][info] Apple clean up")
|
||||||
|
|
||||||
|
self.clear()
|
||||||
|
|
||||||
|
def __exit__(self):
|
||||||
|
print("[Apple][info] Apple exit")
|
||||||
|
|
||||||
|
self.cleanup()
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
|
||||||
|
class Board:
|
||||||
|
COLUMNS = None
|
||||||
|
|
||||||
|
ROWS = None
|
||||||
|
|
||||||
|
COORDINATES = None
|
||||||
|
|
||||||
|
def __init__(self, columns, rows):
|
||||||
|
print("[Board][info] Initialising Board")
|
||||||
|
|
||||||
|
self.COLUMNS = columns
|
||||||
|
self.ROWS = rows
|
||||||
|
self.__generate()
|
||||||
|
|
||||||
|
def __generate(self):
|
||||||
|
self.COORDINATES = [
|
||||||
|
[0 for x in xrange(self.COLUMNS)]
|
||||||
|
for y in xrange(self.ROWS)
|
||||||
|
]
|
||||||
|
|
||||||
|
def columns(self):
|
||||||
|
print("[Board][info] Getting Board columns")
|
||||||
|
|
||||||
|
return self.COLUMNS
|
||||||
|
|
||||||
|
def rows(self):
|
||||||
|
print("[Board][info] Getting Board rows")
|
||||||
|
|
||||||
|
return self.ROWS
|
||||||
|
|
||||||
|
def coordinates(self):
|
||||||
|
print("[Board][info] Getting Board coordinates")
|
||||||
|
|
||||||
|
return self.COORDINATES
|
||||||
|
|
||||||
|
def check_collision(self, snake, offset):
|
||||||
|
print("[Board][info] Checking for Snake collision")
|
||||||
|
|
||||||
|
offset_x, offset_y = offset
|
||||||
|
|
||||||
|
if 0 > offset_x or offset_x > self.ROWS - 1 or 0 > offset_y or offset_y > self.COLUMNS - 1:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
for segment in snake.segments():
|
||||||
|
if segment[0] == offset_x and segment[1] == offset_y:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
print("[Board][info] Clearing board")
|
||||||
|
|
||||||
|
self.COORDINATES = None
|
||||||
|
self.COLUMNS = None
|
||||||
|
self.ROWS = None
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
print("[Board][info] Board clean up")
|
||||||
|
|
||||||
|
self.clear()
|
||||||
|
|
||||||
|
def __exit__(self):
|
||||||
|
print("[Board][info] Board exit")
|
||||||
|
|
||||||
|
self.cleanup()
|
||||||
@@ -0,0 +1,500 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
from board import Board
|
||||||
|
from apple import Apple
|
||||||
|
from mock import MagicMock, patch
|
||||||
|
from random import randint
|
||||||
|
from snake import Snake
|
||||||
|
from tinydb import TinyDB, Query
|
||||||
|
import math
|
||||||
|
import pygame
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from sense_hat import SenseHat
|
||||||
|
except ImportError:
|
||||||
|
print("[Game][error] An error occurred importing 'sense_hat.SenseHat'")
|
||||||
|
mock = MagicMock()
|
||||||
|
mock.clear.return_value = True
|
||||||
|
mock.set_pixel.return_value = True
|
||||||
|
mock.show_message.return_value = True
|
||||||
|
|
||||||
|
with patch.dict('sys.modules', {'sense_hat': mock, 'sense_hat.SenseHat': mock.RTIMU}):
|
||||||
|
from sense_hat import SenseHat
|
||||||
|
|
||||||
|
|
||||||
|
class Game:
|
||||||
|
BLOCK_SIZE = 36
|
||||||
|
|
||||||
|
COLUMNS = 8
|
||||||
|
ROWS = 8
|
||||||
|
|
||||||
|
FPS = None
|
||||||
|
|
||||||
|
COLORS = [
|
||||||
|
# 0 - Black
|
||||||
|
(0, 0, 0),
|
||||||
|
# 1 - Green
|
||||||
|
(0, 255, 0),
|
||||||
|
# 2 - Red
|
||||||
|
(255, 0, 0),
|
||||||
|
# 3 - Purple
|
||||||
|
(128, 0, 128),
|
||||||
|
# 4 - Blue
|
||||||
|
(0, 0, 255),
|
||||||
|
# 5 - Orange
|
||||||
|
(255, 165, 0),
|
||||||
|
# 6 - Cyan
|
||||||
|
(0, 255, 255),
|
||||||
|
# 7 - Yellow
|
||||||
|
(255, 255, 0),
|
||||||
|
# 8 - Dark Grey
|
||||||
|
(35, 35, 35),
|
||||||
|
# 9 - White
|
||||||
|
(255, 255, 255)
|
||||||
|
]
|
||||||
|
|
||||||
|
SHAPES = [
|
||||||
|
# Snake
|
||||||
|
[
|
||||||
|
[1],
|
||||||
|
],
|
||||||
|
|
||||||
|
# Apple
|
||||||
|
[
|
||||||
|
[2]
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
WIDTH = None
|
||||||
|
HEIGHT = None
|
||||||
|
|
||||||
|
COUNTDOWN = None
|
||||||
|
|
||||||
|
SCORE_INCREMENT = None
|
||||||
|
|
||||||
|
SCORE = 0
|
||||||
|
APPLES = 0
|
||||||
|
|
||||||
|
INTERVAL = None
|
||||||
|
INTERVAL_INCREMENT = None
|
||||||
|
|
||||||
|
LEVEL = 1
|
||||||
|
LEVEL_INCREMENT = None
|
||||||
|
|
||||||
|
PAUSED = False
|
||||||
|
|
||||||
|
GAMEOVER = False
|
||||||
|
|
||||||
|
BACKGROUND_GRID = None
|
||||||
|
|
||||||
|
SNAKE_MOVED = True
|
||||||
|
|
||||||
|
pygame = None
|
||||||
|
pygame_font = None
|
||||||
|
pygame_screen = None
|
||||||
|
sensehat = None
|
||||||
|
db = None
|
||||||
|
|
||||||
|
board = None
|
||||||
|
snake = None
|
||||||
|
apple = None
|
||||||
|
|
||||||
|
def __init__(self, columns, rows, fps, countdown, interval, score_increment, level_increment, interval_increment, pygame_instance=None):
|
||||||
|
self.COLUMNS = columns
|
||||||
|
self.ROWS = rows
|
||||||
|
self.FPS = fps
|
||||||
|
self.COUNTDOWN = countdown
|
||||||
|
self.INTERVAL = interval
|
||||||
|
self.SCORE_INCREMENT = score_increment
|
||||||
|
self.LEVEL_INCREMENT = level_increment
|
||||||
|
self.INTERVAL_INCREMENT = interval_increment
|
||||||
|
|
||||||
|
if pygame_instance is None:
|
||||||
|
self.pygame = pygame
|
||||||
|
else:
|
||||||
|
self.pygame = pygame_instance
|
||||||
|
|
||||||
|
self.sensehat = SenseHat()
|
||||||
|
self.db = TinyDB('data/database.json')
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.WIDTH = self.BLOCK_SIZE * self.COLUMNS + 150
|
||||||
|
self.HEIGHT = self.BLOCK_SIZE * self.ROWS
|
||||||
|
|
||||||
|
self.BACKGROUND_GRID = [
|
||||||
|
[8 if x % 2 == y % 2 else 0 for x in xrange(self.COLUMNS)]
|
||||||
|
for y in xrange(self.ROWS)
|
||||||
|
]
|
||||||
|
|
||||||
|
self.pygame.init()
|
||||||
|
self.pygame.key.set_repeat(0, 0)
|
||||||
|
self.pygame_font = self.pygame.font.Font(self.pygame.font.get_default_font(), 12)
|
||||||
|
self.pygame_screen = self.pygame.display.set_mode((self.WIDTH, self.HEIGHT), 0, 24)
|
||||||
|
self.pygame.event.set_blocked(self.pygame.MOUSEMOTION)
|
||||||
|
|
||||||
|
self.board = Board(self.COLUMNS, self.ROWS)
|
||||||
|
self.__generate_snake()
|
||||||
|
self.__generate_apple()
|
||||||
|
except AttributeError:
|
||||||
|
print("[Game][error] An error occurred initialising game")
|
||||||
|
|
||||||
|
def start(self, run_once=False):
|
||||||
|
print("[Game][info] Starting game")
|
||||||
|
|
||||||
|
try:
|
||||||
|
pygame_wait = True
|
||||||
|
|
||||||
|
while pygame_wait:
|
||||||
|
for event in self.pygame.event.get():
|
||||||
|
if event.type == self.pygame.KEYDOWN:
|
||||||
|
if event.key == self.pygame.K_RETURN:
|
||||||
|
pygame_wait = False
|
||||||
|
elif event.key == self.pygame.K_ESCAPE:
|
||||||
|
self.quit()
|
||||||
|
|
||||||
|
self.pygame_screen.fill(self.COLORS[0])
|
||||||
|
self.__display_message("Press to start")
|
||||||
|
self.pygame.display.update()
|
||||||
|
|
||||||
|
self.sensehat.clear()
|
||||||
|
except AttributeError:
|
||||||
|
print("[Game][error] An error occurred starting game")
|
||||||
|
|
||||||
|
self.__countdown()
|
||||||
|
self.__loop()
|
||||||
|
self.finish()
|
||||||
|
|
||||||
|
if run_once is not True:
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
def __countdown(self):
|
||||||
|
print("[Game][info] Starting game countdown")
|
||||||
|
|
||||||
|
try:
|
||||||
|
seconds = 0
|
||||||
|
|
||||||
|
while True:
|
||||||
|
self.pygame_screen.fill(self.COLORS[0])
|
||||||
|
remaining = (self.COUNTDOWN - seconds)
|
||||||
|
|
||||||
|
if seconds > self.COUNTDOWN:
|
||||||
|
break
|
||||||
|
|
||||||
|
if seconds == self.COUNTDOWN:
|
||||||
|
self.__display_message("Go!")
|
||||||
|
else:
|
||||||
|
self.__display_message("%d!" % remaining)
|
||||||
|
|
||||||
|
seconds += 1
|
||||||
|
self.sensehat.clear()
|
||||||
|
self.pygame.display.update()
|
||||||
|
self.pygame.time.wait(1000)
|
||||||
|
|
||||||
|
self.pygame_screen.fill(self.COLORS[0])
|
||||||
|
self.sensehat.clear()
|
||||||
|
except AttributeError:
|
||||||
|
print("[Game][error] An error occurred starting game countdown")
|
||||||
|
|
||||||
|
def __loop(self):
|
||||||
|
print("[Game][info] Starting game loop")
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.pygame.time.set_timer(pygame.USEREVENT + 1, self.INTERVAL)
|
||||||
|
|
||||||
|
key_actions = {
|
||||||
|
'ESCAPE': lambda: self.quit(),
|
||||||
|
'LEFT': lambda: self.__direction_left(),
|
||||||
|
'RIGHT': lambda: self.__direction_right(),
|
||||||
|
'DOWN': lambda: self.__direction_down(),
|
||||||
|
'UP': lambda: self.__direction_up(),
|
||||||
|
'p': lambda: self.toggle_pause(),
|
||||||
|
}
|
||||||
|
|
||||||
|
pygame_clock = self.pygame.time.Clock()
|
||||||
|
|
||||||
|
while not self.GAMEOVER:
|
||||||
|
self.sensehat.clear()
|
||||||
|
self.pygame_screen.fill(self.COLORS[0])
|
||||||
|
|
||||||
|
if self.PAUSED:
|
||||||
|
self.__display_message("Paused")
|
||||||
|
else:
|
||||||
|
self.__draw_line(
|
||||||
|
((self.BLOCK_SIZE * self.COLUMNS) + 1, 0),
|
||||||
|
((self.BLOCK_SIZE * self.COLUMNS) + 1, (self.HEIGHT - 1)),
|
||||||
|
self.COLORS[9]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.__display_message(
|
||||||
|
"Score: %d\n\nLevel: %d\n\nApples: %d" % (self.SCORE, self.LEVEL, self.APPLES),
|
||||||
|
((self.BLOCK_SIZE * self.COLUMNS) + self.BLOCK_SIZE, 2),
|
||||||
|
self.COLORS[9],
|
||||||
|
self.COLORS[0],
|
||||||
|
False
|
||||||
|
)
|
||||||
|
|
||||||
|
self.__draw_matrix(self.BACKGROUND_GRID, (0, 0), None, False)
|
||||||
|
self.__draw_matrix(self.board.coordinates(), (0, 0), None, False)
|
||||||
|
self.__draw_matrix(self.snake.coordinates(self.COLUMNS, self.ROWS), (0, 0))
|
||||||
|
self.__draw_matrix(self.apple.coordinates(), (self.apple.x(), self.apple.y()))
|
||||||
|
|
||||||
|
self.pygame.display.update()
|
||||||
|
|
||||||
|
for event in self.pygame.event.get():
|
||||||
|
if event.type == self.pygame.USEREVENT + 1:
|
||||||
|
self.__move()
|
||||||
|
elif event.type == self.pygame.QUIT:
|
||||||
|
self.quit()
|
||||||
|
elif event.type == self.pygame.KEYDOWN:
|
||||||
|
for key in key_actions:
|
||||||
|
if event.key == eval("self.pygame.K_" + key):
|
||||||
|
key_actions[key]()
|
||||||
|
|
||||||
|
pygame_clock.tick(self.FPS)
|
||||||
|
except AttributeError:
|
||||||
|
print("[Game][error] An error occurred during game loop")
|
||||||
|
|
||||||
|
def __generate_snake(self):
|
||||||
|
print("[Game][info] Generating snake")
|
||||||
|
|
||||||
|
self.snake = Snake(self.SHAPES[0], int(math.floor(self.COLUMNS / 2)), int(math.floor(self.ROWS / 2)))
|
||||||
|
|
||||||
|
def __generate_apple(self):
|
||||||
|
print("[Game][info] Generating apple")
|
||||||
|
|
||||||
|
apple_collision = True
|
||||||
|
offset_x, offset_y = (0, 0)
|
||||||
|
|
||||||
|
while apple_collision:
|
||||||
|
offset_x = randint(0, self.ROWS - 1)
|
||||||
|
offset_y = randint(0, self.COLUMNS - 1)
|
||||||
|
|
||||||
|
apple_collision = self.board.check_collision(self.snake, (offset_x, offset_y))
|
||||||
|
|
||||||
|
self.apple = Apple(self.SHAPES[1], offset_x, offset_y)
|
||||||
|
|
||||||
|
def __display_message(self, message, coordinates=None, color=COLORS[9], background_color=COLORS[0], sensehat=True):
|
||||||
|
print("[Game][info] Displaying message")
|
||||||
|
|
||||||
|
if sensehat:
|
||||||
|
self.sensehat.show_message(message, text_colour=color, scroll_speed=0.05)
|
||||||
|
|
||||||
|
for i, line in enumerate(message.splitlines()):
|
||||||
|
message_image = self.pygame_font.render(line, False, color, background_color)
|
||||||
|
|
||||||
|
if coordinates is not None:
|
||||||
|
position_x, position_y = coordinates
|
||||||
|
else:
|
||||||
|
message_image_center_x, message_image_center_y = message_image.get_size()
|
||||||
|
message_image_center_x //= 2
|
||||||
|
message_image_center_y //= 2
|
||||||
|
position_x = self.WIDTH // 2 - message_image_center_x
|
||||||
|
position_y = self.HEIGHT // 2 - message_image_center_y
|
||||||
|
|
||||||
|
self.pygame_screen.blit(
|
||||||
|
message_image,
|
||||||
|
(position_x, position_y + i * 22)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __draw_line(self, start_position, end_position, color=COLORS[9], sensehat=True):
|
||||||
|
print("[Game][info] Drawing line")
|
||||||
|
|
||||||
|
if sensehat:
|
||||||
|
start_x, start_y = start_position
|
||||||
|
end_x, end_y = start_position
|
||||||
|
|
||||||
|
for i in xrange(start_y, end_y):
|
||||||
|
for j in xrange(start_x, end_x):
|
||||||
|
if start_x == end_x or start_y == end_y:
|
||||||
|
self.sensehat.set_pixel(j, i, color)
|
||||||
|
|
||||||
|
self.pygame.draw.line(self.pygame_screen, color, start_position, end_position)
|
||||||
|
|
||||||
|
def __draw_matrix(self, matrix, offset, color=None, sensehat=True):
|
||||||
|
print("[Game][info] Drawing matrix")
|
||||||
|
|
||||||
|
offset_x, offset_y = offset
|
||||||
|
|
||||||
|
for y, row in enumerate(matrix):
|
||||||
|
for x, val in enumerate(row):
|
||||||
|
if val:
|
||||||
|
if color is None:
|
||||||
|
shape_color = self.COLORS[val]
|
||||||
|
else:
|
||||||
|
shape_color = color
|
||||||
|
|
||||||
|
if sensehat:
|
||||||
|
self.sensehat.set_pixel((offset_x + x), (offset_y + y), shape_color)
|
||||||
|
|
||||||
|
self.pygame.draw.rect(
|
||||||
|
self.pygame_screen,
|
||||||
|
shape_color,
|
||||||
|
self.pygame.Rect((offset_x + x) * self.BLOCK_SIZE, (offset_y + y) * self.BLOCK_SIZE, self.BLOCK_SIZE, self.BLOCK_SIZE),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
|
||||||
|
def __count_clear_apples(self, apples):
|
||||||
|
print("[Game][info] Counting cleared apples")
|
||||||
|
|
||||||
|
if apples > 0:
|
||||||
|
self.APPLES += apples
|
||||||
|
self.SCORE += self.SCORE_INCREMENT * self.LEVEL
|
||||||
|
|
||||||
|
if self.APPLES >= self.LEVEL * self.LEVEL_INCREMENT:
|
||||||
|
self.LEVEL += 1
|
||||||
|
delay = self.INTERVAL - self.INTERVAL_INCREMENT * (self.LEVEL - 1)
|
||||||
|
delay = 100 if delay < 100 else delay
|
||||||
|
self.pygame.time.set_timer(self.pygame.USEREVENT + 1, delay)
|
||||||
|
|
||||||
|
def __move(self):
|
||||||
|
print("[Game][info] Moving snake %s" % (self.snake.direction()))
|
||||||
|
|
||||||
|
if not self.GAMEOVER and not self.PAUSED:
|
||||||
|
new_x, new_y = self.snake.head()
|
||||||
|
|
||||||
|
if self.snake.direction() == self.snake.DIRECTION_UP:
|
||||||
|
new_y = self.snake.y() - 1
|
||||||
|
elif self.snake.direction() == self.snake.DIRECTION_DOWN:
|
||||||
|
new_y = self.snake.y() + 1
|
||||||
|
elif self.snake.direction() == self.snake.DIRECTION_LEFT:
|
||||||
|
new_x = self.snake.x() - 1
|
||||||
|
elif self.snake.direction() == self.snake.DIRECTION_RIGHT:
|
||||||
|
new_x = self.snake.x() + 1
|
||||||
|
|
||||||
|
if self.board.check_collision(self.snake, (new_x, new_y)):
|
||||||
|
self.GAMEOVER = True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
tail_x, tail_y = self.snake.tail()
|
||||||
|
self.snake.set_position((new_x, new_y))
|
||||||
|
cleared_apples = 0
|
||||||
|
|
||||||
|
if new_x == self.apple.x() and new_y == self.apple.y():
|
||||||
|
self.snake.add_segment((tail_x, tail_y))
|
||||||
|
cleared_apples += 1
|
||||||
|
self.__generate_apple()
|
||||||
|
|
||||||
|
self.__count_clear_apples(cleared_apples)
|
||||||
|
self.SNAKE_MOVED = True
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __direction_up(self):
|
||||||
|
print("[Game][info] Event direction up")
|
||||||
|
|
||||||
|
if self.snake.direction() != self.snake.DIRECTION_DOWN and self.SNAKE_MOVED is True:
|
||||||
|
self.snake.set_direction(self.snake.DIRECTION_UP)
|
||||||
|
self.SNAKE_MOVED = False
|
||||||
|
|
||||||
|
def __direction_down(self):
|
||||||
|
print("[Game][info] Event direction down")
|
||||||
|
|
||||||
|
if self.snake.direction() != self.snake.DIRECTION_UP and self.SNAKE_MOVED is True:
|
||||||
|
self.snake.set_direction(self.snake.DIRECTION_DOWN)
|
||||||
|
self.SNAKE_MOVED = False
|
||||||
|
|
||||||
|
def __direction_left(self):
|
||||||
|
print("[Game][info] Event direction left")
|
||||||
|
|
||||||
|
if self.snake.direction() != self.snake.DIRECTION_RIGHT and self.SNAKE_MOVED is True:
|
||||||
|
self.snake.set_direction(self.snake.DIRECTION_LEFT)
|
||||||
|
self.SNAKE_MOVED = False
|
||||||
|
|
||||||
|
def __direction_right(self):
|
||||||
|
print("[Game][info] Event direction right")
|
||||||
|
|
||||||
|
if self.snake.direction() != self.snake.DIRECTION_LEFT and self.SNAKE_MOVED is True:
|
||||||
|
self.snake.set_direction(self.snake.DIRECTION_RIGHT)
|
||||||
|
self.SNAKE_MOVED = False
|
||||||
|
|
||||||
|
def toggle_pause(self):
|
||||||
|
print("[Game][info] Toggling paused state")
|
||||||
|
|
||||||
|
self.PAUSED = not self.PAUSED
|
||||||
|
|
||||||
|
def get_score(self):
|
||||||
|
print("[Game][info] Calculating score")
|
||||||
|
|
||||||
|
return self.SCORE
|
||||||
|
|
||||||
|
def print_score(self, high_score=False):
|
||||||
|
print("[Game][info] Printing score")
|
||||||
|
|
||||||
|
score = self.get_score()
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.sensehat.clear()
|
||||||
|
self.pygame_screen.fill(self.COLORS[0])
|
||||||
|
|
||||||
|
if high_score:
|
||||||
|
self.__display_message("Game Over!\n\nHigh score: %d" % score)
|
||||||
|
self.pygame.display.update()
|
||||||
|
else:
|
||||||
|
self.__display_message("Game Over!\n\nYour score: %d!" % self.get_score())
|
||||||
|
self.pygame.display.update()
|
||||||
|
|
||||||
|
self.pygame.time.wait(3000)
|
||||||
|
except AttributeError:
|
||||||
|
print("[Game][error] An error occurred printing score")
|
||||||
|
|
||||||
|
def finish(self):
|
||||||
|
print("[Game][info] Finishing game")
|
||||||
|
|
||||||
|
score = self.get_score()
|
||||||
|
|
||||||
|
self.pygame.display.update()
|
||||||
|
|
||||||
|
if self.db.contains(Query().score >= score):
|
||||||
|
self.print_score()
|
||||||
|
else:
|
||||||
|
self.print_score(True)
|
||||||
|
|
||||||
|
self.db.insert({'score': score})
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
def quit(self):
|
||||||
|
print("[Game][info] Quitting game")
|
||||||
|
|
||||||
|
self.pygame_screen.fill(self.COLORS[0])
|
||||||
|
self.sensehat.clear()
|
||||||
|
self.__display_message("Exiting...")
|
||||||
|
self.pygame.display.update()
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
print("[Game][info] Resetting game")
|
||||||
|
|
||||||
|
self.PAUSED = False
|
||||||
|
self.GAMEOVER = False
|
||||||
|
self.SCORE = 0
|
||||||
|
self.APPLES = 0
|
||||||
|
self.LEVEL = 1
|
||||||
|
self.SNAKE_MOVED = True
|
||||||
|
|
||||||
|
self.board = Board(self.COLUMNS, self.ROWS)
|
||||||
|
self.snake = None
|
||||||
|
self.apple = None
|
||||||
|
self.__generate_snake()
|
||||||
|
self.__generate_apple()
|
||||||
|
|
||||||
|
self.sensehat.clear()
|
||||||
|
self.pygame.time.set_timer(pygame.USEREVENT + 1, 0)
|
||||||
|
self.pygame.display.update()
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
print("[Game][info] Game clean up")
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.sensehat.clear()
|
||||||
|
self.pygame_screen.fill(self.COLORS[0])
|
||||||
|
self.pygame.display.update()
|
||||||
|
self.pygame.quit()
|
||||||
|
except AttributeError:
|
||||||
|
print("[Game][error] An error occurred cleaning up")
|
||||||
|
|
||||||
|
def __exit__(self):
|
||||||
|
print("[Game][info] Game exit")
|
||||||
|
|
||||||
|
self.cleanup()
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class Snake:
|
||||||
|
COORDINATES = None
|
||||||
|
|
||||||
|
SEGMENTS = None
|
||||||
|
|
||||||
|
X = None
|
||||||
|
Y = None
|
||||||
|
|
||||||
|
DIRECTION = None
|
||||||
|
|
||||||
|
DIRECTION_UP = 'up'
|
||||||
|
DIRECTION_DOWN = 'down'
|
||||||
|
DIRECTION_LEFT = 'left'
|
||||||
|
DIRECTION_RIGHT = 'right'
|
||||||
|
|
||||||
|
def __init__(self, coordinates, x=0, y=0, direction=DIRECTION_LEFT):
|
||||||
|
print("[Snake][info] Initialising Snake")
|
||||||
|
|
||||||
|
self.COORDINATES = coordinates
|
||||||
|
self.SEGMENTS = []
|
||||||
|
self.add_segment((x, y))
|
||||||
|
self.X = x
|
||||||
|
self.Y = y
|
||||||
|
self.DIRECTION = direction
|
||||||
|
|
||||||
|
def set_coordinates(self, coordinates):
|
||||||
|
print("[Snake][info] Setting Snake coordinates")
|
||||||
|
|
||||||
|
self.COORDINATES = coordinates
|
||||||
|
|
||||||
|
def set_direction(self, direction):
|
||||||
|
print("[Snake][info] Setting Snake direction")
|
||||||
|
|
||||||
|
self.DIRECTION = direction
|
||||||
|
|
||||||
|
def set_x(self, x):
|
||||||
|
print("[Snake][info] Setting Snake X position")
|
||||||
|
|
||||||
|
if self.length() > 1:
|
||||||
|
self.remove_segment(-1)
|
||||||
|
self.add_segment((x, self.SEGMENTS[0][1]), 0)
|
||||||
|
else:
|
||||||
|
self.SEGMENTS[0] = (x, self.SEGMENTS[0][1])
|
||||||
|
|
||||||
|
self.X = x
|
||||||
|
|
||||||
|
def set_y(self, y):
|
||||||
|
print("[Snake][info] Setting Snake Y position")
|
||||||
|
|
||||||
|
if self.length() > 1:
|
||||||
|
self.remove_segment(-1)
|
||||||
|
self.add_segment((self.SEGMENTS[0][0], y), 0)
|
||||||
|
else:
|
||||||
|
self.SEGMENTS[0] = (self.SEGMENTS[0][0], y)
|
||||||
|
|
||||||
|
self.Y = y
|
||||||
|
|
||||||
|
def set_position(self, coordinates):
|
||||||
|
print("[Snake][info] Setting Snake X, Y position")
|
||||||
|
|
||||||
|
x, y = coordinates
|
||||||
|
|
||||||
|
if self.length() > 1:
|
||||||
|
self.remove_segment(-1)
|
||||||
|
self.add_segment(coordinates, 0)
|
||||||
|
else:
|
||||||
|
self.SEGMENTS[0] = coordinates
|
||||||
|
|
||||||
|
self.X = x
|
||||||
|
self.Y = y
|
||||||
|
|
||||||
|
def add_segment(self, coordinates, position=-1):
|
||||||
|
print("[Snake][info] Creating Snake segment at index %d" % (position))
|
||||||
|
|
||||||
|
self.SEGMENTS.insert(position if position != -1 else len(self.SEGMENTS), coordinates)
|
||||||
|
|
||||||
|
def remove_segment(self, position=-1):
|
||||||
|
print("[Snake][info] Removing Snake segment at index %d" % (position))
|
||||||
|
|
||||||
|
self.SEGMENTS.pop(position)
|
||||||
|
|
||||||
|
def coordinates(self, columns=0, rows=0):
|
||||||
|
print("[Snake][info] Getting Snake coordinates")
|
||||||
|
|
||||||
|
if columns == 0 and rows == 0:
|
||||||
|
return self.COORDINATES
|
||||||
|
|
||||||
|
coordinates = [
|
||||||
|
[False for x in xrange(columns)]
|
||||||
|
for y in xrange(rows)
|
||||||
|
]
|
||||||
|
|
||||||
|
for segment in self.SEGMENTS:
|
||||||
|
coordinates[segment[1]][segment[0]] = self.COORDINATES[0][0]
|
||||||
|
|
||||||
|
return coordinates
|
||||||
|
|
||||||
|
def direction(self):
|
||||||
|
print("[Snake][info] Getting Snake direction")
|
||||||
|
|
||||||
|
return self.DIRECTION
|
||||||
|
|
||||||
|
def x(self):
|
||||||
|
print("[Snake][info] Getting Snake X position")
|
||||||
|
|
||||||
|
return self.X
|
||||||
|
|
||||||
|
def y(self):
|
||||||
|
print("[Snake][info] Getting Snake Y position")
|
||||||
|
|
||||||
|
return self.Y
|
||||||
|
|
||||||
|
def position(self):
|
||||||
|
print("[Snake][info] Getting Snake X,Y position")
|
||||||
|
|
||||||
|
return (self.X, self.Y)
|
||||||
|
|
||||||
|
def segments(self):
|
||||||
|
print("[Snake][info] Getting all Snake segments")
|
||||||
|
|
||||||
|
return self.SEGMENTS
|
||||||
|
|
||||||
|
def head(self):
|
||||||
|
print("[Snake][info] Getting Snake head")
|
||||||
|
|
||||||
|
return self.SEGMENTS[0]
|
||||||
|
|
||||||
|
def body(self):
|
||||||
|
print("[Snake][info] Getting Snake body")
|
||||||
|
|
||||||
|
if len(self.SEGMENTS) < 2:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self.SEGMENTS[1:]
|
||||||
|
|
||||||
|
def tail(self):
|
||||||
|
print("[Snake][info] Getting Snake tail")
|
||||||
|
|
||||||
|
return self.SEGMENTS[-1]
|
||||||
|
|
||||||
|
def length(self):
|
||||||
|
print("[Snake][info] Getting Snake length")
|
||||||
|
|
||||||
|
return len(self.SEGMENTS)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
print("[Snake][info] Clearing Snake")
|
||||||
|
|
||||||
|
self.COORDINATES = None
|
||||||
|
self.SEGMENTS = None
|
||||||
|
self.X = None
|
||||||
|
self.Y = None
|
||||||
|
self.DIRECTION = None
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
print("[Snake][info] Snake clean up")
|
||||||
|
|
||||||
|
self.clear()
|
||||||
|
|
||||||
|
def __exit__(self):
|
||||||
|
print("[Snake][info] Snake exit")
|
||||||
|
|
||||||
|
self.cleanup()
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
from lib.game import Game
|
||||||
|
import atexit
|
||||||
|
import config
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
game = Game(
|
||||||
|
config.game['columns'],
|
||||||
|
config.game['rows'],
|
||||||
|
config.game['fps'],
|
||||||
|
config.game['countdown'],
|
||||||
|
config.game['interval'],
|
||||||
|
config.game['score_increment'],
|
||||||
|
config.game['level_increment'],
|
||||||
|
config.game['interval_increment'],
|
||||||
|
)
|
||||||
|
|
||||||
|
game.start()
|
||||||
|
|
||||||
|
atexit.register(game.__exit__)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
from setuptools import setup, find_packages
|
||||||
|
from codecs import open
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
here = path.abspath(path.dirname(__file__))
|
||||||
|
|
||||||
|
with open(path.join(here, 'README.md'), encoding='utf-8') as f:
|
||||||
|
long_description = f.read()
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='sense-hat-snake',
|
||||||
|
|
||||||
|
version='1.0.0',
|
||||||
|
|
||||||
|
description='Raspberry Pi Python sense hat snake',
|
||||||
|
long_description=long_description,
|
||||||
|
|
||||||
|
url='https://github.com/bradcornford/Sense-Hat-Snake',
|
||||||
|
|
||||||
|
author='Bradley Cornford',
|
||||||
|
author_email='me@bradleycornford.co.uk',
|
||||||
|
|
||||||
|
license='MIT',
|
||||||
|
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 5 - Production/Stable',
|
||||||
|
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
|
||||||
|
'Topic :: Software Development :: Build Tools',
|
||||||
|
|
||||||
|
'License :: OSI Approved :: MIT License',
|
||||||
|
|
||||||
|
'Programming Language :: Python :: 2',
|
||||||
|
'Programming Language :: Python :: 2.7',
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
'Programming Language :: Python :: 3.3',
|
||||||
|
'Programming Language :: Python :: 3.4',
|
||||||
|
'Programming Language :: Python :: 3.5',
|
||||||
|
],
|
||||||
|
|
||||||
|
keywords='sense hat snake raspberry pi',
|
||||||
|
|
||||||
|
packages=find_packages(exclude=['contrib', 'docs', 'test']),
|
||||||
|
|
||||||
|
install_requires=['pygame', 'sense-hat', 'tinydb', 'mock'],
|
||||||
|
|
||||||
|
extras_require={
|
||||||
|
'dev': ['check-manifest'],
|
||||||
|
'test': ['coverage'],
|
||||||
|
},
|
||||||
|
|
||||||
|
package_data={},
|
||||||
|
|
||||||
|
data_files=[],
|
||||||
|
|
||||||
|
entry_points={
|
||||||
|
'console_scripts': []
|
||||||
|
},
|
||||||
|
)
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
from sensehatsnake.lib.apple import Apple
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class AppleTestCase(unittest.TestCase):
|
||||||
|
COORDINATES = [
|
||||||
|
[1]
|
||||||
|
]
|
||||||
|
|
||||||
|
apple = None
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.apple = Apple(self.COORDINATES)
|
||||||
|
|
||||||
|
def test__init__(self):
|
||||||
|
self.assertIsInstance(self.apple, Apple)
|
||||||
|
|
||||||
|
def test_set_coordinates(self):
|
||||||
|
self.assertIs(self.apple.set_coordinates([[0]]), None)
|
||||||
|
self.assertEquals(self.apple.coordinates(), [[0]])
|
||||||
|
|
||||||
|
def test_set_x(self):
|
||||||
|
self.assertIs(self.apple.set_x(1), None)
|
||||||
|
self.assertEquals(self.apple.x(), 1)
|
||||||
|
|
||||||
|
def test_set_y(self):
|
||||||
|
self.assertIs(self.apple.set_y(1), None)
|
||||||
|
self.assertEquals(self.apple.y(), 1)
|
||||||
|
|
||||||
|
def test_set_position(self):
|
||||||
|
self.assertIs(self.apple.set_position((1, 1)), None)
|
||||||
|
self.assertEquals(self.apple.x(), 1)
|
||||||
|
self.assertEquals(self.apple.y(), 1)
|
||||||
|
|
||||||
|
def test_coordinates(self):
|
||||||
|
self.assertEquals(self.apple.coordinates(), self.COORDINATES)
|
||||||
|
|
||||||
|
def test_x(self):
|
||||||
|
self.assertEquals(self.apple.x(), 0)
|
||||||
|
|
||||||
|
def test_y(self):
|
||||||
|
self.assertEquals(self.apple.y(), 0)
|
||||||
|
|
||||||
|
def test_position(self):
|
||||||
|
self.assertEquals(self.apple.position(), (0, 0))
|
||||||
|
|
||||||
|
def test_cleanup(self):
|
||||||
|
self.assertIs(self.apple.cleanup(), None)
|
||||||
|
|
||||||
|
def test__exit__(self):
|
||||||
|
self.assertIs(self.apple.__exit__(), None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
from sensehatsnake.lib.board import Board
|
||||||
|
from sensehatsnake.lib.snake import Snake
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class BoardTestCase(unittest.TestCase):
|
||||||
|
COLUMNS = 2
|
||||||
|
ROWS = 2
|
||||||
|
|
||||||
|
board = None
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.board = Board(self.COLUMNS, self.ROWS)
|
||||||
|
|
||||||
|
def test__init__(self):
|
||||||
|
self.assertIsInstance(self.board, Board)
|
||||||
|
|
||||||
|
def test_columns(self):
|
||||||
|
self.assertEquals(self.board.columns(), self.COLUMNS)
|
||||||
|
|
||||||
|
def test_rows(self):
|
||||||
|
self.assertEquals(self.board.rows(), self.ROWS)
|
||||||
|
|
||||||
|
def test_coordinates(self):
|
||||||
|
self.assertEquals(self.board.coordinates(), [[0, 0], [0, 0]])
|
||||||
|
|
||||||
|
def test_check_collision(self):
|
||||||
|
snake = Snake([[1]])
|
||||||
|
self.assertIs(self.board.check_collision(snake, (snake.x(), snake.y())), True)
|
||||||
|
|
||||||
|
def test_clear(self):
|
||||||
|
self.assertIs(self.board.clear(), None)
|
||||||
|
|
||||||
|
def test_cleanup(self):
|
||||||
|
self.assertIs(self.board.cleanup(), None)
|
||||||
|
|
||||||
|
def test__exit__(self):
|
||||||
|
self.assertIs(self.board.__exit__(), None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
from sensehatsnake.lib.game import Game
|
||||||
|
from mock import MagicMock
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class GameTestCase(unittest.TestCase):
|
||||||
|
COLUMNS = 2
|
||||||
|
ROWS = 2
|
||||||
|
FPS = 1
|
||||||
|
COUNTDOWN = 0
|
||||||
|
INTERVAL = 0
|
||||||
|
SCORE_INCREMENT = 1
|
||||||
|
LEVEL_INCREMENT = 1
|
||||||
|
INTERVAL_INCREMENT = 0
|
||||||
|
|
||||||
|
game = None
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
mock = MagicMock()
|
||||||
|
|
||||||
|
keypress_event_mock = MagicMock()
|
||||||
|
keypress_event_mock.type = 1
|
||||||
|
keypress_event_mock.key = 1
|
||||||
|
|
||||||
|
userevent_event_mock = MagicMock()
|
||||||
|
userevent_event_mock.type = 3
|
||||||
|
|
||||||
|
mock.get_size.return_value = (0, 0)
|
||||||
|
mock.get.return_value = [keypress_event_mock, userevent_event_mock]
|
||||||
|
mock.get_ticks.side_effect = [0, 6000, 0, 5000]
|
||||||
|
|
||||||
|
mock.Font.return_value = mock
|
||||||
|
mock.render.return_value = mock
|
||||||
|
|
||||||
|
mock.KEYDOWN = 1
|
||||||
|
mock.K_RETURN = 1
|
||||||
|
mock.USEREVENT = 2
|
||||||
|
|
||||||
|
mock.font = mock
|
||||||
|
mock.display = mock
|
||||||
|
mock.event = mock
|
||||||
|
mock.time = mock
|
||||||
|
|
||||||
|
self.game = Game(
|
||||||
|
self.COLUMNS,
|
||||||
|
self.ROWS,
|
||||||
|
self.FPS,
|
||||||
|
self.COUNTDOWN,
|
||||||
|
self.INTERVAL,
|
||||||
|
self.SCORE_INCREMENT,
|
||||||
|
self.LEVEL_INCREMENT,
|
||||||
|
self.INTERVAL_INCREMENT,
|
||||||
|
mock
|
||||||
|
)
|
||||||
|
|
||||||
|
def test__init__(self):
|
||||||
|
self.assertIsInstance(self.game, Game)
|
||||||
|
|
||||||
|
def test_start(self):
|
||||||
|
self.assertIs(self.game.start(True), None)
|
||||||
|
|
||||||
|
def test_toggle_pause(self):
|
||||||
|
self.assertIs(self.game.toggle_pause(), None)
|
||||||
|
self.assertEqual(self.game.PAUSED, True)
|
||||||
|
self.assertIs(self.game.toggle_pause(), None)
|
||||||
|
self.assertEqual(self.game.PAUSED, False)
|
||||||
|
|
||||||
|
def test_get_score(self):
|
||||||
|
self.assertIs(self.game.get_score(), 0)
|
||||||
|
|
||||||
|
def test_print_score(self):
|
||||||
|
self.assertIs(self.game.print_score(), None)
|
||||||
|
|
||||||
|
def test_finish(self):
|
||||||
|
self.assertIs(self.game.finish(), None)
|
||||||
|
|
||||||
|
def test_quit(self):
|
||||||
|
with self.assertRaises(SystemExit):
|
||||||
|
self.assertIs(self.game.quit(), None)
|
||||||
|
|
||||||
|
def test_reset(self):
|
||||||
|
self.assertIs(self.game.reset(), None)
|
||||||
|
|
||||||
|
def test_cleanup(self):
|
||||||
|
self.assertIs(self.game.cleanup(), None)
|
||||||
|
|
||||||
|
def test__exit__(self):
|
||||||
|
self.assertIs(self.game.__exit__(), None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
from sensehatsnake.lib.snake import Snake
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class SnakeTestCase(unittest.TestCase):
|
||||||
|
COORDINATES = [
|
||||||
|
[1]
|
||||||
|
]
|
||||||
|
|
||||||
|
COLUMNS = 2
|
||||||
|
ROWS = 2
|
||||||
|
|
||||||
|
snake = None
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.snake = Snake(self.COORDINATES)
|
||||||
|
|
||||||
|
def test__init__(self):
|
||||||
|
self.assertIsInstance(self.snake, Snake)
|
||||||
|
|
||||||
|
def test_set_coordinates(self):
|
||||||
|
self.assertIs(self.snake.set_coordinates([[0]]), None)
|
||||||
|
self.assertEquals(self.snake.coordinates(), [[0]])
|
||||||
|
|
||||||
|
def test_set_direction(self):
|
||||||
|
self.assertIs(self.snake.set_direction(self.snake.DIRECTION_UP), None)
|
||||||
|
self.assertEquals(self.snake.direction(), self.snake.DIRECTION_UP)
|
||||||
|
|
||||||
|
def test_set_x(self):
|
||||||
|
self.assertIs(self.snake.set_x(1), None)
|
||||||
|
self.assertEquals(self.snake.x(), 1)
|
||||||
|
|
||||||
|
def test_set_y(self):
|
||||||
|
self.assertIs(self.snake.set_y(1), None)
|
||||||
|
self.assertEquals(self.snake.y(), 1)
|
||||||
|
|
||||||
|
def test_set_position(self):
|
||||||
|
self.assertIs(self.snake.set_position((1, 1)), None)
|
||||||
|
self.assertEquals(self.snake.x(), 1)
|
||||||
|
self.assertEquals(self.snake.y(), 1)
|
||||||
|
|
||||||
|
def test_add_segment(self):
|
||||||
|
self.assertIs(self.snake.add_segment((1, 1)), None)
|
||||||
|
self.assertEquals(self.snake.length(), 2)
|
||||||
|
|
||||||
|
def test_remove_segment(self):
|
||||||
|
self.assertIs(self.snake.remove_segment(), None)
|
||||||
|
self.assertEquals(self.snake.length(), 0)
|
||||||
|
|
||||||
|
def test_coordinates(self):
|
||||||
|
self.assertEquals(self.snake.coordinates(), self.COORDINATES)
|
||||||
|
self.assertEquals(self.snake.coordinates(self.COLUMNS, self.ROWS), [[self.COORDINATES[0][0], False], [False, False]])
|
||||||
|
|
||||||
|
def test_direction(self):
|
||||||
|
self.assertEquals(self.snake.direction(), self.snake.DIRECTION_LEFT)
|
||||||
|
|
||||||
|
def test_x(self):
|
||||||
|
self.assertEquals(self.snake.x(), 0)
|
||||||
|
|
||||||
|
def test_y(self):
|
||||||
|
self.assertEquals(self.snake.y(), 0)
|
||||||
|
|
||||||
|
def test_position(self):
|
||||||
|
self.assertEquals(self.snake.position(), (0, 0))
|
||||||
|
|
||||||
|
def test_segments(self):
|
||||||
|
self.assertEquals(self.snake.segments(), [(0, 0)])
|
||||||
|
|
||||||
|
def test_head(self):
|
||||||
|
self.assertEquals(self.snake.head(), (0, 0))
|
||||||
|
|
||||||
|
def test_body(self):
|
||||||
|
self.assertEquals(self.snake.body(), None)
|
||||||
|
|
||||||
|
def test_tail(self):
|
||||||
|
self.assertEquals(self.snake.tail(), (0, 0))
|
||||||
|
|
||||||
|
def test_length(self):
|
||||||
|
self.assertEquals(self.snake.length(), 1)
|
||||||
|
|
||||||
|
def test_cleanup(self):
|
||||||
|
self.assertIs(self.snake.cleanup(), None)
|
||||||
|
|
||||||
|
def test__exit__(self):
|
||||||
|
self.assertIs(self.snake.__exit__(), None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
import sensehatsnake.main
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class MainTestCase(unittest.TestCase):
|
||||||
|
def test__init__(self):
|
||||||
|
self.assertTrue("main" in dir(sensehatsnake.main))
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
[tox]
|
||||||
|
envlist = py{27,33,34}
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
basepython =
|
||||||
|
py27: python2.7
|
||||||
|
py33: python3.3
|
||||||
|
py34: python3.4
|
||||||
|
deps =
|
||||||
|
check-manifest
|
||||||
|
readme_renderer
|
||||||
|
flake8
|
||||||
|
pytest
|
||||||
|
commands =
|
||||||
|
check-manifest --ignore tox.ini,tests*
|
||||||
|
python setup.py check -m -r -s
|
||||||
|
flake8 .
|
||||||
|
py.test tests
|
||||||
|
[flake8]
|
||||||
|
exclude = .tox,*.egg,build,data
|
||||||
|
select = E,W,F
|
||||||
Reference in New Issue
Block a user