def unit_attack_ranged(contubernium: BattleContuberniumInTurn,
                       target_contubernium: BattleContuberniumInTurn):
    for soldier in contubernium.battlesoldierinturn_set.all():
        target_soldier = random.choice(
            target_contubernium.battlesoldierinturn_set.all()[:])
        while (random.random() < 0.3 * soldier.attack_chance_multiplier()):
            if target_soldier.wound_status < BattleSoldierInTurn.DEAD:
                target_soldier.take_hit()
        target_soldier.save()
    contubernium.ammo_remaining -= 1
    if contubernium.ammo_remaining < 0:
        contubernium.ammo_remaining = 0
    contubernium.save()
Esempio n. 2
0
def optimistic_move_desire_formulation(
        battle_contubernium_in_turn: BattleContuberniumInTurn,
        target_distance_function):
    def tile_availability_test(coords: Coordinates):
        return True

    if target_distance_function(battle_contubernium_in_turn.coordinates()) > 0:
        path = find_path(battle_contubernium_in_turn, target_distance_function,
                         tile_availability_test)
        if len(path) > 1:
            battle_contubernium_in_turn.desires_pos = True
            battle_contubernium_in_turn.desired_x_pos = path[1].x
            battle_contubernium_in_turn.desired_z_pos = path[1].z
            battle_contubernium_in_turn.save()
Esempio n. 3
0
def safe_move(battle_contubernium_in_turn: BattleContuberniumInTurn,
              target_distance_function):
    turn = battle_contubernium_in_turn.battle_turn

    def tile_availability_test(coords: Coordinates):
        return True if turn.get_contubernium_in_position(
            coords) is None else False

    if target_distance_function(battle_contubernium_in_turn.coordinates()) > 0:
        path = find_path(battle_contubernium_in_turn, target_distance_function,
                         tile_availability_test)
        if len(path) > 1:
            battle_contubernium_in_turn.moved_this_turn = True
            battle_contubernium_in_turn.x_pos = path[1].x
            battle_contubernium_in_turn.z_pos = path[1].z
            #TODO WARNING: HORRIBLE HACK STARTS HERE
            #(to avoid unique constraint errors when contubs overlap for some reason)
            with transaction.atomic():
                try:
                    battle_contubernium_in_turn.save()
                except django.db.utils.IntegrityError as e:
                    pass
Esempio n. 4
0
def find_path(battle_contubernium_in_turn: BattleContuberniumInTurn,
              target_distance_function, tile_availability_test) -> list:
    starting_coordinates = battle_contubernium_in_turn.coordinates()
    if target_distance_function(starting_coordinates) <= 0:
        return True

    closed_set = set()
    open_set = set()
    open_set.add(starting_coordinates)
    came_from = {}
    g_score = {}
    g_score[starting_coordinates] = 0
    f_score = {}
    f_score[starting_coordinates] = target_distance_function(
        starting_coordinates)

    while open_set:
        minel = None
        for el in open_set:
            if minel is None or f_score[el] < f_score[minel]:
                minel = el
        current = minel
        open_set.remove(minel)

        if target_distance_function(current) <= 0:
            # RECONSTRUCT
            # print("REACHED GOAL, backtracing")
            total_path = [current]
            while current in came_from.keys():
                current = came_from[current]
                if current != starting_coordinates and not tile_availability_test(
                        current):
                    return []
                total_path.append(current)
                # print("Backtrace {}".format(current))
            total_path.reverse()
            return total_path

        closed_set.add(current)
        for neighbor in coordinate_neighbours(current):
            if neighbor in closed_set:
                # print("Already closed: {}".format(neighbor))
                continue
            tentative_g_score = g_score[current] + euclidean_distance(
                current, neighbor)
            if not tile_availability_test(neighbor):
                tentative_g_score += 20
            # print("Considering {} with score {}".format(neighbor, tentative_g_score))
            if neighbor not in open_set:
                # print("Adding to open set")
                open_set.add(neighbor)
            elif tentative_g_score >= g_score[neighbor]:
                # print("Better value in g_score map")
                continue

            # print("Found better path")
            came_from[neighbor] = current
            g_score[neighbor] = tentative_g_score
            f_score[neighbor] = g_score[neighbor] + target_distance_function(
                neighbor)

    return []
Esempio n. 5
0
def get_target_distance_function(
        battle_contubernium_in_turn: BattleContuberniumInTurn):
    order = battle_contubernium_in_turn.battle_unit_in_turn.battle_unit.get_order(
    )
    enemy_contubernia = BattleContuberniumInTurn.objects.filter(
        battle_turn=battle_contubernium_in_turn.battle_turn).exclude(
            battle_contubernium__battle_unit__battle_side=
            battle_contubernium_in_turn.battle_contubernium.battle_unit.
            battle_side)

    if order:

        if order.what == Order.STAND:
            return None

        if order.what == Order.MOVE:
            unit_target = order.target_location_coordinates()
            target = Coordinates(
                x=(unit_target.x + battle_contubernium_in_turn.
                   battle_contubernium.x_offset_to_unit),
                z=(unit_target.z + battle_contubernium_in_turn.
                   battle_contubernium.z_offset_to_unit))

            def result(coords: Coordinates):
                return euclidean_distance(coords, target)

            return result

        if order.what == Order.FLEE:
            original_enemy_distance = closest_in_set(
                battle_contubernium_in_turn.coordinates(),
                enemy_contubernia)[1]

            def result(coords: Coordinates):
                closest, distance = closest_in_set(coords, enemy_contubernia)
                return (original_enemy_distance +
                        10) - distance if distance is not None else 0

            return result

        if order.what == Order.CHARGE:

            def result(coords: Coordinates):
                closest, distance = closest_in_set(coords, enemy_contubernia)
                return distance if distance is not None and distance >= 2 else 0

            return result

        if order.what == Order.ADVANCE_IN_FORMATION:
            z_direction = -1 if battle_contubernium_in_turn.battle_contubernium.battle_unit.battle_side.z else 1
            z_offset = battle_contubernium_in_turn.battle_turn.num * z_direction
            target = Coordinates(x=battle_contubernium_in_turn.
                                 battle_contubernium.starting_x_pos,
                                 z=battle_contubernium_in_turn.
                                 battle_contubernium.starting_z_pos + z_offset)

            def result(coords: Coordinates):
                return euclidean_distance(coords, target)

            return result

        if order.what == Order.RANGED_ATTACK:
            pass
Esempio n. 6
0
def grant_position_desire(desire_getter: BattleContuberniumInTurn):
    desire_getter.desires_pos = False
    desire_getter.moved_this_turn = True
    desire_getter.x_pos = desire_getter.desired_x_pos
    desire_getter.z_pos = desire_getter.desired_z_pos
    desire_getter.save()
Esempio n. 7
0
def grant_position_swap(contubernium1: BattleContuberniumInTurn,
                        contubernium2: BattleContuberniumInTurn):
    contubernium1.x_pos = 31337
    contubernium1.save()
    grant_position_desire(contubernium2)
    grant_position_desire(contubernium1)
def get_target_distance_function(
        battle_contubernium_in_turn: BattleContuberniumInTurn):
    order = battle_contubernium_in_turn.battle_unit_in_turn.battle_unit.get_order(
    )
    enemy_contubernia = BattleContuberniumInTurn.objects.filter(
        battle_turn=battle_contubernium_in_turn.battle_turn).exclude(
            battle_contubernium__battle_unit__battle_side=
            battle_contubernium_in_turn.battle_contubernium.battle_unit.
            battle_side)

    if order:

        if order.what == Order.STAND or (
                order.what == Order.RANGED_AND_STAND
                and battle_contubernium_in_turn.ammo_remaining == 0):
            return None

        if order.what == Order.MOVE:
            unit_target = order.target_location_coordinates()
            target = Coordinates(
                x=(unit_target.x + battle_contubernium_in_turn.
                   battle_contubernium.x_offset_to_unit),
                z=(unit_target.z + battle_contubernium_in_turn.
                   battle_contubernium.z_offset_to_unit))

            def result(coords: Coordinates):
                return euclidean_distance(coords, target)

            return result

        if order.what == Order.FLEE or (
                order.what == Order.RANGED_AND_FLEE
                and battle_contubernium_in_turn.ammo_remaining == 0):
            original_enemy_distance = closest_in_set(
                battle_contubernium_in_turn.coordinates(),
                enemy_contubernia)[1]

            def result(coords: Coordinates):
                closest, distance = closest_in_set(coords, enemy_contubernia)
                return (original_enemy_distance +
                        10) - distance if distance is not None else 0

            return result

        if order.what == Order.CHARGE or (
                order.what == Order.RANGED_AND_CHARGE
                and battle_contubernium_in_turn.ammo_remaining == 0):

            def result(coords: Coordinates):
                closest, distance = closest_in_set(coords, enemy_contubernia)
                return distance if distance is not None and distance >= 2 else 0

            return result

        if order.what == Order.ADVANCE_IN_FORMATION:
            z_direction = -1 if battle_contubernium_in_turn.battle_contubernium.battle_unit.battle_side.z else 1
            z_offset = battle_contubernium_in_turn.battle_turn.num * z_direction
            target = Coordinates(x=battle_contubernium_in_turn.
                                 battle_contubernium.starting_x_pos,
                                 z=battle_contubernium_in_turn.
                                 battle_contubernium.starting_z_pos + z_offset)

            def result(coords: Coordinates):
                return euclidean_distance(coords, target)

            return result

        if order.what in (Order.RANGED_AND_CHARGE, Order.RANGED_AND_FLEE,
                          Order.RANGED_AND_STAND
                          ) and battle_contubernium_in_turn.ammo_remaining > 0:

            def result(coords: Coordinates):
                closest, distance = closest_in_set(coords, enemy_contubernia)
                shot_range = battle_contubernium_in_turn.battle_unit_in_turn.battle_unit.world_unit.shot_range(
                )
                if distance > shot_range:
                    return distance - shot_range
                if distance < shot_range - 1:
                    return shot_range - distance
                return 0

            return result

        if order.what == Order.STAND_AND_DISTANCE:

            def result(coords: Coordinates):
                closest, enemy_distance = closest_in_set(
                    coords, enemy_contubernia)
                shot_range = battle_contubernium_in_turn.battle_unit_in_turn.battle_unit.world_unit.shot_range(
                )
                if shot_range == 0:
                    min_enemy_distance = 7
                else:
                    min_enemy_distance = shot_range - 1

                if enemy_distance > min_enemy_distance:
                    return 0
                else:
                    return min_enemy_distance - enemy_distance

            return result