Skip to content
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
15 changes: 4 additions & 11 deletions contrib/ci_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,6 @@ def pretty_print_results(self, full=False, team=None, highlight=None, html_expor
table.add_column("# Losses")
table.add_column("Score")
table.add_column("ELO")
table.add_column("# Timeouts")
table.add_column("# Fatal Errors")

elo = dict(self.dbwrapper.get_elo())
Expand Down Expand Up @@ -669,7 +668,6 @@ def create_tables(self):
(
id INTEGER PRIMARY KEY,
player1 text, player2 text, result int, final_state text,
player1_num_timeouts int, player2_num_timeouts int,
player1_had_fatal_error bool, player2_had_fatal_error bool,
FOREIGN KEY(player1) REFERENCES players(name) ON DELETE CASCADE,
FOREIGN KEY(player2) REFERENCES players(name) ON DELETE CASCADE)
Expand Down Expand Up @@ -797,20 +795,17 @@ def add_gameresult(self, p1_name, p2_name, result, final_state, std, p1_out, p2_
return

final_state_str = json.dumps(final_state)
player1_num_timeouts, player2_num_timeouts = final_state['num_timeouts']

player1_had_fatal_error = len(final_state['fatal_errors'][0]) != 0
player2_had_fatal_error = len(final_state['fatal_errors'][1]) != 0

self.cursor.execute("""
INSERT INTO games
(player1, player2, result, final_state,
player1_num_timeouts, player2_num_timeouts,
player1_had_fatal_error, player2_had_fatal_error)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
VALUES (?, ?, ?, ?, ?, ?)
RETURNING id
""", [p1_name, p2_name, result, final_state_str,
player1_num_timeouts, player2_num_timeouts,
player1_had_fatal_error, player2_had_fatal_error])

game_id, = self.cursor.fetchone()
Expand Down Expand Up @@ -943,27 +938,25 @@ def get_errorcount(self, p1_name):
error_count, fatalerror_count : errorcount
"""
self.cursor.execute("""
SELECT sum(timeouts), sum(fatal_errors) FROM
SELECT sum(fatal_errors) FROM
(
SELECT
sum(player1_num_timeouts) AS timeouts,
sum(player1_had_fatal_error) AS fatal_errors
FROM games
WHERE player1 = :p1

UNION ALL

SELECT
sum(player2_num_timeouts) AS timeouts,
sum(player2_had_fatal_error) AS fatal_errors
FROM games
WHERE player2 = :p1
)
""",
dict(p1=p1_name))
timeouts, fatal_errorcount = self.cursor.fetchone()
fatal_errorcount = self.cursor.fetchone()

return timeouts, fatal_errorcount
return fatal_errorcount

def get_wins_losses(self, team=None):
""" Get all wins and losses combined in a table of
Expand Down
2 changes: 1 addition & 1 deletion contrib/test_ci_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def db_wrapper():
return wrapper

def make_simple_gameresult(p1, p2, result):
return [p1, p2, result, {'num_timeouts': [0, 0], 'fatal_errors': [[], []]}, ['', ''], ['', ''], ['', '']]
return [p1, p2, result, {'fatal_errors': [[], []]}, ['', ''], ['', ''], ['', '']]

"""Tests for the DB_Wrapper class."""

Expand Down
71 changes: 8 additions & 63 deletions pelita/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def controller_await(state, await_action='play_step'):
return False

def run_game(team_specs, *, layout_dict, max_rounds=300,
rng=None, allow_camping=False, error_limit=5, timeout_length=TIMEOUT_SECS,
rng=None, allow_camping=False, timeout_length=TIMEOUT_SECS,
initial_timeout_length=INITIAL_TIMEOUT_SECS,
viewers=None, store_output=False,
team_names=(None, None), team_infos=(None, None),
Expand Down Expand Up @@ -156,17 +156,10 @@ def run_game(team_specs, *, layout_dict, max_rounds=300,
rng : random.Random | int | None
random number generator or a seed used to initialize a new one.

error_limit : int
The limit of non fatal errors to reach for a team before the
game is over and the team is disqualified. Non fatal errors are
timeouts and returning an illegal move. Fatal errors are raising
Exceptions. An error_limit of 0 will disable the limit.
Default: 5.

timeout_length : int or float
Time in seconds to wait for the move function (or for the remote
client) to return. After timeout_length seconds are elapsed a
non-fatal error is recorded for the team.
fatal error is recorded for the team.

initial_timeout_length : int or float
Time in seconds to wait for a remote player to have started
Expand Down Expand Up @@ -229,7 +222,7 @@ def run_game(team_specs, *, layout_dict, max_rounds=300,
# we create the initial game state
state = setup_game(team_specs, layout_dict=layout_dict, max_rounds=max_rounds,
allow_camping=allow_camping,
error_limit=error_limit, timeout_length=timeout_length,
timeout_length=timeout_length,
initial_timeout_length=initial_timeout_length,
rng=rng, viewers=viewers,
store_output=store_output, team_names=team_names,
Expand Down Expand Up @@ -304,7 +297,7 @@ def setup_viewers(viewers, print_result=True):


def setup_game(team_specs, *, layout_dict, max_rounds=300, rng=None,
allow_camping=False, error_limit=5, timeout_length=TIMEOUT_SECS, initial_timeout_length=INITIAL_TIMEOUT_SECS,
allow_camping=False, timeout_length=TIMEOUT_SECS, initial_timeout_length=INITIAL_TIMEOUT_SECS,
viewers=None, store_output=False,
team_names=(None, None), team_infos=(None, None),
raise_bot_exceptions=False, print_result=True):
Expand Down Expand Up @@ -394,9 +387,6 @@ def setup_game(team_specs, *, layout_dict, max_rounds=300, rng=None,
#: Fatal errors
fatal_errors=[[], []],

#: Number of timeouts for a team
timeouts=[{}, {}],

### Configuration
#: Maximum number of rounds, int
max_rounds=max_rounds,
Expand Down Expand Up @@ -469,9 +459,6 @@ def setup_game(team_specs, *, layout_dict, max_rounds=300, rng=None,
#: Random number generator
rng=rng,

#: Error limit. A team loses when the limit is reached, int
error_limit=error_limit,

#: Viewers, list
viewers=viewer_state['viewers'],

Expand Down Expand Up @@ -626,8 +613,6 @@ def send_initial(game_state, raise_bot_exceptions=False):


def request_new_position(game_state):
round = game_state['round']
turn = game_state['turn']
team_idx = game_state['turn'] % 2
_bot_turn = game_state['turn'] // 2
team = game_state['teams'][team_idx]
Expand All @@ -651,28 +636,11 @@ def request_new_position(game_state):
}

except RemotePlayerRecvTimeout:
if game_state['error_limit'] != 0 and len(game_state['timeouts'][team_idx]) + 1 >= game_state['error_limit']:
# We had too many timeouts already. Trigger a fatal_error.
# If error_limit is 0, the game will go on.
# Trigger a fatal_error.
bot_reply = {
'error': 'Timeout error',
'error_msg': 'Too many timeouts'
'error': 'TimeoutError',
'error_msg': 'Timeout error'
}
else:
# There was a timeout. Execute a random move
legal_positions = get_legal_positions(game_state["walls"], game_state["shape"],
game_state["bots"][game_state["turn"]])
req_position = game_state['rng'].choice(legal_positions)
game_print(turn, f"Player timeout. Setting a legal position at random: {req_position}")

bot_reply = {
'move': req_position
}
timeout_event = {
'type': 'timeout',
'description': f"Player timeout. Setting a legal position at random: {req_position}"
}
game_state['timeouts'][team_idx][(round, turn)] = timeout_event


duration = time.monotonic() - start_time
Expand Down Expand Up @@ -736,7 +704,6 @@ def prepare_bot_state(game_state, team_idx=None):
'kills': game_state['kills'][own_team::2],
'deaths': game_state['deaths'][own_team::2],
'bot_was_killed': game_state['bot_was_killed'][own_team::2],
'num_timeouts': len(game_state['timeouts'][own_team]),
'food': list(game_state['food'][own_team]),
'shaded_food': shaded_food,
'name': game_state['team_names'][own_team],
Expand All @@ -751,7 +718,6 @@ def prepare_bot_state(game_state, team_idx=None):
'kills': game_state['kills'][enemy_team::2],
'deaths': game_state['deaths'][enemy_team::2],
'bot_was_killed': game_state['bot_was_killed'][enemy_team::2],
'num_timeouts': 0, # TODO. Could be left out for the enemy
'food': list(game_state['food'][enemy_team]),
'shaded_food': [],
'name': game_state['team_names'][enemy_team],
Expand Down Expand Up @@ -806,26 +772,6 @@ def prepare_viewer_state(game_state):
viewer_state['food_age'] = [item for team_food_age in viewer_state['food_age']
for item in team_food_age.items()]

# game_state["timeouts"] has a tuple as a dict key
# that cannot be serialized in json.
# To fix this problem, we only send the current error
# and add another attribute "num_timeouts"
# to the final dict.

# the key for the current round, turn
round_turn = (game_state["round"], game_state["turn"])
viewer_state["timeouts"] = [
# retrieve the current error or None
team_errors.get(round_turn)
for team_errors in game_state["timeouts"]
]

# add the number of errors
viewer_state["num_timeouts"] = [
len(team_errors)
for team_errors in game_state["timeouts"]
]

# remove unserializable values
del viewer_state['teams']
del viewer_state['rng']
Expand Down Expand Up @@ -855,7 +801,6 @@ def play_turn(game_state, raise_bot_exceptions=False):
game_state.update(next_round_turn(game_state))

turn = game_state['turn']
round = game_state['round']
team = turn % 2

# update food age and relocate expired food for the current team
Expand Down Expand Up @@ -907,7 +852,7 @@ def play_turn(game_state, raise_bot_exceptions=False):
game_state = apply_move(game_state, position)

# If there was no error, we claim a success in requested_moves
if (round, turn) not in game_state['timeouts'][team] and not game_state['fatal_errors'][team]:
if not game_state['fatal_errors'][team]:
game_state['requested_moves'][turn]['success'] = True

# Send updated game state with team names to the viewers
Expand Down
4 changes: 1 addition & 3 deletions pelita/scripts/pelita_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,6 @@ def long_help(s):
dest='timeout_length', help='Run game without timeouts.')
game_settings.add_argument('--initial-timeout', type=float, metavar="SEC", default=pelita.game.INITIAL_TIMEOUT_SECS,
dest='initial_timeout_length', help=long_help('Timeout to load a team'))
game_settings.add_argument('--error-limit', type=int, default=5,
dest='error_limit', help='Error limit. Reaching this limit disqualifies a team (default: 5).')
parser.set_defaults(timeout_length=pelita.game.TIMEOUT_SECS)
game_settings.add_argument('--stop-at', dest='stop_at', type=int, metavar="N",
help='Stop before playing round N.')
Expand Down Expand Up @@ -457,7 +455,7 @@ def main():

pelita.game.run_game(team_specs=team_specs, max_rounds=args.rounds, layout_dict=layout_dict, rng=rng,
allow_camping=args.allow_camping, timeout_length=args.timeout_length,
initial_timeout_length=args.initial_timeout_length, error_limit=args.error_limit,
initial_timeout_length=args.initial_timeout_length,
viewers=viewers,
store_output=args.store_output,
team_infos=(args.append_blue, args.append_red))
Expand Down
9 changes: 1 addition & 8 deletions pelita/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,6 @@ def __init__(self, *, bot_index,
is_blue,
team_name,
team_time,
num_timeouts,
is_noisy,
bot_turn=None):
self._bots = None
Expand Down Expand Up @@ -708,7 +707,6 @@ def __init__(self, *, bot_index,
self.is_blue = is_blue
self.team_name = team_name
self.team_time = team_time
self.timeouts = num_timeouts
self.is_noisy = is_noisy
self.has_exact_position = not is_noisy
self.graph = graph
Expand Down Expand Up @@ -894,8 +892,7 @@ def __str__(self):

header = ("{blue}{you_blue} vs {red}{you_red}.\n" +
"Playing on {col} side. Current turn: {turn}. "+
"Bot: {bot_char}. Round: {round}, score: {blue_score}:{red_score}. " +
"timeouts: {blue_timeouts}:{red_timeouts}\n").format(
"Bot: {bot_char}. Round: {round}, score: {blue_score}:{red_score}.\n").format(
blue=blue.team_name,
red=red.team_name,
turn=bot.turn,
Expand All @@ -906,8 +903,6 @@ def __str__(self):
col="blue" if bot.is_blue else "red",
you_blue=" (you)" if bot.is_blue else "",
you_red=" (you)" if not bot.is_blue else "",
blue_timeouts=blue.timeouts,
red_timeouts=red.timeouts,
)

footer = ("Bots: {bots}\nExact: {exact}\nFood: {food}\n").format(
Expand Down Expand Up @@ -950,7 +945,6 @@ def make_bots(*, walls, shape, initial_positions, homezone, team, enemy, round,
kills=team['kills'][idx],
was_killed=team['bot_was_killed'][idx],
is_noisy=False,
num_timeouts=team['num_timeouts'],
food=_ensure_list_tuples(team['food']),
shaded_food=_ensure_list_tuples(team['shaded_food']),
walls=walls,
Expand Down Expand Up @@ -978,7 +972,6 @@ def make_bots(*, walls, shape, initial_positions, homezone, team, enemy, round,
deaths=enemy['deaths'][idx],
was_killed=enemy['bot_was_killed'][idx],
is_noisy=enemy['is_noisy'][idx],
num_timeouts=enemy['num_timeouts'],
food=_ensure_list_tuples(enemy['food']),
shaded_food=[],
walls=walls,
Expand Down
2 changes: 1 addition & 1 deletion pelita/ui/tk_canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,7 @@ def status(team_idx):
# sum the deaths of both bots in this team
deaths = game_state['deaths'][team_idx] + game_state['deaths'][team_idx+2]
kills = game_state['kills'][team_idx] + game_state['kills'][team_idx+2]
ret = "Timeouts: %d, Kills: %d, Deaths: %d, Time: %.2f" % (game_state["num_timeouts"][team_idx], kills, deaths, game_state["team_time"][team_idx])
ret = "Kills: %d, Deaths: %d, Time: %.2f" % (kills, deaths, game_state["team_time"][team_idx])
return ret
except TypeError:
return ""
Expand Down
4 changes: 0 additions & 4 deletions pelita/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,6 @@ def run_background_game(*, blue_move, red_move, layout=None, max_rounds=300, see
out['red_bots'] = game_state['bots'][1::2]
out['blue_score'] = game_state['score'][0]
out['red_score'] = game_state['score'][1]
out['blue_errors'] = game_state['timeouts'][0]
out['red_errors'] = game_state['timeouts'][1]
out['blue_deaths'] = game_state['deaths'][::2]
out['red_deaths'] = game_state['deaths'][1::2]
out['blue_kills'] = game_state['kills'][::2]
Expand Down Expand Up @@ -230,7 +228,6 @@ def setup_test_game(*, layout, is_blue=True, round=None, score=None, seed=None,
'kills': [0]*2,
'deaths': [0]*2,
'bot_was_killed' : [False]*2,
'num_timeouts': 0,
'food': food[team_index],
'shaded_food': list(shaded_food(bot_positions, food[team_index], radius=SHADOW_DISTANCE)),
'name': "blue" if is_blue else "red",
Expand All @@ -243,7 +240,6 @@ def setup_test_game(*, layout, is_blue=True, round=None, score=None, seed=None,
'kills': [0]*2,
'deaths': [0]*2,
'bot_was_killed': [False]*2,
'num_timeouts': 0,
'food': food[enemy_index],
'shaded_food': [],
'is_noisy': is_noisy_enemy,
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/remote_timeout_red.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ def move(b, s):
if b.round == 2 and b.turn == 1:
return (-2, 0)
time.sleep(0.5)
return b.position
return b.position
Loading
Loading