Working on the code

This commit is contained in:
Thomas Forgione 2019-03-13 20:45:36 +01:00
parent 471a1e0141
commit 9ad99579b6
No known key found for this signature in database
GPG Key ID: BFD17A2D71B3B5E7
6 changed files with 124 additions and 32 deletions

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python3
from snake.map import Map
from snake.game import Game, PositionPlayer
from snake.player import Player, Direction, ConstantPlayer, KeyboardPlayer
from tron.map import Map
from tron.game import Game, PositionPlayer
from tron.player import Player, Direction, ConstantPlayer, KeyboardPlayer
def main():
width = 40

View File

@ -20,10 +20,15 @@ def main():
PositionPlayer(2, ConstantPlayer(Direction.LEFT), [width - 1, height - 1]),
])
window = Window(game, 20)
window = Window(game, 10)
game.main_loop(window)
if game.winner is None:
print("It's a draw!")
else:
print('Player {} wins!'.format(game.winner))
if __name__ == '__main__':
main()

View File

@ -7,7 +7,14 @@ from enum import Enum
from tron.map import Map
class Winner(Enum):
PLAYER_ONE = 1
PLAYER_TWO = 2
class Case(Enum):
"""
The different type of elements that can be in a map.
"""
EMPTY = 0
WALL = -1
PLAYER_ONE_BODY = 1
@ -16,6 +23,9 @@ class Case(Enum):
PLAYER_TWO_HEAD = 4
def color(self):
"""
Converts an element of a map to a nice color.
"""
if self == Case.EMPTY:
return (255, 255, 255)
elif self == Case.WALL:
@ -32,6 +42,10 @@ class Case(Enum):
return None
class PositionPlayer:
"""
A container to store a player with is id, position and boolean indicating
whether it's still alive or not.
"""
def __init__(self, id, player, position):
self.id = id
self.player = player
@ -39,17 +53,36 @@ class PositionPlayer:
self.alive = True
def body(self):
"""
Returns the body type of the PP depending on its id.
"""
if self.id == 1:
return Case.PLAYER_ONE_BODY
elif self.id == 2:
return Case.PLAYER_TWO_BODY
def head(self):
"""
Returns the head type of the PP depending of its id.
"""
if self.id == 1:
return Case.PLAYER_ONE_HEAD
elif self.id == 2:
return Case.PLAYER_TWO_HEAD
class HistoryElement:
"""
An element from an history.
It contains the map, but also the direction of each player during the frame.
The directions of the players will be None at the first frame.
"""
def __init__(self, mmap, player_one_direction, player_two_direction):
self.map = mmap
self.player_one_direction = player_one_direction
self.player_two_direction = player_two_direction
class Game:
"""
This class contains the map of the game, and the players.
@ -65,14 +98,19 @@ class Game:
"""
self.width = width
self.height = height
self.history = [Map(width, height, Case.EMPTY, Case.WALL)]
mmap = Map(width, height, Case.EMPTY, Case.WALL)
self.history = [HistoryElement(mmap, None, None)]
self.pps = pps
self.winner = None
for pp in self.pps:
self.map()[pp.position[0], pp.position[1]] = pp.head()
def map(self):
return self.history[-1]
"""
Returns the current map, the last map in the history.
"""
return self.history[-1].map
def next_frame(self, window = None):
"""
@ -84,8 +122,6 @@ class Game:
that is already occupied or that is outside of the map, the players
dies.
"""
# Clone map
self.history.append(self.map().clone())
# Set previous heads to body
for pp in self.pps:
@ -103,9 +139,12 @@ class Game:
for pp in self.pps:
pp.player.manage_event(event)
player_directions = []
for pp in self.pps:
pp.position = pp.player.next_position(pp.position, self)
(pp.position, direction) = pp.player.next_position_and_direction(pp.position, self)
player_directions.append(direction)
# Check boundaries
if pp.position[0] < 0 or pp.position[1] < 0 or \
@ -120,6 +159,10 @@ class Game:
else:
self.map()[pp.position[0], pp.position[1]] = pp.head()
# Append to history
map_clone = self.map().clone()
self.history.append(HistoryElement(map_clone, player_directions[0], player_directions[1]))
def main_loop(self, window = None):
"""
@ -151,10 +194,7 @@ class Game:
if alive_count <= 1:
if alive_count == 1:
print('Player {} win!'.format(alive + 1))
else:
print('It\'s a draw!')
self.winner = alive + 1
break
if window:

View File

@ -18,7 +18,9 @@ class Map:
"""
Creates a new map from its width and its height.
The matrix is initialized with Nones
The map will contain (height + 2) * (width + 2) tiles, by having a
border. The matrix is initialized with `empty` in the inside and
`wall` on the borders.
"""
self.width = w
self.height = h
@ -28,13 +30,23 @@ class Map:
"""
Creates a clone of the map.
"""
map = Map(self.width, self.height, 0, 0)
map._data = np.copy(self._data)
return map
clone = Map(self.width, self.height, 0, 0)
clone._data = np.copy(self._data)
return clone
def convert(self, converter):
map = Map(self.width, self.height, 0, 0)
map._data = np.fromiter((converter.convert(xi) for xi in self._data), self._data.dtype)
"""
Converts a map by applying a function to each element.
"""
converted = Map(self.width, self.height, 0, 0)
converted._data = np.array([[converter(self._data[i][j]) for i in range(self.height + 2)] for j in range(self.width + 2)])
return converted
def array(self):
"""
Returns the inner array of the map.
"""
return self._data
def __getitem__(self, index):
(i, j) = index
@ -44,11 +56,3 @@ class Map:
(i, j) = position
self._data[i+1][j+1] = other
class Converter:
def __init__(self):
pass
def convert(self, x):
pass

View File

@ -24,16 +24,16 @@ class Player:
def __init__(self):
pass
def next_position(self, current_position, game):
def next_position_and_direction(self, current_position, game):
direction = self.action(game)
if direction == Direction.UP:
return (current_position[0] - 1, current_position[1])
return ((current_position[0] - 1, current_position[1]), direction)
if direction == Direction.RIGHT:
return (current_position[0], current_position[1] + 1)
return ((current_position[0], current_position[1] + 1), direction)
if direction == Direction.DOWN:
return (current_position[0] + 1, current_position[1])
return ((current_position[0] + 1, current_position[1]), direction)
if direction == Direction.LEFT:
return (current_position[0], current_position[1] - 1)
return ((current_position[0], current_position[1] - 1), direction)
def action(self, game):
"""

43
tron/tests/map.py Normal file
View File

@ -0,0 +1,43 @@
import unittest
from tron.map import Map
class TestMap(unittest.TestCase):
def test_constructor(self):
mymap = Map(3, 3, 0, -1)
for i in range(5):
self.assertEqual(mymap._data[0][i], -1)
self.assertEqual(mymap._data[i][0], -1)
self.assertEqual(mymap._data[4][i], -1)
self.assertEqual(mymap._data[i][4], -1)
for i in range(1, 4):
for j in range(1, 4):
self.assertEqual(mymap._data[i][j], 0)
def test_clone(self):
original = Map(3, 3, 0, -1)
mymap = Map(3, 3, 0, -1)
mymap2 = mymap.clone()
for i in range(5):
for j in range(5):
self.assertEqual(mymap._data[i][j], mymap2._data[i][j])
mymap._data[i][j] = 3
for i in range(5):
for j in range(5):
self.assertEqual(original._data[i][j], mymap2._data[i][j])
def test_convert(self):
def increment(x):
return x + 1
original = Map(3, 3, 0, -1)
converted = original.convert(increment)
for i in range(5):
for j in range(5):
self.assertEqual(converted._data[i][j], original._data[i][j] + 1)
if __name__ == '__main__':
unittest.main()