Ghost in the Cell (aka Cyborg Uprising) - Puzzle Discussion

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")

Comment out line 116 and uncomment line 117, and your code will at least run without the previous error.

1 Like

How can I best improve my code from here? I’m currently trying to improve my coding skills and thought this website would be pretty good for that but I keep finding problems I don’t even know how to start solving and I can’t really find any helpful guidance anywhere.

import sys
import math

# Auto-generated code below aims at helping you parse
# the standard input according to the problem statement.
enemy = False
action = ""
enemy_troops = 0
my_factory = []
enemy_factory = []
factory_count = int(input())  # the number of factories
link_count = int(input())  # the number of links between factories
for i in range(link_count):
    factory_1, factory_2, distance = [int(j) for j in input().split()]

# game loop
while True:
    entity_count = int(input())  # the number of entities (e.g. factories and troops)
    for i in range(entity_count):
        inputs = input().split()
        entity_id = int(inputs[0])
        entity_type = inputs[1]
        arg_1 = int(inputs[2])
        arg_2 = int(inputs[3])
        arg_3 = int(inputs[4])
        arg_4 = int(inputs[5])
        arg_5 = int(inputs[6])

        if entity_type == "FACTORY":
            if arg_1 == 1 and my_factory.count(entity_id) == 0:
                my_factory.append(entity_id)
            elif arg_1 != 1 and enemy_factory.count(entity_id) == 0 and arg_3 > 0 and len(enemy_factory) < 3:
                enemy = True
                enemy_factory.append(entity_id) 

            if arg_1 == 1 and entity_id in enemy_factory:
                enemy_factory.remove(entity_id)
            if arg_1 != 1 and entity_id in my_factory:
                my_factory.remove(entity_id)
        
    if enemy == True and len(my_factory) > 0:
        for i in range(len(enemy_factory)):
            for x in range(len(my_factory)):
                if i == 0: 
                    action = "MOVE " + str(my_factory[0]) + " " + str(enemy_factory[0]) + " 1"
                else:
                    action = action + ";MOVE " + str(my_factory[x]) + " " + str(enemy_factory[i]) + " 1"
        print(action)
        action = "WAIT"
            
    else:
        print("WAIT")

Hello, I am 1st in gold division with 23.45 can anyone help me to get into legend league, please pm me if you can thank you.

Thank you I just promoted to legend league

1 Like

Nicely Done!!!
That’s amazing.