Last active
December 27, 2015 22:10
-
-
Save qrees/7397360 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
from collections import namedtuple, deque, defaultdict | |
import random | |
import time | |
import imp | |
import sys | |
Point = namedtuple('Point', ['x', 'y']) | |
class Board(object): | |
def __init__(self, width=10, height=10): | |
self.width = width | |
self.height = height | |
self.fields = [['.'] * width for _ in range(height)] | |
self.empty_fields = set(Point(x, y) for x in range(width) for y in range(height)) | |
self.apples = set() | |
def __getitem__(self, p): | |
x, y = p | |
if x < 0 or x >= self.width or y < 0 or y >= self.height: | |
return '#' | |
return self.fields[y][x] | |
def __setitem__(self, p, value): | |
x, y = p | |
if x < 0 or x >= self.width or y < 0 or y >= self.height: | |
return | |
self.fields[y][x] = value | |
if value == 'o': | |
self.apples.add(Point(x, y)) | |
else: | |
self.apples.discard(Point(x, y)) | |
if value == '.': | |
self.empty_fields.add(Point(x, y)) | |
else: | |
self.empty_fields.discard(Point(x, y)) | |
def random_empty_field(self): | |
if len(self.empty_fields) == 0: | |
return None | |
return random.sample(self.empty_fields, 1)[0] | |
def apples(self): | |
return self.apples | |
def __str__(self): | |
result = [] | |
for row in self.fields: | |
result.append(''.join(row)) | |
return '\n'.join(result) | |
class Snake(object): | |
def __init__(self, parts, move, direction=None, color=None, name='annonymous'): | |
self.parts = deque(parts) if parts is not None else deque([Point(4, 4)]) | |
self.direction = direction if direction is not None else 'right' | |
self.ate_apple = False | |
self.dead = False | |
self.name = name | |
self.color = color | |
self.move_direction = move | |
@property | |
def head(self): | |
return self.parts[-1] | |
def grow(self): | |
new_part = {'up': Point(self.head.x, self.head.y - 1), | |
'down': Point(self.head.x, self.head.y + 1), | |
'left': Point(self.head.x - 1, self.head.y), | |
'right': Point(self.head.x + 1, self.head.y)}[self.direction] | |
self.parts.append(new_part) | |
return new_part | |
def shrink(self): | |
return self.parts.popleft() | |
def move(self, bb): | |
self.direction = self.move_direction.move(bb) | |
if self.direction not in ['left', 'right', 'up', 'down']: | |
print("Wrong direction: %s" % self.direction) | |
self.dead = True | |
return (None, None) | |
if self.dead: | |
return (None, None) | |
added = self.grow() | |
removed = None | |
if not self.ate_apple: | |
removed = self.shrink() | |
self.ate_apple = False | |
return (added, removed) | |
def as_dict(self): | |
return {'name': self.name, | |
'parts': [[p.x, p.y] for p in self.parts], | |
'dead': self.dead, | |
'color': self.color} | |
class SingleJudge(object): | |
def __init__(self, movefunction, width=10, height=10): | |
self.width = width | |
self.height = height | |
self.board = Board(width, height) | |
self.snakes = [] | |
for fun in movefunction: | |
self.snakes.append(self.spawn_snake('black', fun)) | |
self.turn = 0 | |
def spawn_snake(self, color, move): | |
p = self.board.random_empty_field() | |
self.board[p.x, p.y] = "#" | |
return Snake([p], move, color=color) | |
def spawn_apple(self): | |
p = self.board.random_empty_field() | |
if p is not None: | |
self.board[p.x, p.y] = 'o' | |
def kill_snake(self, snake): | |
for p in snake.parts: | |
self.board[p.x, p.y] = '.' | |
p = self.board.random_empty_field() | |
self.board[p.x, p.y] = "#" | |
snake.parts = deque([p]) | |
snake.move_direction = imp.reload(snake.move_direction) | |
snake.dead = False | |
def check_collisions(self, heads, removed): | |
for p in removed: | |
self.board[p.x, p.y] = '.' | |
for p, snakes in heads.items(): | |
# Check collisions between heads | |
if len(snakes) > 1: | |
for snake in snakes: | |
self.kill_snake(snake) | |
continue | |
# Check collisions between other parts | |
if self.board[p.x, p.y] == '#': | |
for snake in snakes: | |
self.kill_snake(snake) | |
continue | |
# Check collisions with apples | |
if self.board[p.x, p.y] == 'o': | |
for snake in snakes: | |
snake.ate_apple = True | |
self.board[p.x, p.y] = '#' | |
if self.turn % 5 == 0: | |
self.spawn_apple() | |
self.turn += 1 | |
def run(self): | |
while True: | |
bb = str(self.board).splitlines() | |
bb = [list(x) for x in bb] | |
heads = defaultdict(list) | |
removed = [] | |
for snake in self.snakes: | |
hh = snake.head | |
bb[hh.y][hh.x] = 'H' | |
#bb[hh.y] = bb[hh.y][:hh.x] + "H" + bb[hh.y][hh.x+1:] | |
head, tail = snake.move(["".join(x) for x in bb]) | |
bb[hh.y][hh.x] = '#' | |
if head is not None: | |
heads[head].append(snake) | |
if tail is not None: | |
removed.append(tail) | |
if snake.dead: | |
self.kill_snake(snake) | |
self.check_collisions(heads, removed) | |
print(20*'\n') | |
sys.stdout.write("%s" % self.board) | |
sys.stdout.write("\n") | |
sys.stdout.flush() | |
time.sleep(0.1) | |
HEIGHT = 60 | |
WIDTH = 80 | |
def main(): | |
if len(sys.argv) < 2: | |
print("Please add filename as first parameter") | |
exit() | |
else: | |
fs = sys.argv[1:] | |
mods = [] | |
for f in fs: | |
mods.append(__import__(f)) | |
judge = SingleJudge(mods, 80, 60) | |
judge.run() | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment