Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
SHELL := /usr/bin/env bash
.DEFAULT_GOAL := help
.PHONY: clean requirements


help:
@echo ' make help show this help information'
@echo ' make clean.card_lib remove any artifacts or compiled files from the card_lib project'
@echo ' make requirements.card_lib install python requirements for the card_lib project and tests'
@echo ' make test.card_lib run unit tests for the card_lib project'
@echo ' make clean.game_server kill the game_server container and remove it, as well as any artifacts or compiled files'
@echo ' make build.game_server build the game_server docker container'
@echo ' make run.game_server run the game_server container'


### General

clean: clean.game_server clean.card_lib

requirements: requirements.game_server requirements.card_lib

### Make targets for the card_lib

clean.card_lib:
find card_lib -name '*pyc' |xargs -I {} rm {}

requirements.card_lib:
pip install -r requirements/test.txt

test.card_lib:
pytest card_lib

### Make targets for the game_server

clean.game_server:
docker kill game_server || true
docker rm game_server || true
docker rmi game_server || true
find game_server -name '*pyc' |xargs -I {} rm {}

requirements.game_server:
pip install -r requirements/game_server.txt
pip install -r requirements/test.txt

test.game_server:
pytest game_server

build.game_server:
docker build -t game_server -f docker/game_server.Dockerfile .

run.game_server:
docker run --name game_server -p 8888:8888 --rm game_server
14 changes: 0 additions & 14 deletions card_lib/Makefile

This file was deleted.

21 changes: 21 additions & 0 deletions docker/game_server.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM ubuntu:16.04

RUN apt-get update \
&& apt-get install -y make python3-pip python3.5

RUN mkdir /game_server

COPY game_server/* /game_server/
COPY requirements/* /game_server/requirements/
COPY Makefile /game_server/

EXPOSE 8888

# relink python3 and pip3 to common python aliases for convenience
RUN ln -sf /usr/bin/python3.5 /usr/bin/python \
&& ln -s /usr/bin/pip3 /usr/bin/pip

WORKDIR /game_server
RUN make requirements.game_server

CMD ["make", "help"]
Empty file added game_server/__init__.py
Empty file.
87 changes: 87 additions & 0 deletions game_server/game.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
""" components of a card game, from the perspective of the game server """

import json
import uuid
import threading


class PlayerID(object):
"""
Representation of a player (client) in a card game.

This is purely the the reference to a remote player used to identify
them amongst others in the lobby or game. It does not store what cards
they have nor control their plays.
"""

def __init__(self, id_num, host, port):
self.id_num = id_num
self.host = host
self.port = port

@property
def address(self):
"""
return the address of the player client, which will be used
to communicate with it
"""
return "{}:{}".format(self.host, self.port)


class Lobby(object):
"""
Representation of the 'lobby' phase of a game, in which players can join
but gameplay has not yet begun
"""

def __init__(self, min_players, max_players)
self.game = game
self.min_players = min_players
self.max_players = max_players
self.accepting = True
self.players = []

def register_player(self, player_request):
"""
given a valid player request, create and add a player to the lobby
if it is not already
"""
player_request = json.loads(player_request)
host = player_request['host']
port = player_request['port']
id_num = uuid.uuid4()
player = PlayerID(id_num, host, port)
if player not in self.players:
self.players.append(player)
else:
raise PlayerConflictException()

def _generate_status(self):
"""
create a json status message describing the current state of the
lobby. This will be sent out to all currently registered players
in the lobby
"""
return '{"accepting":"{}", "players":"{}"}'.format(
self.accepting,
[p.address() for p in self.players]
)

def is_at_quorum(self):
"""
determine if the lobby is at `quorum`- in other words, have enough
players registered with the lobby to begin a game
"""
return self.min_players <= len(self.players) < self.max_players

def serve(self, _socket):
"""
continually serve the game lobby, accepting incoming player requests
until the lobby has filled or timed out once quorum has been met
"""
while True:
pass


class PlayerConflictException(Exception):
pass
47 changes: 47 additions & 0 deletions game_server/game_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@

import socket
import sys
import json
import logging

from game import (
PlayerID,
PlayerConflictException
Lobby
)

logging.basicConfig()
LOGGER = logging.getLogger()
LOGGER.setLevel(logging.INFO)

def create_socket(host, port):
"""
create a socket object and bind it to a port. This will
be used to communicate between the various players within
a game
"""
LOG.debug('Creating a socket and binding to {} on {}'.format(
host, port
))
_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
_socket.bind((host, port))
except socket.error:
error_msg = 'Unable to bind socket to {} on {}'.format(
host, port
)
LOG.error(error_msg)
sys.exit(1)
LOG.debug('Successfully bound socket')
return _socket

def handle_player_request(connection):

def main():
# for now, using hard coded values
_socket = create_socket('localhost', 8080)
lobby = Lobby('go fish', 2, 5)
lobby.serve(_socket)

if __name__ == "__main__":
main()
Empty file added requirements/game_server.txt
Empty file.
File renamed without changes.