Skip to content

Commit

Permalink
Add Board class; switch to single turn object
Browse files Browse the repository at this point in the history
  • Loading branch information
jacebrowning committed Aug 13, 2015
1 parent 4811433 commit 127b955
Show file tree
Hide file tree
Showing 21 changed files with 257 additions and 192 deletions.
8 changes: 4 additions & 4 deletions data/games/_started_.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
players:
- code: '1234'
color: red
turns:
- done: false
turn:
done: false
moves: []
- code: '5678'
color: blue
turns:
- done: false
turn:
done: false
moves: []
turn: 1
3 changes: 2 additions & 1 deletion gridcommand/domain/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Domain models for the application."""

from .move import Move, Moves
from .turn import Turn, Turns
from .turn import Turn
from .player import Player, Players
from .board import Board
from .game import Game
26 changes: 26 additions & 0 deletions gridcommand/domain/board.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""Classes representing boards."""

import copy

from .. import common


log = common.logger(__name__)


class Board:

"""The board for a game."""

@classmethod
def randomize(cls, players):
"""Create a new random board for the players."""
# TODO: implement randomize
print(players)
return cls()

def update(self, players):
"""Update the board state from the player's moves."""
# TODO: implement update
print(players)
return copy.copy(self)
39 changes: 30 additions & 9 deletions gridcommand/domain/game.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
"""Classes representing games."""

import time
import string
import random

from .. import common
from .player import Players
from .turn import Turn
from .board import Board

log = common.logger(__name__)

Expand All @@ -17,10 +18,12 @@ class Game:
KEY_CHARS = string.ascii_lowercase + string.digits
KEY_LENGTH = 8

def __init__(self, key=None):
def __init__(self, key=None, timestamp=None):
self.key = key or self._generate_key()
self.time = timestamp or self._get_timestamp()
self.players = Players()
self.turn = 0
self.board = None

def __repr__(self):
return "<game: {}>".format(self.key)
Expand All @@ -36,6 +39,10 @@ def _generate_key():
return ''.join(random.choice(Game.KEY_CHARS)
for _ in range(Game.KEY_LENGTH))

@staticmethod
def _get_timestamp():
return int(time.time())

def create_player(self, code, exc=ValueError):
if self.started:
raise exc("Game has already started.")
Expand All @@ -51,15 +58,29 @@ def started(self):
return self.turn > 0

def start(self, exc=ValueError):
if len(self.players) < 2:
"""Populate the game board."""
log.info("starting the game...")
if self.started:
raise exc("The game has already started.")
elif len(self.players) < 2:
raise exc("At least 2 players are required.")
if self.turn == 0:
self.advance()
else:
self.board = Board.randomize(self.players)
self.turn = 1

def advance(self):
def advance(self, exc=ValueError):
"""Start the next turn."""
log.info("starting the next turn...")
if not self.started:
raise exc("The game has not started.")

# End every players turn
for player in self.players:
player.turn.done = True

# TODO: update the board

# Start the next turn
self.turn += 1
for player in self.players:
if player.turns.current:
player.turns.current.done = True
player.turns.append(Turn())
player.turn.done = False
4 changes: 2 additions & 2 deletions gridcommand/domain/player.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Classes representing players in a game."""

from ..common import logger
from .turn import Turns
from .turn import Turn


log = logger(__name__)
Expand All @@ -15,7 +15,7 @@ def __init__(self, color, code=''):
super().__init__()
self.color = color
self.code = code
self.turns = Turns()
self.turn = Turn()

def __repr__(self):
return "<player: {}>".format(self.color)
Expand Down
29 changes: 3 additions & 26 deletions gridcommand/domain/turn.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,9 @@ class Turn:

"""An individual turn for a player."""

def __init__(self):
super().__init__()
def __init__(self, done=False):
self.moves = Moves()
self.done = False
self.done = done

def __repr__(self):
return "<turn>"


class Turns(list):

"""A list of turns in a game for each player."""

def __repr__(self):
return "<{} turn{}>".format(len(self), "" if len(self) == 1 else "s")

@property
def current(self):
"""Get the most recent turn."""
try:
return self[-1]
except IndexError:
return None

def find(self, number, exc=ValueError):
try:
return self[number - 1]
except IndexError:
raise exc("The turn '{}' does not exist.".format(number))
return "<turn: {}done>".format("" if self.done else "not ")
22 changes: 15 additions & 7 deletions gridcommand/routes/formatters.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Formats domain objects for route responses."""

from collections import OrderedDict

from flask import url_for

from .base import Formatter
Expand All @@ -19,6 +21,7 @@ def format_single(self, game):
players_url = url_for('.players_list', **kwargs)
start_url = url_for('.games_start', **kwargs)
return {'uri': game_url,
'stamp': game.time,
'players': players_url,
'start': start_url,
'turn': game.turn}
Expand All @@ -33,23 +36,27 @@ class PlayerFormatter(Formatter):
"""Serializes players into dictionaries."""

def format_single(self, player, game, auth):
data = {'turn': len(player.turns)}
data = OrderedDict()
kwargs = dict(_external=True, key=game.key, color=player.color)
if auth:
kwargs.update(code=player.code)
player_url = url_for('.players_detail', **kwargs)
turns_url = url_for('.turns_list', **kwargs)
data['turns'] = turns_url
else:
player_url = url_for('.players_detail', **kwargs)
data['uri'] = player_url
data['uri'] = url_for('.players_detail', **kwargs)
data['turns'] = url_for('.turns_list', **kwargs)
return data

def format_multiple(self, players, game):
return [url_for('.players_detail', _external=True,
key=game.key, color=player.color) for player in players]


class BoardFormatter(Formatter):

def format_single(self, board):
# TODO: format board
print(board)
return {}


class TurnFormatter(Formatter):

"""Serializes turns into dictionaries."""
Expand Down Expand Up @@ -87,5 +94,6 @@ def format_multiple(self, moves, game, player):

game_formatter = GameFormatter()
player_formatter = PlayerFormatter()
board_formatter = BoardFormatter()
turn_formatter = TurnFormatter()
move_formatter = MoveFormatter()
14 changes: 14 additions & 0 deletions gridcommand/routes/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
from . import app
from .root import ROOT_URL
from .formatters import game_formatter as formatter
from .formatters import board_formatter


GAMES_LIST_URL = ROOT_URL + "/games/"
GAMES_DETAIL_URL = GAMES_LIST_URL + "<string:key>"
GAMES_START_URL = GAMES_DETAIL_URL + "/start"
GAMES_BOARD_URL = GAMES_DETAIL_URL + "/board"


@app.route(GAMES_LIST_URL, methods=['GET', 'POST'])
Expand Down Expand Up @@ -56,3 +58,15 @@ def games_start(key):
assert None

return {'started': game.started}


@app.route(GAMES_BOARD_URL, methods=['GET'])
@board_formatter.single
def games_board(key):
"""Get the game board."""
if request.method == 'GET':
board = app.service.get_board(key)
return board

else: # pragma: no cover
assert None
12 changes: 10 additions & 2 deletions gridcommand/routes/turn.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from flask import request
from flask.ext.api import exceptions # pylint: disable=E0611,F0401

from ..domain import Turn

from . import app
from .player import PLAYERS_DETAIL_URL
from .formatters import turn_formatter as formatter
Expand All @@ -22,7 +24,8 @@ def turns_list(key, color):
player.authenticate(code, exc=exceptions.AuthenticationFailed)

if request.method == 'GET':
return formatter.format_multiple(player.turns, game, player)
turns = [Turn() for count in range(game.turn)]
return formatter.format_multiple(turns, game, player)

else: # pragma: no cover
assert None
Expand All @@ -37,7 +40,12 @@ def turns_detail(key, color, number):
player.authenticate(code, exc=exceptions.AuthenticationFailed)

if request.method == 'GET':
turn = player.turns.find(number, exc=exceptions.NotFound)
if 1 >= number < game.turn:
turn = Turn(done=True)
elif number == game.turn:
turn = player.turn
else:
raise exceptions.NotFound
return formatter.format_single(turn, game, player, number)

else: # pragma: no cover
Expand Down
12 changes: 10 additions & 2 deletions gridcommand/services/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ def __init__(self, game_store, **kwargs):
super().__init__(**kwargs)
self.game_store = game_store

def create_game(self, key=None):
game = Game(key=key)
def create_game(self, key=None, timestamp=None):
game = Game(key=key, timestamp=timestamp)
self.game_store.create(game)
return game

Expand All @@ -37,6 +37,14 @@ def start_game(self, game):
game.start(exc=self.exceptions.permission_denied)
self.game_store.update(game)

def get_board(self, key):
game = self.find_game(key)
if game.board is None:
msg = "The game has not started."
raise self.exceptions.not_found(msg)
else:
return game.board

def create_move(self, game, turn, begin, end, count):
move = turn.moves.set(begin, end, count)
self.game_store.update(game)
Expand Down
Loading

0 comments on commit 127b955

Please sign in to comment.