Skip to content

Commit

Permalink
Merged commits up to '8f0b8e99'
Browse files Browse the repository at this point in the history
- Added DEBIAN_FRONTEND=noninteractive to deploy-web and deploy-webdip
- Preventing installation of h5py 2.10.0
- Standardized set initialization from set([]) to set()
- WebDip - Only returning stuck_in_local_optimum if power_name is stuck and doesn't have the most SC
- WebDip - Preventing 2 retreats to the same location
  • Loading branch information
ppaquette committed Sep 17, 2019
1 parent 16e0c92 commit 3c7ed06
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 18 deletions.
1 change: 1 addition & 0 deletions diplomacy_research/containers/deploy-web/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ENV LANG=en_CA.UTF-8
ENV PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
ENV PYTHONUNBUFFERED=1
ENV WORKING_DIR=/work_dir
ENV DEBIAN_FRONTEND=noninteractive

ARG GITHUB_TOKEN
ARG REPO
Expand Down
1 change: 1 addition & 0 deletions diplomacy_research/containers/deploy-webdip/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ENV LANG=en_CA.UTF-8
ENV PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
ENV PYTHONUNBUFFERED=1
ENV WORKING_DIR=/work_dir
ENV DEBIAN_FRONTEND=noninteractive

ARG GITHUB_TOKEN
ARG REPO
Expand Down
4 changes: 2 additions & 2 deletions diplomacy_research/models/state_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,8 +510,8 @@ def get_orderable_locs_for_powers(state_proto, powers, shuffled=False):

# Detecting orderable locations for each top victor
# Not storing coasts for orderable locations
all_orderable_locs = set([])
orderable_locs = {power_name: set([]) for power_name in powers}
all_orderable_locs = set()
orderable_locs = {power_name: set() for power_name in powers}
for power_name in powers:

# Adding build locations
Expand Down
61 changes: 47 additions & 14 deletions diplomacy_research/scripts/launch_bot_webdip.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,20 +128,22 @@ def submit_orders(self, api, game_id, country_id):
return

# Querying the model for object
player = self.get_player(game)
player = self.get_player(game, power_name)
if player is None:
LOGGER.error('Unable to retrieve the player for map %s.', game.map_name)
return
orders = yield player.get_orders(game, power_name)
orders = self.adjust_orders(orders, game, power_name)

# Submitting orders
success = yield api.set_orders(game, power_name, orders, wait=False)
if not success:
self.add_error(game_id, country_id)

def get_player(self, game):
def get_player(self, game, power_name):
""" Returns the player to query the orders
:param game: A game instance
:param power_name: The name of the power we are playing
:type game: diplomacy.Game
:return: A player object to query the orders
"""
Expand All @@ -150,7 +152,7 @@ def get_player(self, game):
if game.map_name == 'standard':
if game.get_current_phase() in ('S1901M', 'F1901M'): # To get a diverse set of openings
return self.players['beam_0.50']
if self.game_stuck_in_local_optimum(game): # In case the bot gets stuck
if self.game_stuck_in_local_optimum(game, power_name): # In case the bot gets stuck
return self.players['beam_0.50']
return self.players['greedy'] # Greedy by default

Expand All @@ -166,14 +168,15 @@ def get_player(self, game):
return None

@staticmethod
def game_stuck_in_local_optimum(game):
def game_stuck_in_local_optimum(game, power_name):
""" Determines if the bots are stuck in a local optimum, to avoid endless loops
:param game: A game instance
:param power_name: The name of the power we are playing
:type game: diplomacy.Game
:return: A boolean that indicates if a local optimum has been detected.
"""
# 1) A local optimum can only be detected on the standard map
if game.map_name != 'standard':
# 1) A local optimum can only be detected on the standard map for a valid power
if game.map_name != 'standard' or power_name not in game.powers:
return False

# 2) A local optimum can only happen if a power has 13 or more supply centers
Expand All @@ -184,6 +187,10 @@ def game_stuck_in_local_optimum(game):
if game.get_current_phase() == 'COMPLETED':
return False

# 4) A local optimum can not happen if the power has the most supply centers
if len(game.powers[power_name].centers) == max([len(power.centers) for power in game.powers.values()]):
return False

# Building a list of units at the start of the last phase of each year for each power
# e.g. W1901A, W1902A, S1903M if the current phase is S1903M
# We can use this to detect a power that has not been able to move its units in the last 'x' years
Expand All @@ -199,22 +206,47 @@ def game_stuck_in_local_optimum(game):
units[current_year] = {power_name: set(game.get_units(power_name)) for power_name in game.powers}

# Checking if powers have not moved unit in the last 3 years
nb_powers_stuck = 0
for power_name in game.powers:
units_yr_0 = units.get(current_year, {}).get(power_name, set([]))
units_yr_1 = units.get(current_year - 1, {}).get(power_name, set([]))
units_yr_2 = units.get(current_year - 2, {}).get(power_name, set([]))
powers_stuck = set()
for pow_name in game.powers:
units_yr_0 = units.get(current_year, {}).get(pow_name, set())
units_yr_1 = units.get(current_year - 1, {}).get(pow_name, set())
units_yr_2 = units.get(current_year - 2, {}).get(pow_name, set())

# Power can only be stuck if it still has units on the board
if not units_yr_0:
continue

# Power is stuck if (yr_0 == yr_1 and yr_1 == yr_2)
if units_yr_0 == units_yr_1 == units_yr_2:
nb_powers_stuck += 1
powers_stuck.add(pow_name)

# 4) A local optimum can only happen if 2 or more powers are stuck (same units in the last 3 years)
return bool(nb_powers_stuck >= 2)
# 5) A local optimum can only happen if 2 or more powers are stuck (same units in the last 3 years)
return bool(len(powers_stuck) >= 2 and power_name in powers_stuck)

@staticmethod
def adjust_orders(orders, game, power_name):
""" Performs manual order adjustments to remove edge case scenarios
:param orders: The list of orders to submit
:param game: A game instance
:param power_name: The name of the power we are playing
:type game: diplomacy.Game
:return: The adjusted list of orders
"""
del game, power_name # Unused args
adjusted_orders = []
retreat_locs = set()

# 1) Only allow one retreat to a given location, convert the others to disband
for order in orders:
if ' R ' in order:
unit, dest = order.split(' R ')
if dest in retreat_locs:
order = '%s D' % unit
retreat_locs.add(dest)
adjusted_orders.append(order)

# Returning adjusted orders
return adjusted_orders

def add_error(self, game_id, country_id):
""" Marks a request as a failure, to throttle if too many failures are detected in a period of time
Expand Down Expand Up @@ -258,6 +290,7 @@ def main():
io_loop.run_sync(bot.run)
except KeyboardInterrupt:
LOGGER.error('Bot interrupted.')
break
except Exception as exc: # pylint: disable=broad-except
print('--------------------------------------------------------------------------------')
LOGGER.error(exc)
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ diplomacy==1.1.0
grpcio==1.15.0
grpcio-tools==1.15.0
gym>=0.9.6
h5py>=2.8.0
h5py>=2.8.0,<2.10.0
html5lib
hiredis
numpy>=1.15,<1.16
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def get_module_exts():
'grpcio==1.15.0',
'grpcio-tools==1.15.0',
'gym>=0.9.6',
'h5py>=2.8.0',
'h5py>=2.8.0,<2.10.0',
'html5lib',
'hiredis',
'numpy>=1.15,<1.16',
Expand Down

0 comments on commit 3c7ed06

Please sign in to comment.