Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolves #115 2 #118

Open
wants to merge 2 commits into
base: v2
Choose a base branch
from
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
36 changes: 36 additions & 0 deletions docs/pysc2_usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# PySC2 usage in URNAI

## Actions in URNAI vs Actions in PySC2

In PySC2 you would normally call an action in the following manner:
`actions.X.F`. Where `X` is the action function set, such as `RAW_FUNCTIONS`
or `FUNCTIONS`, and `F` is the action function you are calling,
such as `no_op` or `Move_pt`.

But in URNAI, due to encapsulation, the call is done in the following manner:
`X[F].run()`. Where `X` is a dict containing classes for each of the action functions
in PySC2, and `F` is a string with the name of the action function you are calling.
The dictionaries mentioned above are stored in the `urnai/sc2/actions/sc2_actions.py`, and can
be imported such as in the example below:

```python
from urnai.sc2 import raw_functions_classes as sc2_actions
```

### Examples

```python
# PySC2
actions.RAW_FUNCTIONS.no_op()
actions.RAW_FUNCTIONS.Move_pt('now', unit.tag, [new_army_x, new_army_y])

# URNAI
sc2_actions["no_op"].run()
sc2_actions["Move_pt"].run('now', unit.tag,[new_army_x, new_army_y])
```

### Why?

URNAI chooses to represent actions as classes so they can be better organized and tested.
Therefore, this encapsulation, which transforms each PySC2 action into a class, contributes
to all environments being done under a single system, something that is desired.
4 changes: 0 additions & 4 deletions tests/units/actions/test_action_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,8 @@ def test_abstract_methods(self):

# WHEN
run_return = fake_action.run()
check_return = fake_action.check("observation")
is_complete_return = fake_action.is_complete

# THEN
assert fake_action.__id__ is None
assert isinstance(ActionBase, ABCMeta)
assert run_return is None
assert check_return is None
assert is_complete_return is None
29 changes: 29 additions & 0 deletions tests/units/actions/test_action_base_strict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import unittest
from abc import ABCMeta

from urnai.actions.action_base_strict import ActionBaseStrict


class FakeActionStrict(ActionBaseStrict):
ActionBaseStrict.__abstractmethods__ = set()
__id__ = None
...

class TestActionBase(unittest.TestCase):

def test_abstract_methods(self):

# GIVEN
fake_action = FakeActionStrict()

# WHEN
run_return = fake_action.run()
check_return = fake_action.check("observation")
is_complete_return = fake_action.is_complete

# THEN
assert fake_action.__id__ is None
assert isinstance(ActionBaseStrict, ABCMeta)
assert run_return is None
assert check_return is None
assert is_complete_return is None
8 changes: 4 additions & 4 deletions tests/units/sc2/actions/test_sc2_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from pysc2.lib import actions

from urnai.sc2.actions.sc2_action import SC2Action
from urnai.sc2.actions.sc2_actions import raw_functions_classes as sc2_actions

_BUILD_REFINERY = actions.RAW_FUNCTIONS.Build_Refinery_pt
_NO_OP = actions.FUNCTIONS.no_op
Expand All @@ -11,9 +11,9 @@ class TestSC2Action(unittest.TestCase):

def test_run(self):

run_no_op = SC2Action.run(_NO_OP)
run_build_refinery = SC2Action.run(_BUILD_REFINERY, 'now', 0)
run_no_op = sc2_actions["no_op"].run()
run_build_refinery = sc2_actions["Build_Refinery_pt"].run('now', 0)

self.assertEqual(run_no_op.function, _NO_OP.id)
self.assertEqual(run_no_op.arguments, [])

Expand Down
14 changes: 2 additions & 12 deletions urnai/actions/action_base.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
from abc import ABC, abstractmethod
from typing import Any


class ActionBase(ABC):
__id__ = None

@abstractmethod
def run(self) -> None:
def run(*args) -> Any:
"""Executing the action"""
...

@abstractmethod
def check(self, obs) -> bool:
"""Returns whether the action can be executed or not"""
...

@property
@abstractmethod
def is_complete(self) -> bool:
"""Returns whether the action has finished or not"""
...
22 changes: 22 additions & 0 deletions urnai/actions/action_base_strict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from abc import abstractmethod

from urnai.actions.action_base import ActionBase


class ActionBaseStrict(ActionBase):

@abstractmethod
def run(*args):
"""Executing the action"""
...

@abstractmethod
def check(self, obs) -> bool:
"""Returns whether the action can be executed or not"""
...

@property
@abstractmethod
def is_complete(self) -> bool:
"""Returns whether the action has finished or not"""
...
6 changes: 6 additions & 0 deletions urnai/sc2/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from urnai.sc2.actions import sc2_actions

functions_classes = sc2_actions.functions_classes
raw_functions_classes = sc2_actions.raw_functions_classes

__all__ = ['functions_classes', 'raw_functions_classes']
9 changes: 0 additions & 9 deletions urnai/sc2/actions/sc2_action.py

This file was deleted.

29 changes: 29 additions & 0 deletions urnai/sc2/actions/sc2_actions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from pysc2.lib import actions

from urnai.actions.action_base import ActionBase

"""
This file creates dicts which store classes for each of the actions in PySC2.
"""

def _function_classes(functions):

@classmethod
def run_method(cls, *args) -> actions.FunctionCall:
return cls.my_action_function(*args)

function_class_dict = {}

for sc2_action in functions:

function_class_dict[sc2_action.name] = type(sc2_action.name, (ActionBase,), {

"my_action_function": sc2_action,
"run": run_method,

})

return function_class_dict

functions_classes = _function_classes(actions.FUNCTIONS)
raw_functions_classes = _function_classes(actions.RAW_FUNCTIONS)
Loading