Skip to content
Snippets Groups Projects
Commit e286afe8 authored by Tessaris Sergio's avatar Tessaris Sergio
Browse files

major: new API

parent dcca1944
No related branches found
No related tags found
No related merge requests found
#!/usr/bin/env python
"""
Examples of the use of the EaterWorld class
"""
import random
from typing import Iterable
import sys
from wumpus import InformedPlayer
from wumpus.gridworld import Eater, EaterWorld, Food
class MyPlayer(InformedPlayer):
"""
Informed player demonstrating the use of the start episode method to inspect the world.
"""
def _say(self, text: str):
"""
docstring
"""
print(self.name + ' says: ' + text)
def start_episode(self, world: EaterWorld):
"""
Print the description of the world before starting.
"""
# keep track of the reward
self.reward = 0
self._say('Episode starting for player {}'.format(self.name))
# inspect the objects in the world
food_locations = []
eater_location = None
for o in world.objects:
if isinstance(o, Eater):
eater_location = (o.location.x, o.location.y)
elif isinstance(o, Food):
food_locations.append((o.location.x, o.location.y))
# get the list of blocks
block_locations = sorted((bl.x, bl.y) for bl in world.blocks)
# Print the description of the world
self._say('World size: {}x{}'.format(world.size.x, world.size.y))
self._say('Eater agent in {}'.format(eater_location))
self._say('Food in {}'.format(sorted(food_locations)))
self._say('Blocks in {}'.format(block_locations))
self._say('Available actions: {}'.format({a.name: a.value for a in Eater.Actions}))
def end_episode(self):
"""Method called at the when an episode is completed."""
self._say('Episode completed, my reward is {}'.format(self.reward))
# random player
def play(self, turn: int, percept: Eater.Percept, actions: Iterable[Eater.Actions]) -> Eater.Actions:
actions_lst = list(actions)
next_move = actions_lst[random.randint(0, len(actions) - 1)]
self._say('I see {}, my next move is {}'.format(percept, next_move.name))
return next_move
def feedback(self, action: Eater.Actions, reward: int, percept: Eater.Percept):
"""Receive in input the reward of the last action and the resulting state. The function is called right after the execution of the action."""
self._say('Moved to {} with reward {}'.format(percept.position, reward))
self.reward += reward
MAP_STR = """
################
# # # #
# # # #
# # #
# # # #
### ##
"""
def main(*args):
"""
Play a random EaterWorld episode using the default player
"""
player_class = MyPlayer
world = EaterWorld.random(MAP_STR)
player = player_class('Hungry.Monkey')
world.run_episode(player, horizon=20)
return 0
if __name__ == "__main__":
sys.exit(main(*sys.argv[1:]))
{"size": [5, 5], "block": [[1, 3]], "food": [[3, 0], [0, 0]], "eater": [1, 0]}
......@@ -2,64 +2,55 @@
# Examples demonstrating the use of the Wumpus package
import json
import random
import sys
import wumpus as wws
class MyPlayer(wws.UserPlayer):
"""Player demonstrating the use of the start episode method to inspect the world."""
class MyPlayer(wws.InformedPlayer, wws.UserPlayer):
"""Informed player demonstrating the use of the start episode method to inspect the world."""
def start_episode(self):
"""Print the description of the world and the agent before starting (if known)."""
if self.world is not None:
# I know the world
world_info = {k: [] for k in ('Hunter', 'Pits', 'Wumpus', 'Gold', 'Exits')}
world_info['Size'] = (self.world.size.x, self.world.size.y)
world_info['Blocks'] = [(c.x, c.y) for c in self.world.blocks]
def start_episode(self, world: wws.WumpusWorld):
"""Print the description of the world before starting."""
for obj in self.world.objects:
if isinstance(obj, wws.Hunter):
world_info['Hunter'].append((obj.location.x, obj.location.y))
elif isinstance(obj, wws.Pit):
world_info['Pits'].append((obj.location.x, obj.location.y))
elif isinstance(obj, wws.Wumpus):
world_info['Wumpus'].append((obj.location.x, obj.location.y))
elif isinstance(obj, wws.Exit):
world_info['Exits'].append((obj.location.x, obj.location.y))
elif isinstance(obj, wws.Gold):
world_info['Gold'].append((obj.location.x, obj.location.y))
world_info = {k: [] for k in ('Hunter', 'Pits', 'Wumpus', 'Gold', 'Exits')}
world_info['Size'] = (world.size.x, world.size.y)
world_info['Blocks'] = [(c.x, c.y) for c in world.blocks]
print('World details:')
for k in ('Size', 'Pits', 'Wumpus', 'Gold', 'Exits', 'Blocks'):
print(' {}: {}'.format(k, world_info.get(k, None)))
for obj in world.objects:
if isinstance(obj, wws.Hunter):
world_info['Hunter'].append((obj.location.x, obj.location.y))
elif isinstance(obj, wws.Pit):
world_info['Pits'].append((obj.location.x, obj.location.y))
elif isinstance(obj, wws.Wumpus):
world_info['Wumpus'].append((obj.location.x, obj.location.y))
elif isinstance(obj, wws.Exit):
world_info['Exits'].append((obj.location.x, obj.location.y))
elif isinstance(obj, wws.Gold):
world_info['Gold'].append((obj.location.x, obj.location.y))
if self.agent is not None and isinstance(self.agent, wws.Hunter):
print('Controlling hunter in position ({}, {}) with direction {}'.format(self.agent.location.x, self.agent.location.y, self.agent.orientation))
print('World details:')
for k in ('Size', 'Pits', 'Wumpus', 'Gold', 'Exits', 'Blocks'):
print(' {}: {}'.format(k, world_info.get(k, None)))
def play_classic(size: int = 0):
"""Play the classic version of the wumpus."""
# create the world
world = wws.WumpusWorld.classic(size=size if size > 3 else random.randint(4, 8))
# get the hunter agent
hunter = next(iter(o for o in world.objects if isinstance(o, wws.Hunter)), None)
# Run a player without any knowledge about the world
world.run_episode(hunter, wws.UserPlayer.player())
world.run_episode(wws.UserPlayer())
def play_classic_informed(size: int = 0):
"""Play the classic version of the wumpus with a player knowing the world and the agent."""
# create the world
world = wws.WumpusWorld.classic(size=size if size > 3 else random.randint(4, 8))
# get the hunter agent
hunter = next(iter(o for o in world.objects if isinstance(o, wws.Hunter)), None)
# Run a player with knowledge about the world
world.run_episode(hunter, MyPlayer.player(world=world, agent=hunter))
world.run_episode(MyPlayer())
WUMPUS_WORLD = '''
......@@ -76,29 +67,25 @@ WUMPUS_WORLD = '''
'''
def play_fixed(world_json: str = WUMPUS_WORLD):
def play_fixed_informed(world_json: str = WUMPUS_WORLD):
"""Play on a given world described in JSON format."""
# create the world
world = wws.WumpusWorld.from_JSON(json.loads(world_json))
# get the hunter agent
hunter = next(iter(o for o in world.objects if isinstance(o, wws.Hunter)), None)
world = wws.WumpusWorld.from_JSON(world_json)
# Run a player with knowledge about the world
world.run_episode(hunter, MyPlayer.player(world=world, agent=hunter))
world.run_episode(MyPlayer())
def real_deal(size: int = 0):
"""Play the classic version of the wumpus without being able to see the actual layout, that is as the actual software agent will do."""
# create the world
world = wws.WumpusWorld.classic(size=size if size > 3 else random.randint(4, 8))
# get the hunter agent
hunter = next(iter(o for o in world.objects if isinstance(o, wws.Hunter)), None)
# Run a player without any knowledge about the world
world.run_episode(hunter, wws.UserPlayer.player(), show=False)
world.run_episode(wws.UserPlayer(), show=False)
EXAMPLES = (play_classic, play_classic_informed, play_fixed, real_deal)
EXAMPLES = (play_classic, play_classic_informed, play_fixed_informed, real_deal)
def main(*args):
......
from wumpus.wumpus import WumpusWorld, Hunter, Wumpus, Pit, Gold, Exit
from wumpus.gridworld import Player, UserPlayer, RandomPlayer, Coordinate, coord
from wumpus.gridworld import Agent, Percept, InformedPlayer, UninformedPlayer, UserPlayer, RandomPlayer, Coordinate, coord
__version__ = '0.2.0'
This diff is collapsed.
from enum import Enum
import json
import random
from typing import Iterable, NamedTuple, Dict, Sequence, Tuple
import sys
from typing import Any, Iterable, NamedTuple, Dict, Sequence, Tuple
from .gridworld import Agent, WorldObject, GridWorld, Coordinate, coord, GridWorldException, UserPlayer
from .gridworld import Actions, Agent, WorldObject, GridWorld, Coordinate, coord, GridWorldException, Percept, UserPlayer
class WumpusWorldObject(WorldObject):
......@@ -39,7 +40,7 @@ class Exit(WumpusWorldObject):
class Hunter(Agent):
class Actions(Agent.Actions):
class Actions(Actions):
MOVE = 0
RIGHT = 1
LEFT = 2
......@@ -53,7 +54,7 @@ class Hunter(Agent):
E = (1, 0)
W = (-1, 0)
class Percept(NamedTuple):
class Percept(Percept, NamedTuple):
stench: bool
breeze: bool
bump: bool
......@@ -101,7 +102,7 @@ class Hunter(Agent):
"""Return true once the goal of the agent has been achieved."""
return self._done
def percept(self):
def percept(self) -> 'Hunter.Percept':
return self.Percept(
stench=self.stench,
breeze=self.breeze,
......@@ -246,14 +247,26 @@ class WumpusWorld(GridWorld):
return world
@classmethod
def from_JSON(cls, json_obj: Dict):
def random(cls, **kwargs):
"""
docstring
"""
size = kwargs.get('size', 4)
seed = kwargs.get('seed', None)
pitProb = kwargs.get('pitProb', .2)
return cls.classic(size=size, seed=seed, pitProb=pitProb)
@classmethod
def from_dict(cls, desc: Dict[str, Any]):
"""Create a wumpus world from a JSON object"""
def getCoord(lst: Sequence[int]) -> Coordinate:
return coord(lst[0], lst[1])
def coordLst(key: str) -> Iterable[Coordinate]:
data = json_obj.get(key, [])
data = desc.get(key, [])
if len(data) < 1:
return []
elif isinstance(data[0], Sequence):
......@@ -264,7 +277,7 @@ class WumpusWorld(GridWorld):
size = coordLst('size')[0]
blocks = coordLst('blocks')
hunters = json_obj.get('hunters', [])
hunters = desc.get('hunters', [])
pits = coordLst('pits')
wumpuses = coordLst('wumpuses')
exits = coordLst('exits')
......@@ -347,7 +360,7 @@ class WumpusWorld(GridWorld):
"""Return a exit if it's at the coordinate or None."""
return next(iter(self._objAt(Exit, pos)), None)
def to_JSON(self) -> Dict:
def to_dict(self) -> Dict[str, Any]:
"""Return a JSON serialisable object with the description of the world."""
def coord_tuple(c: Coordinate) -> Tuple[int]:
......@@ -452,12 +465,11 @@ if __name__ == "__main__":
])
# world = WumpusWorld.randomWorld(size=7, blockProb=0.1, world_desc=WORLD_MAP)
world = WumpusWorld.classic(size=7)
hunter = next(iter(o for o in world.objects if isinstance(o, Hunter)), None)
world.run_episode(hunter, UserPlayer.player())
world.run_episode(UserPlayer())
print(json.dumps(world.to_JSON()))
world.to_JSON(sys.stdout)
print()
JSON_STRING = '{"size": [7, 7], "hunters": [[0, 0, "E"]], "pits": [[4, 0], [3, 1], [2, 2], [6, 2], [4, 4], [3, 5], [4, 6], [5, 6]], "wumpuses": [[1, 2]], "exits": [[0, 0]], "golds": [[6, 3]]}'
world = WumpusWorld.from_JSON(json.loads(JSON_STRING))
print(world)
print(json.dumps(world.to_JSON()))
print(world.to_JSONs())
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment