Skip to content

Commit

Permalink
Merge branch 'release-0.0.7'
Browse files Browse the repository at this point in the history
  • Loading branch information
nilp0inter committed Jul 11, 2015
2 parents 5708385 + 81cd648 commit 09f641e
Show file tree
Hide file tree
Showing 7 changed files with 325 additions and 161 deletions.
35 changes: 20 additions & 15 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,41 +61,46 @@ This package creates the command ``pyagar``.
Controls
~~~~~~~~

====== ============================================
Action Control
====== ============================================
Move Mouse (Relative to the center of the window)
Start Mouse (Left button)
Eject ``W`` key
Split ``Space`` key
====== ============================================
=========== ============================================
Action Control
=========== ============================================
Move Mouse (Relative to the center of the window)
Start Mouse (Left button)
Eject ``W`` key
Split ``Space`` key
Fullscreen ``F`` key
Zoom Mouse wheel
Exit ``ESC`` key
=========== ============================================


Play examples
-------------

Play setting a custom nick
~~~~~~~~~~~~~~~~~~~~~~~~~~
Just play
~~~~~~~~~

.. code-block:: bash
$ pyagar -n doge
$ pyagar play
Press the left mouse button to start.


Just watch the game
~~~~~~~~~~~~~~~~~~~

.. code-block:: bash
$ pyagar --spectate
$ pyagar spectate
Play automatically using the default bot
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Play automatically using a bot
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: bash
$ pyagar --auto
$ pyagar bot --type=EatWhenNoPredators
Other implementations
Expand Down
72 changes: 1 addition & 71 deletions pyagar/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import argparse
import asyncio
import pkg_resources
import sys

from pyagar.log import logger
from pyagar.client import Client
from pyagar.visual import Visualizer
from pyagar.control import EatWhenNoPredators, Escape, Closer, Greedy


LOOP = asyncio.get_event_loop()
NICK = "pyagar"
Expand Down Expand Up @@ -36,69 +32,3 @@ def run(self):
while True:
data = yield from self.messages.get()
logger.debug(data)


def main():
parser = argparse.ArgumentParser()

parser.add_argument("--no-visualize", action="store_true")
parser.add_argument("-n", "--nick", default=NICK)
parser.add_argument("--auto", action="store_true")
parser.add_argument(
"-d",
action="count",
dest="debug",
help=("Enable debug mode. "
"Use multiple times to increase the debug level."))
parser.add_argument("--spectate", action="store_true")
args = parser.parse_args()

client = Client(args.nick)

coros = [client.read()]

dsts = []

if not args.no_visualize:
visualizer = Visualizer(client, view_only=args.spectate or args.auto)
coros.append(visualizer.run())
dsts.append(visualizer)

if args.auto:
controller = EatWhenNoPredators(client)
coros.append(controller.run())
dsts.append(controller)

if args.debug > 0:
import logging
logger.setLevel(logging.DEBUG)

if args.debug > 1:
output = Output()
coros.append(output.run())
dsts.append(output)

if args.spectate:
coros.append(client.spectate())

coros.append(hub(client, *dsts))

logger.info("Starting pyagar!")
if VERSION:
logger.info("Version %s", VERSION)

LOOP.run_until_complete(client.connect())

game = asyncio.wait(coros, return_when=asyncio.FIRST_COMPLETED)
done, not_done = LOOP.run_until_complete(game)
for coro in done:
try:
res = coro.result()
except:
logger.exception("Exception running coroutine.")

logger.info("Bye!")


if __name__ == '__main__':
main()
2 changes: 1 addition & 1 deletion pyagar/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def read(self):
def move(self, x, y):
yield from self.connected.wait()
yield from self.ws.send(struct.pack("<BddI", 16, x, y, 0))
logger.debug("Move sent.")
logger.debug("Move sent (x=%s, y=%s)", x, y)

@asyncio.coroutine
def spectate(self):
Expand Down
149 changes: 149 additions & 0 deletions pyagar/cmdline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import argparse
import asyncio
import imp
import logging
import sys
import textwrap

from pyagar import LOOP, NICK, VERSION, hub
from pyagar.client import Client
from pyagar.log import logger
from pyagar.visual import Visualizer


def parser():
"""Generates the argument parser."""
parser = argparse.ArgumentParser()

# General options
parser.add_argument(
"--disable-hw",
action="store_true",
help="Disable hardware acceleration.")
parser.add_argument(
"-n",
"--nick",
default=NICK)
parser.add_argument(
"-d",
"--debug",
action="count",
dest="debug",
help=("Enable debug mode. "
"Use multiple times to increase the debug level."))

parser.add_argument('--version', action='version',
version='%(prog)s ' + VERSION)

# Subcommands
subparsers = parser.add_subparsers(dest="command")

# Play subcommand
play = subparsers.add_parser("play")

# Spectate subcommand
spectate = subparsers.add_parser("spectate")

# Bot subcommand
bot = subparsers.add_parser("bot")

group = bot.add_mutually_exclusive_group(required=True)
group.add_argument('--list-types', action='store_true')
group.add_argument('--type', action='store')
group.add_argument('--from-file', action='store')

return parser


def pyagar():
"""pyagar cli interface."""

args = parser().parse_args()
if args.command is None:
logger.error("No subcommand present. To play execute: 'pyagar play'")
sys.exit(1)

client = Client(args.nick)

coros = [client.read()]

dsts = []

visualizer = Visualizer(
client,
view_only=args.command != "play",
hardware=not args.disable_hw)
coros.append(visualizer.run())
dsts.append(visualizer)

if args.debug is not None:
logger.setLevel(logging.DEBUG)

if args.debug > 1:
from pyagar import Output
output = Output()
coros.append(output.run())
dsts.append(output)
else:
logger.setLevel(logging.INFO)

if args.command == "bot":
if args.list_types:
print("Available bot types:\n")
from pyagar.control import Controller
for c in Controller.__subclasses__():
doc = c.__doc__ if c.__doc__ else '**Not documented**'
dedented_text = textwrap.dedent(doc).strip()
name = ' * %s: ' % c.__name__
msg = textwrap.fill(
dedented_text,
initial_indent=name,
subsequent_indent=' ')
print(msg)
sys.exit(0)
elif args.type:
from pyagar import control
if not hasattr(control, args.type):
print("Unknown bot type")
sys.exit(1)
else:
bot = getattr(control, args.type)
if (not issubclass(bot, control.Controller) or
bot is control.Controller):
print("Invalid bot type.")
sys.exit(1)
else:
controller = bot(client)
coros.append(controller.run())
dsts.append(controller)
elif args.from_file:
from pyagar.control import Controller
module = imp.load_source('botmodule', args.from_file)
if (not hasattr(module, 'UserBot') or
not issubclass(module.UserBot, Controller)):
print("Invalid bot.")
else:
controller = module.UserBot(client)
coros.append(controller.run())
dsts.append(controller)

coros.append(hub(client, *dsts))

logger.info("Starting pyagar!")
if VERSION:
logger.info("Version %s", VERSION)

LOOP.run_until_complete(client.connect())

if args.command == "spectate":
LOOP.run_until_complete(client.spectate())

game = asyncio.wait(coros, return_when=asyncio.FIRST_COMPLETED)
done, not_done = LOOP.run_until_complete(game)
for coro in done:
try:
res = coro.result()
except:
logger.exception("Exception running coroutine.")

logger.info("Bye!")
19 changes: 13 additions & 6 deletions pyagar/control.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
"""
The documentation is important!
"""
import asyncio
from collections import namedtuple
import asyncio

from pyagar.log import logger
from pyagar.messages import Status, PlayerCell, ScreenAndCamera

Movement = namedtuple('Movement', ['x', 'y'])
Expand All @@ -18,6 +16,12 @@ def __init__(self, client):
self.alive = False
self.screen = None

def get_name(self):
if not hasattr(self, 'name'):
return self.__class__.__name__
else:
return self.name

def get_movement(self):
raise NotImplementedError()

Expand Down Expand Up @@ -61,6 +65,8 @@ def do_move(self):

@asyncio.coroutine
def run(self):
logger.info("Running bot '%s'", self.get_name())

while True:
data = yield from self.messages.get()
if isinstance(data, Status):
Expand Down Expand Up @@ -150,7 +156,8 @@ def get_movement(self):
return Movement(x=self.screen.x2 / 2, y=self.screen.y2 / 2)


class EatWhenNoPredators(Escape, Greedy, Center):
class EatWhenNoPredators(Escape, Greedy, Center, Controller):
"""Only eats when all visible cells are smaller then itself."""
escape = Escape.get_movement
eat = Greedy.get_movement
nothing_to_do = Center.get_movement
Expand Down

0 comments on commit 09f641e

Please sign in to comment.