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

Ally move filter #100

Merged
merged 3 commits into from
Oct 21, 2022
Merged
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
103 changes: 102 additions & 1 deletion src/baseline_bots/bots/smart_order_accepter_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from diplomacy import Message
from stance_vector import ActionBasedStance, ScoreBasedStance
import random
import numpy as np


from baseline_bots.bots.dipnet.dipnet_bot import DipnetBot
Expand Down Expand Up @@ -56,6 +57,8 @@ def __init__(self, power_name, game) -> None:
self.allies_influence = set()
self.orders = None
self.my_influence = set()
self.ally_threshold = 2.0
self.enemy_threshold = 1.0

def gen_pos_stance_messages(
self, msgs_data: MessagesData, orders_list: List[str]
Expand Down Expand Up @@ -387,6 +390,102 @@ def generate_support_proposals(self, comms_obj: MessagesData) -> Dict[str, str]:
final_messages[recipient] = str(suggested_proposals)
comms_obj.add_message(recipient, str(suggested_proposals))
return final_messages

def is_order_aggressive_to_powers(self, order: str, powers: List[str]):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great to see a test for this function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a test for the whole process. Will later add the test case!

"""
check if the order is aggressive by
wwongkamjan marked this conversation as resolved.
Show resolved Hide resolved
1. to attack allies unit
wwongkamjan marked this conversation as resolved.
Show resolved Hide resolved
2. to move to allies' SC
3. support attack allies unit
4. support move to allies' SC

:param order: an order as string, e.g. "A BUD S F TRI"
:param powers: powers that we want to check if a bot is having aggressive move to
:return: Boolean
wwongkamjan marked this conversation as resolved.
Show resolved Hide resolved

"""
order_token = get_order_tokens(order)
if order_token[0][0] == "A" or order_token[0][0] == "F":
# for 1 and 2
wwongkamjan marked this conversation as resolved.
Show resolved Hide resolved
if order_token[1][0] == "-":
# get location - add order_token[0] ('A' or 'F') at front to check if it collides with other powers' units
order_unit = order_token[0][0] + order_token[1][1:]
for power in powers:
if self.power_name != power:
# if the order is to attack allies' units
if order_unit in self.game.powers[power].units:
return True
# if the order is a move to allies' SC
if order_token[1][2:] in self.game.powers[power].centers:
return True
# for 3 and 4
if order_token[1][0] == "S":
# if support hold
if len(order_token) == 3: # ['A BUD', 'S', 'A VIE']
return False
order_unit = order_token[2][0] + order_token[3][1:]
for power in powers:
if self.power_name != power:
# if the order is to attack allies' units
if order_unit in self.game.powers[power].units:
return True
# if the order is a move to allies' SC
if order_token[3][2:] in self.game.powers[power].centers:
return True
return False

@gen.coroutine
def get_non_aggressive_order(self, order: str, powers: List[str]):
wwongkamjan marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would also like to see a test for this function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that can be added too.

"""
return a non-aggressive order with other options in dipnet beam order, if none left, support its own unit. if none around, support self hold.
wwongkamjan marked this conversation as resolved.
Show resolved Hide resolved

:param order: an order as string, e.g. "A BUD S F TRI"
:param powers: powers that we want to check if a bot is having aggressive move to
wwongkamjan marked this conversation as resolved.
Show resolved Hide resolved
:return: order

"""
order_token = get_order_tokens(order)
unit = order_token[0]
loc_unit = unit[2:]
list_order, prob_order = yield self.brain.get_beam_orders(self.game, self.power_name)

if len(list_order)>1:
for i in range(1,len(list_order)):
dipnet_order = list_order[i]
for candidate_order in dipnet_order:
if unit in candidate_order and not self.is_order_aggressive_to_powers(candidate_order, powers):
return candidate_order

# if none in dipnet beam orders
for current_order in self.orders.get_list_of_orders():
if current_order != order and not self.is_order_aggressive_to_powers(current_order, powers) and current_order in self.game.get_all_possible_orders()[loc_unit]:
return unit + ' S ' + current_order

return unit + ' H'

@gen.coroutine
def replace_aggressive_order_to_allies(self):
"""
replace aggressive orders with non-aggressive orders (in-place replace self.orders)
wwongkamjan marked this conversation as resolved.
Show resolved Hide resolved

:return: nothing
wwongkamjan marked this conversation as resolved.
Show resolved Hide resolved
"""
ally = [power for power in self.game.map.powers if power!=self.power_name and self.stance.stance[self.power_name][power] >= self.ally_threshold]

if not len(ally):
return
final_orders = []
for order in self.orders.get_list_of_orders():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments needed

if self.is_order_aggressive_to_powers(order, ally):
new_order = yield from self.get_non_aggressive_order(order, ally)
else:
new_order = order
final_orders.append(new_order)

orders_data = OrdersData()
orders_data.add_orders(final_orders)
self.orders = orders_data


@gen.coroutine
def __call__(self, rcvd_messages: List[Tuple[int, Message]]):
Expand Down Expand Up @@ -418,9 +517,11 @@ def __call__(self, rcvd_messages: List[Tuple[int, Message]]):
# add orders
orders_data = OrdersData()
orders_data.add_orders(best_orders)

self.orders = orders_data

# filter out aggressive orders to allies
yield self.replace_aggressive_order_to_allies()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would highly prefer a pattern in which orders are passed into and out of this function, e.g.

orders = yield self.replace_aggressive_order_to_allies(best_orders)


# generate messages for FCT sharing info orders
msgs_data = self.gen_messages(orders_data.get_list_of_orders())
self.respond_to_invalid_orders(invalid_proposal_orders, msgs_data)
Expand Down
29 changes: 29 additions & 0 deletions tests/bot_tests/SOA_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def test(self):
# start_io_loop(self.test_parse_proposals)
# start_io_loop(self.test_get_best_orders)
# start_io_loop(self.test_gen_pos_stance_messages)
start_io_loop(self.test_ally_move_filter)

@gen.coroutine
def test_auxilary_functions(self):
Expand Down Expand Up @@ -148,6 +149,34 @@ def test_action_stance(self):
print('finish test_stance')
stop_io_loop()

@gen.coroutine
def test_ally_move_filter(self):
# assume that stance is correct using score-based
game = Game()
soa_bot = SmartOrderAccepterBot('FRANCE', game)
soa_bot.ally_threshold = 1.0
bot_instances = [RandomProposerBot_AsyncBot('ENGLAND', game), RandomProposerBot_AsyncBot('GERMANY', game), soa_bot]
game_play = GamePlay(game, bot_instances, 3, True)
game_play.game.set_centers('ENGLAND', ['LON'], reset=True)
game_play.game.set_centers('GERMANY', ['MUN', 'KIE', 'BER','BEL'])
game_play.game.set_centers(soa_bot.power_name, ['PAR','BRE', 'MAR'])
game_play.game.set_orders('FRANCE', ['A MAR - BUR', 'A PAR - PIC', 'F BRE H'])
game_play.game.set_orders('ENGLAND', ['A LVP - WAL', 'F EDI - NTH', 'F LON - ENG'])
game_play.game.process()
orders = ['F BRE - ENG', 'A PIC - BEL', 'A BUR - PIC']
orders_data = OrdersData()
orders_data.add_orders(orders)
soa_bot.orders = orders_data

print("aggressive order: ", orders)
soa_bot_stance = soa_bot.stance.get_stance()[soa_bot.power_name]
print('soa stance', {k: v for k,v in soa_bot_stance.items() if v >= soa_bot.ally_threshold})
yield soa_bot.replace_aggressive_order_to_allies()
print("remove non-aggressive", soa_bot.orders.get_list_of_orders())

print('finish test ally move filter')
stop_io_loop()

@gen.coroutine
def test_parse_proposals(self):
# proposal messages -> proposal dict {power_name: a list of proposal orders}
Expand Down