Skip to content

Commit

Permalink
Merge branch 'main' into public-release
Browse files Browse the repository at this point in the history
  • Loading branch information
TheApplePieGod committed Jan 28, 2025
2 parents 067f6ef + e74bdcf commit 5236720
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 16 deletions.
7 changes: 5 additions & 2 deletions battlecode25/engine/container/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,13 @@ def instrument_call(self):
self.bytecode -= 1
if self.bytecode <= 0:
self.error_method(f'Ran out of bytecode. Remaining bytecode: {self.bytecode}')
self.thread.wait()
self.pause()

def multinstrument_call(self, n):
self.bytecode -= n
if self.bytecode <= 0:
self.error_method(f'Ran out of bytecode. Remaining bytecode: {self.bytecode}')
self.thread.wait()
self.pause()

def import_call(self, name, globals=None, locals=None, fromlist=(), level=0, caller='robot'):
if not isinstance(name, str) or not (isinstance(fromlist, tuple) or fromlist is None):
Expand Down Expand Up @@ -259,6 +259,9 @@ def run(self):
self.thread.finished_event.wait()
self.thread.finished_event.clear()

def pause(self):
self.thread.wait()

def kill(self):
self.thread.kill()
self.thread.join()
4 changes: 4 additions & 0 deletions battlecode25/engine/game/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ class GameConstants:

TOWER_BYTECODE_LIMIT = 20000

# The maximum execution time that can be spent on a team in one match. If the total time spent executing a team's bots
# exceeds this limit, the team will immediately lose the game. Execution time is measured in ns.
MAX_TEAM_EXECUTION_TIME = 1200000000000

# The maximum length of indicator strings that a player can associate with a robot.
INDICATOR_STRING_MAX_LENGTH = 64

Expand Down
26 changes: 21 additions & 5 deletions battlecode25/engine/game/game.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import math
import time
import random
from enum import Enum
from .robot import Robot
Expand All @@ -19,8 +21,6 @@
from typing import Generator
from .message import Message

import math

class Game:

def __init__(self, code, initial_map: InitialMap, game_fb: GameFB, game_args):
Expand Down Expand Up @@ -66,12 +66,20 @@ def __init__(self, code, initial_map: InitialMap, game_fb: GameFB, game_args):
self.update_defense_towers(robot.team, new_type)

def run_round(self):
def run_turn(robot: Robot):
start_time = time.time_ns()
robot.turn()
run_time = time.time_ns() - start_time
self.team_info.add_execution_time(robot.team, run_time)
if self.team_info.get_execution_time(robot.team) >= GameConstants.MAX_TEAM_EXECUTION_TIME:
self.resign(robot.team)

if self.running:
self.round += 1
self.game_fb.start_round(self.round)
self.update_resource_patterns()
self.each_robot(lambda robot: robot.process_beginning_of_round())
self.each_robot_update(lambda robot: robot.turn())
self.each_robot_update(run_turn)
self.serialize_team_info()
self.team_info.process_end_of_round()
self.game_fb.end_round()
Expand Down Expand Up @@ -250,6 +258,9 @@ def set_winner_arbitrary(self):
self.set_winner(Team.A if random.random() < 0.5 else Team.B, DominationFactor.WON_BY_DUBIOUS_REASONS)
return True

def resign(self, team: Team):
self.set_winner(team.opponent(), DominationFactor.RESIGNATION)

def run_tiebreakers(self):
if self.set_winner_if_more_area(): return
if self.set_winner_if_more_allied_towers(): return
Expand Down Expand Up @@ -584,12 +595,17 @@ def create_methods(self, rc: RobotController):
'upgrade_tower': rc.upgrade_tower,
'resign': rc.resign,
'disintegrate': rc.disintegrate,
'yield_turn': (rc.yield_turn, 0),
'get_bytecode_num': (rc.get_bytecode_num, 0),
'get_bytecodes_left': (rc.get_bytecodes_left, 0),
'get_time_elapsed': (rc.get_time_elapsed, 0),
'get_time_left': (rc.get_time_left, 0),
'set_indicator_string': rc.set_indicator_string,
'set_indicator_dot': rc.set_indicator_dot,
'set_indicator_line': rc.set_indicator_line,
'set_timeline_marker': rc.set_timeline_marker,
'set_timeline_marker': rc.set_timeline_marker
}

def create_patterns(self):
resource_pattern = [
[True, True, False, True, True],
Expand Down
2 changes: 1 addition & 1 deletion battlecode25/engine/game/play.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def run_game(args: RunGameArgs):
b_wins += 1
game_fb.make_match_footer(game.winner, game.domination_factor, game.round)
except Exception as e:
print("[server:error] An internal engine error has occurred. Please report this to the devs. This match has been terminated.")
print(f"[server:error] An internal engine error has occurred. Please report this to the devs. This match has been terminated : {e}")
game.set_winner_arbitrary()
game.stop()
# Internal engine occurred, we have to throw away this replay
Expand Down
20 changes: 14 additions & 6 deletions battlecode25/engine/game/robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ def __init__(self, game: Game, id, team: Team, type: UnitType, loc: MapLocation)
self.paint = round(self.type.paint_capacity * GameConstants.INITIAL_ROBOT_PAINT_PERCENTAGE / 100)
else:
self.paint = GameConstants.INITIAL_TOWER_PAINT_AMOUNT
self.bytecodes_used = 0
self.rounds_alive = 0
self.action_cooldown = type.action_cooldown
self.movement_cooldown = GameConstants.COOLDOWN_LIMIT
Expand All @@ -52,12 +51,12 @@ def calc_paint_cooldown_multiplier(self):
if paint_percent < 0.5:
return 2 - 2 * paint_percent
return 1

def add_action_cooldown(self, cooldown=-1):
if cooldown == -1:
cooldown = self.type.action_cooldown
self.action_cooldown += round(cooldown * self.calc_paint_cooldown_multiplier())

def add_movement_cooldown(self):
self.movement_cooldown += round(GameConstants.MOVEMENT_COOLDOWN * self.calc_paint_cooldown_multiplier())

Expand All @@ -68,7 +67,7 @@ def upgrade_tower(self):

def log(self, msg):
self.logs.append(msg)

def error(self, msg):
self.logs.append(msg)

Expand All @@ -80,6 +79,15 @@ def animate(self, code, methods, debug=False):
def kill(self):
self.runner.kill()

def get_bytecode_limit(self):
return self.runner.bytecode_limit

def get_bytecodes_left(self):
return self.runner.bytecode

def get_bytecodes_used(self):
return max(self.runner.bytecode_limit - self.runner.bytecode, 0)

def turn(self):
self.process_beginning_of_turn()
self.logs.clear()
Expand All @@ -104,7 +112,7 @@ def process_beginning_of_turn(self):
self.action_cooldown = max(0, self.action_cooldown - GameConstants.COOLDOWNS_PER_TURN)
self.movement_cooldown = max(0, self.movement_cooldown - GameConstants.COOLDOWNS_PER_TURN)
self.game.game_fb.start_turn(self.id)

def process_end_of_turn(self):
loc_idx = self.game.loc_to_index(self.loc)
paint_status = self.game.paint[loc_idx]
Expand Down Expand Up @@ -135,7 +143,7 @@ def process_end_of_turn(self):
if self.type.is_robot_type() and self.paint == 0:
self.add_health(-GameConstants.NO_PAINT_DAMAGE)

self.game.game_fb.end_turn(self.id, self.health, self.paint, self.movement_cooldown, self.action_cooldown, self.bytecodes_used, self.loc)
self.game.game_fb.end_turn(self.id, self.health, self.paint, self.movement_cooldown, self.action_cooldown, self.get_bytecodes_used(), self.loc)
self.rounds_alive += 1

def get_robot_info(self) -> RobotInfo:
Expand Down
21 changes: 19 additions & 2 deletions battlecode25/engine/game/robot_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -792,11 +792,28 @@ def set_timeline_marker(self, label: str, red: int, green: int, blue: int) -> No
self.game.game_fb.add_timeline_marker(self.robot.team, label, red, green, blue)

def resign(self) -> None:
self.game.set_winner(self.robot.team.opponent(), DominationFactor.RESIGNATION)
self.game.resign(self.robot.team)

def disintegrate(self) -> None:
self.game.destroy_robot(self.robot.id)


# CLOCK METHODS

def yield_turn(self) -> None:
self.robot.runner.pause()

def get_bytecode_num(self) -> int:
return self.robot.get_bytecodes_used()

def get_bytecodes_left(self) -> int:
return self.robot.get_bytecodes_left()

def get_time_elapsed(self) -> int:
return self.game.team_info.get_execution_time(self.robot.team)

def get_time_left(self) -> int:
return max(GameConstants.MAX_TEAM_EXECUTION_TIME - self.get_time_elapsed(), 0)

class RobotError(Exception):
"""Raised for illegal robot inputs"""
pass
7 changes: 7 additions & 0 deletions battlecode25/engine/game/team_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def __init__(self, game_world):
self.old_coin_counts = [0] * 2
self.unit_counts = [0] * 2
self.defense_damage_increase = [0] * 2
self.execution_time = [0] * 2

# ***** GETTER METHODS *****

Expand All @@ -33,6 +34,9 @@ def get_unit_count(self, team):

def get_defense_damage_increase(self, team):
return self.defense_damage_increase[team.value]

def get_execution_time(self, team):
return self.execution_time[team.value]

# ***** UPDATE METHODS *****

Expand All @@ -56,3 +60,6 @@ def add_unit_count(self, team, amount):

def add_defense_damage_increase(self, team, amount):
self.defense_damage_increase[team.value] += amount

def add_execution_time(self, team, amount):
self.execution_time[team.value] += amount
34 changes: 34 additions & 0 deletions battlecode25/stubs.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,3 +476,37 @@ def disintegrate() -> None:
Destroys this robot.
"""
pass

# CLOCK METHODS

def yield_turn() -> None:
"""
Ends the processing of this robot during the current round.
"""
pass

def get_bytecode_num() -> int:
"""
Returns the number of bytecodes the current robot has executed since the
beginning of the current round.
"""
pass

def get_bytecodes_left() -> int:
"""
Returns the number of bytecodes this robot has left in this round.
"""
pass

def get_time_elapsed() -> int:
"""
Returns the total amount of time, in nanoseconds, that this team's robots have collectively spent executing
since the beginning of the match.
"""
pass

def get_time_left() -> int:
"""
Returns the total amount of execution time, in nanoseconds, left this team has before they timeout
"""
pass

0 comments on commit 5236720

Please sign in to comment.