Sorry if this is a lot, but I cant find the issue… It just times out immediately. I am learning to program and this is one of the first things I have written, and I got a little carried away without testing. Help?
import sys
import math
import heapq
# Initialization input
# This is the code the game supplied me with
factory_count = int(input()) # the number of factories on the map
link_count = int(input()) # the number of links between factories on the map
# Dictionary to store distances between factories
# Distance is expressed as the number of turns it takes to reach one factory starting from another
distances = {}
EnemyTroops = []
MyTroops = []
entities = {}
MyFactories = []
EnemyFactories = []
NeutralFactories = []
actions = []
# This is the code the game supplied me with
for i in range(link_count):
factory_1, factory_2, distance = [int(j) for j in input().split()]
# The distance between factory_1 and factory_2 is the same as the distance between factory_2 and factory_1
distances[(factory_1, factory_2)] = distance
distances[(factory_2, factory_1)] = distance
# Function to calculate turns between factories based on the distances dictionary
def turns(factory_1_id, factory_2_id):
return distances.get((factory_1_id, factory_2_id), None)
# Function to calculate the opposition value for a move from one location to another
def total_opposition(location, destination):
positive = 0
negative = 0
if entities[destination["id"]]["arg1"] == 1: # If destination is owned by me
positive += entities[destination["id"]]["arg2"] + entities[destination["id"]]["arg3"]
else: # If destination is not owned by me
negative += entities[destination["id"]]["arg2"] + entities[destination["id"]]["arg3"]
# Add the number of my troops on the way to the destination
for i in MyTroops:
if i["arg3"] == destination["id"]:
positive += i["arg4"]
# Add the number of enemy troops on the way to the location if they will be there before or at the same time as my troops
for i in EnemyTroops:
if i["arg3"] == location["id"] and i["arg5"] <= turns(location["id"], destination["id"]):
negative += i["arg4"]
return positive - negative
def total_needed(location, destination):
positive = 0
negative = 0
if entities[destination["id"]]["arg1"] == 1: # If destination is owned by me
positive += entities[destination["id"]]["arg2"] + entities[destination["id"]]["arg3"]
else: # If destination is not owned by me
negative += entities[destination["id"]]["arg2"] + entities[destination["id"]]["arg3"]
# Add the number of my troops on the way to the destination
for i in MyTroops:
if i["arg3"] == destination["id"]:
positive += i["arg4"]
# Add the number of enemy troops on the way to the location if they will be there before or at the same time as my troops
for i in EnemyTroops:
if i["arg3"] == location["id"] and i["arg5"] <= turns(location["id"], destination["id"]):
negative += i["arg4"]
return negative
# Function to calculate the threat level to a factory
def threat_level(factory):
positive = 0
negative = 0
# Add the number of enemy troops on the way to the location
for i in EnemyTroops:
if i["arg3"] == factory["id"]:
negative += i["arg4"]
if entities[factory["id"]]["arg1"] == 1: # If destination is owned by me
positive += entities[factory["id"]]["arg2"] + entities[factory["id"]]["arg3"]
else: # If destination is not owned by me
negative += entities[factory["id"]]["arg2"] + entities[factory["id"]]["arg3"]
# Add the number of my troops on the way to the destination
for i in MyTroops:
if i["arg3"] == factory["id"]:
positive += i["arg4"]
return negative - positive
def select_source_factory(target_factory, my_factories):
heap = []
for i in my_factories:
# calculate distance
distance = turns(i["id"], target_factory["id"])
# Push tuple into heap
heapq.heappush(heap, (threat_level(i), distance, i))
# Return factories sorted by threat level and distance
return [factory for _, _, factory in heapq.nsmallest(len(heap), heap)]
# The main game loop
while True:
entities = {}
MyFactories.clear()
EnemyFactories.clear()
NeutralFactories.clear()
EnemyTroops.clear()
MyTroops.clear()
actions = []
entity_count = int(sys.stdin.readline().strip())
# entity_count = int(input()) # the number of entities (factories and troops) on the map
# Input the data for each entity
for i in range(entity_count):
entity_data = input().split()
entity_id = int(entity_data[0])
entity_type = entity_data[1]
arg_1, arg_2, arg_3, arg_4, arg_5 = map(int, entity_data[2:])
entity = {
"id": entity_id,
"type": entity_type,
"arg1": arg_1,
"arg2": arg_2,
"arg3": arg_3,
"arg4": arg_4,
"arg5": arg_5,
}
entities[entity_id] = entity
# Populate lists for my factories, enemy factories, neutral factories, my troops and enemy troops
if entity_type == "FACTORY":
if arg_1 == 1: # Owned by me
MyFactories.append(entity)
elif arg_1 == -1: # Owned by the enemy
EnemyFactories.append(entity)
else: # Neutral
NeutralFactories.append(entity)
else: # Entity type is "TROOP"
if arg_1 == 1: # Owned by me
MyTroops.append(entity)
else: # Owned by the enemy
EnemyTroops.append(entity)
all_factories = NeutralFactories + EnemyFactories + MyFactories # A list of all factories
# Sort all factories by relative threat
all_factories.sort(key=threat_level)
for target_factory in all_factories:
source_factories = MyFactories
sent_cyborgs = False
source_factories = select_source_factory(target_factory, MyFactories)
#sort through all of my factories in order of which ones are more oppertune to attack
for source_factory in source_factories:
factory_id = source_factory['id']
corresponding_entity = entities[factory_id]
# Find the corresponding entity in the entities dictionary
# Calculate the number of cyborgs to send to the target factory based on its relative strength
cyborgs_to_send = min(total_needed(source_factory, target_factory), total_opposition(source_factory, target_factory), corresponding_entity["arg2"])
# if we are sending cyborgs
if cyborgs_to_send > 0 and source_factory != target_factory and corresponding_entity["arg2"] >= 1: # and source_factory["arg2"] >= cyborgs_to_send:
for factory in MyFactories:
if factory['id'] == corresponding_entity['id']:
factory['arg2'] -= cyborgs_to_send
break
corresponding_entity['arg2'] -= cyborgs_to_send # Subtract the cyborgs from source factory for future loops
entity = {
"id": len(entities) + 1,
"type": 'TROOP',
"arg1": 1,
"arg2": corresponding_entity['id'], # the source factory if it's a troop
"arg3": target_factory['id'], # Production if it's a factory or ID of the target factory if it's a troop
"arg4": cyborgs_to_send, # Number of cyborgs if it's a troop
"arg5": turns(corresponding_entity['id'], target_factory['id']), # Amount of turns until arrive at Factory if it's a Troop
}
# create a new unite to calculate in for future loops use of threat and opposition functions
entities[entity['id']] = entity
# Create an action to send cyborgs from my factory to the target factory
# The action is in the format "MOVE source destination cyborgCount"
actions.append(f"MOVE {corresponding_entity['id']} {target_factory['id']} {cyborgs_to_send}")
# actions.append(f"MSG {int(source_factory['id'])} {int(target_factory['id'])} {int(cyborgs_to_send)}")
# Output the actions, separated by semicolons
# If there are no actions, output "WAIT"
print(';'.join(actions)) if actions else print("WAIT")