Skip to content
This repository has been archived by the owner on Aug 7, 2024. It is now read-only.

Commit

Permalink
Merge 6bdb7ae into d4511aa
Browse files Browse the repository at this point in the history
  • Loading branch information
danalex97 authored Aug 31, 2017
2 parents d4511aa + 6bdb7ae commit 8d244e4
Show file tree
Hide file tree
Showing 40 changed files with 1,512 additions and 189 deletions.
2 changes: 0 additions & 2 deletions aimmo-game-creator/tests/test_worker_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
from json import dumps

from httmock import HTTMock

from worker_manager import WorkerManager


class ConcreteWorkerManager(WorkerManager):
def __init__(self, *args, **kwargs):
self.final_workers = set()
Expand Down
11 changes: 9 additions & 2 deletions aimmo-game/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
import flask
from flask_socketio import SocketIO

from simulation.turn_manager import state_provider
from simulation import map_generator
from simulation import custom_map

from simulation.turn_manager import state_provider
from simulation.avatar.avatar_manager import AvatarManager
from simulation.turn_manager import ConcurrentTurnManager
from simulation.worker_manager import WORKER_MANAGERS
Expand Down Expand Up @@ -69,7 +71,12 @@ def run_game(port):
settings = pickle.loads(os.environ['settings'])

api_url = os.environ.get('GAME_API_URL', 'http://localhost:8000/players/api/games/')
generator = getattr(map_generator, settings['GENERATOR'])(settings)
if hasattr(custom_map, settings['GENERATOR']):
generator = getattr(custom_map, settings['GENERATOR'])(settings)
else:
generator = getattr(map_generator, settings['GENERATOR'])(settings)

global player_manager
player_manager = AvatarManager()
game_state = generator.get_game_state(player_manager)

Expand Down
115 changes: 115 additions & 0 deletions aimmo-game/simulation/cell.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
from abc import ABCMeta, abstractmethod

from simulation.action import MoveAction
from simulation.location import Location

class CellContent(object):
__metaclass__ = ABCMeta

def __init__(self, sprite):
self.sprite = sprite

@abstractmethod
def is_habitable(self):
pass

@abstractmethod
def generates_score(self):
pass

def get_sprite(self):
return self.sprite

class Obstacle(CellContent):
def __init__(self, *args, **kwargs):
super(Obstacle, self).__init__(*args, **kwargs)

def is_habitable(self):
return False

def generates_score(self):
return False

class ScoreLocation(CellContent):
def __init__(self, *args, **kwargs):
super(ScoreLocation, self).__init__(*args, **kwargs)

def is_habitable(self):
return True

def generates_score(self):
return True

class Floor(CellContent):
def __init__(self, *args, **kwargs):
super(Floor, self).__init__(*args, **kwargs)

def is_habitable(self):
return True

def generates_score(self):
return False

class Cell(object):
"""
Any position on the world grid.
"""

def __init__(self, location, cell_content=Floor({}), partially_fogged=False):
self.location = location
self.cell_content = cell_content
self.avatar = None
self.pickup = None
self.partially_fogged = partially_fogged
self.actions = []
self.created = False

# Used to update the map features in the current view of the user (score points on pickups).
self.remove_from_scene = None
self.add_to_scene = None

def __repr__(self):
return 'Cell({} h={} s={} a={} p={} f{})'.format(
self.location, self.habitable, self.generates_score, self.avatar, self.pickup, self.partially_fogged)

def __eq__(self, other):
return self.location == other.location

def __ne__(self, other):
return not self == other

def __hash__(self):
return hash(self.location)

@property
def habitable(self):
return self.cell_content.is_habitable()

@property
def generates_score(self):
return self.cell_content.generates_score()

@property
def moves(self):
return [move for move in self.actions if isinstance(move, MoveAction)]

@property
def is_occupied(self):
return self.avatar is not None

def serialise(self):
if self.partially_fogged:
return {
'generates_score': self.generates_score,
'location': self.location.serialise(),
'partially_fogged': self.partially_fogged
}
else:
return {
'avatar': self.avatar.serialise() if self.avatar else None,
'generates_score': self.generates_score,
'habitable': self.habitable,
'location': self.location.serialise(),
'pickup': self.pickup.serialise() if self.pickup else None,
'partially_fogged': self.partially_fogged
}
183 changes: 183 additions & 0 deletions aimmo-game/simulation/custom_map.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import abc
import math

from simulation.levels.levels import LEVELS
from simulation.levels.completion_checks import COMPLETION_CHECKS
from simulation.levels.decoders import *

from pprint import pprint

from simulation.location import Location
from simulation.game_state import GameState
from simulation.world_map import WorldMap

from simulation.world_map import WorldMapStaticSpawnDecorator
from simulation.world_map import DEFAULT_LEVEL_SETTINGS
from simulation.world_map import Cell

import sys
current_module = sys.modules[__name__]

class BaseGenerator(object):
"""
A map generator that exposes a game state and a check for level completion.
API:
- contructor(setting)
- a set of basic settings that the map uses at generation
- see DEFAULT_LEVEL_SETTINGS in simulation.world_map
- get_game_state(avatar_manager)
- exposes a game state used by the turn manager daemon
- for details see GameState
- check_complete(game_state)
- function to check if a map is "complete"
- the turn manager runs the action for each avatar, then runs check_complete afterwards
@abstract
- get_map
- returns the generated map
"""

__metaclass__ = abc.ABCMeta

def __init__(self, settings):
self.settings = settings

def get_game_state(self, avatar_manager):
return GameState(self.get_map(), avatar_manager, self.check_complete)

def check_complete(self, game_state):
return False

@abc.abstractmethod
def get_map(self):
pass

class EmptyMapGenerator(BaseGenerator):
"""
Generates empty maps
- get_map_by_corners
- get_map - generates a map with center in (0, 0)
"""
def __init__(self, settings):
self.height = self.settings['START_HEIGHT']
self.width = self.settings['START_WIDTH']
self.settings = settings

def __init__(self, height, width, settings):
self.height = height
self.width = width
self.settings = settings

@classmethod
def get_map_by_corners(cls, settings, corners):
(min_x, max_x, min_y, max_y) = corners
grid = {}
for x in xrange(min_x, max_x + 1):
for y in xrange(min_y, max_y + 1):
location = Location(x, y)
grid[location] = Cell(location)
return WorldMap(grid, settings)

def get_map(self):
def get_corners(height, width):
max_x = int(math.floor(width / 2))
min_x = -(width - max_x - 1)
max_y = int(math.floor(height / 2))
min_y = -(height - max_y - 1)
return min_x, max_x, min_y, max_y

new_settings = DEFAULT_LEVEL_SETTINGS.copy()
new_settings.update(self.settings)

return EmptyMapGenerator.get_map_by_corners(self.settings, get_corners(self.height, self.width))

class BaseLevelGenerator(BaseGenerator):
"""
BaseGenerator with default settings.
"""
__metaclass__ = abc.ABCMeta

def __init__(self, *args, **kwargs):
super(BaseLevelGenerator, self).__init__(*args, **kwargs)
self.settings.update(DEFAULT_LEVEL_SETTINGS)

################################################################################

class JsonLevelGenerator(BaseLevelGenerator):
"""
Workflow:
- setup the metadata: map dimensions, etc.
- register the json that represents the map
- register the decoders that tranform the jsons into WorldMap objects
- decode the map applying the decoder to each of the jsons
All the levels can be found in json format in levels.LEVELS.
To register a level extend this class.
"""
def __init__(self, *args, **kwargs):
super(JsonLevelGenerator, self).__init__(*args, **kwargs)

def _setup_meta(self):
# Used so that the map dimension does not increase automatically
self.settings["TARGET_NUM_CELLS_PER_AVATAR"] = -1000

self.meta = None
# Finds the json with metaiformation
for element in self.json_map:
if element["code"] == "meta":
self.meta = element

if not self.meta is None:
# Sets the empty map to the dimensions of the given level
minX = - int((self.meta["rows"]) / 2)
maxX = int((self.meta["rows"] - 1) / 2) + 1
minY = -int((self.meta["cols"]) / 2)
maxY = int((self.meta["cols"] - 1) / 2) + 1

self.world_map = EmptyMapGenerator.get_map_by_corners(
self.settings,
(minY, maxY, minX, maxX))

def _register_json(self, json_map):
self.json_map = json_map
self.world_map = EmptyMapGenerator(15, 15, self.settings).get_map()

def _register_decoders(self):
self.decoders = DECODERS

def _json_decode_map(self):
def find_element_by_code(json, code):
for element in json:
if element["code"] == str(code):
yield element

for decoder in self.decoders:
for element in find_element_by_code(self.json_map, decoder.code):
decoder.decode(element, self.world_map)

def generate_level_class(level_nbr, LEVELS=LEVELS, COMPLETION_CHECKS=COMPLETION_CHECKS):
level_name = "Level" + str(level_nbr)
level_id = "level" + str(level_nbr)

def get_map_by_level(level_id):
def get_map(self):
self._register_json(LEVELS[level_id])

self._setup_meta()
self._register_decoders()
self._json_decode_map()

return self.world_map

return get_map

ret_class = type(level_name, (JsonLevelGenerator,), {
"get_map": get_map_by_level(level_id),
"check_complete": COMPLETION_CHECKS[level_id]
})

return ret_class

for cur_level in xrange(1, len(LEVELS) + 1):
gen_class = generate_level_class(cur_level)
setattr(current_module, gen_class.__name__, gen_class)
1 change: 0 additions & 1 deletion aimmo-game/simulation/game_state.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from simulation.avatar import fog_of_war


class GameState(object):
"""
Encapsulates the entire game state, including avatars, their code, and the world.
Expand Down
Empty file.
16 changes: 16 additions & 0 deletions aimmo-game/simulation/levels/completion_checks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
def check_complete(self, game_state):
try:
main_avatar = game_state.get_main_avatar()
except KeyError:
return False

return main_avatar.score > 1000

COMPLETION_CHECKS = {
"level1" : check_complete,
"level2" : check_complete,
"level3" : check_complete,
"level4" : check_complete,
"level5" : check_complete,
"level6" : check_complete
}
Loading

0 comments on commit 8d244e4

Please sign in to comment.