<commit_before>import copy

WALL = 0
EMPTY = 1
PILL = 2
POWER_PILL = 3
FRUIT_LOCATION = 4
LAMAN_START = 5
GHOST_START = 6

GHOST_STANDARD = 0
GHOST_FRIGHTENED = 1
GHOST_INVISIBLE = 2

UP = 0
RIGHT = 1
DOWN = 2
LEFT = 3

DIRECTION_NAMES = {
    UP: 'UP',
    RIGHT: 'RIGHT',
    LEFT: 'LEFT',
    DOWN: 'DOWN',
}

FRUIT_SCORES = [100,300,500,500,700,700,1000,1000,2000,2000,3000,3000,5000]
GHOST_SCORES = [200, 400, 800, 1600]


def move_from(position, direction):
    """
    position, direction -> new position
    """
    if direction == UP:
        return position[0]-1, position[1]
    if direction == RIGHT:
        return position[0], position[1]+1
    if direction == DOWN:
        return position[0]+1, position[1]
    if direction == LEFT:
        return position[0], position[1]-1
    raise ValueError('Wrong direction: {}'.format(direction))


def can_move(world, pos, direction):
    return world.map_at(move_from(pos, direction)) != WALL


def manhattan_distance(pos1, pos2):
    return abs(pos1[0]-pos2[0]) + abs(pos1[1]-pos2[1])


def direction_turns(d):
    if d in [LEFT, RIGHT]:
        return [UP, DOWN]
    else:
        return [LEFT, RIGHT]


def direction_back(d):
    return (d+2) % 4


def cell_score(pos, world):
    c = world.map_at(pos)
    if c == PILL:
        return 10
    if c == POWER_PILL:
        return 50
    if c == FRUIT_LOCATION and world.is_fruit_on():
        if world.level > 12:
            return 5000
        else:
            return FRUIT_SCORES[world.level]
    return 0


class Temporary:
    """
    Something influenced by time.
    """
    def get_update_interval(self, **kwargs):
        raise ValueError('You really need to define this')

    def next_self(self, time_delta, **kwargs):
        """
        The method you need to define: what changes?
        :return: the new self
        """
        raise ValueError('What is the point of being time-dependent then?')


class Loop:
    class Entry:
        def __init__(self, mortal, **kwargs):
            self.mortal = mortal
            self.ticks_till_next = mortal.get_update_interval(**kwargs)

        def next_entry(self, mortal, time_delta, **kwargs):
            result = Loop.Entry(mortal, **kwargs)
            result.ticks_till_next -= time_delta
            assert result.ticks_till_next >= 0, "Another guy missed his time"
            return result

    def __init__(self, tracked=None):
        self.tracked = tracked or []

    def add_tracked(self, t, **kwargs):
        self.tracked.append(Loop.Entry(t, **kwargs))

    def entries(self):
        return [e.mortal for e in self.tracked]

    def next_tick_in(self):
        return min([t.ticks_till_next for t in self.tracked])

    def next_self(self, delta_time, mortal_clones=None, **kwargs):
        """
        :param mortal_clones: The pre-filled clones of current objects (maybe with already changed state) to use instead
        stored, immutable copies. A hack to allow La-Man to modify "future Ghosts".
        :type mortal_clones: list(Temporal)
        """
        new_tracked = []
        i = 0
        for t in self.tracked:
            if t.ticks_till_next < delta_time:
                raise AssertionError('Poor guy missed its time: ' + str(t))
            mortal = mortal_clones[i] if mortal_clones and mortal_clones[i] else t.mortal
            if t.ticks_till_next == delta_time:
                new_mortal = mortal.next_self(delta_time, **kwargs)
                new_tracked.append(Loop.Entry(new_mortal, **kwargs))
            else:
                e = t.next_entry(mortal, delta_time, **kwargs)
                new_tracked.append(e)
            i += 1
        return Loop(new_tracked)


class Laman:
    def __init__(self, vitality, pos, direction, lives, score, ghosts_eaten=0):
        self.vitality, self.pos, self.direction, self.lives, self.score = vitality, pos, direction, lives, score
        self.ghosts_eaten = ghosts_eaten
        self.game_over = False

    def ghost_score(self):
        return GHOST_SCORES[-1] if self.ghosts_eaten > 4 else GHOST_SCORES[self.ghosts_eaten]

    def next_self(self, delta_time, next_direction=None, **kwargs):
        pos = move_from(self.pos, next_direction)
        result = Laman(self.vitality, pos, next_direction, self.lives, self.score)
        return result

    def get_update_interval(self, world=None, **kwargs):
        # TODO: check if it's using correct position
        return 137 if world.map_at(self.pos) in [PILL, POWER_PILL, FRUIT_LOCATION] else 127


GHOST_SPEEDS = [130, 132, 134, 136]
GHOST_FRIGHTENED_SPEEDS = [195, 198, 201, 204]


class Ghost:
    def __init__(self, vitality, pos, direction, index):
        self.vitality = vitality
        self.pos = pos
        self.direction = direction
        self.index = index

    def next_self(self, delta_time, world=None, **kwargs):
        turns = direction_turns(self.direction)
        ways_to_go = [d for d in turns + [self.direction] if can_move(world, self.pos, d)]
        if len(ways_to_go) == 0:
            self.direction = direction_back(self.direction)
        elif len(ways_to_go) == 1:
            self.direction = ways_to_go[0]
        else:
            choices = [(d, manhattan_distance(move_from(self.pos, d), world.laman.pos)) for d in ways_to_go]
            self.direction = max(choices, key=lambda x: x[1]) [0]

        return Ghost(self.vitality, move_from(self.pos, self.direction), self.direction, self.index)

    def get_update_interval(self, **kwargs):
        if self.vitality == GHOST_FRIGHTENED:
            return GHOST_FRIGHTENED_SPEEDS[self.index]
        return GHOST_SPEEDS[self.index]


class World:
    def __init__(self, map, laman, ghosts, fruit_status, loop=None):
        self.fruits = fruit_status
        self.ghosts = ghosts
        self.laman = laman
        self.map = map
        self.fruit_status = fruit_status

        self.utc = 0
        self.level = int(len(map) * len(map[0]) / 100)
        self.pill_count = 0<commit_msg>A couple of critical errors<commit_after>import copy

WALL = 0
EMPTY = 1
PILL = 2
POWER_PILL = 3
FRUIT_LOCATION = 4
LAMAN_START = 5
GHOST_START = 6

GHOST_STANDARD = 0
GHOST_FRIGHTENED = 1
GHOST_INVISIBLE = 2

UP = 0
RIGHT = 1
DOWN = 2
LEFT = 3

DIRECTION_NAMES = {
    UP: 'UP',
    RIGHT: 'RIGHT',
    LEFT: 'LEFT',
    DOWN: 'DOWN',
}

FRUIT_SCORES = [100,300,500,500,700,700,1000,1000,2000,2000,3000,3000,5000]
GHOST_SCORES = [200, 400, 800, 1600]


def move_from(position, direction):
    """
    position, direction -> new position
    """
    if direction == UP:
        return position[0]-1, position[1]
    if direction == RIGHT:
        return position[0], position[1]+1
    if direction == DOWN:
        return position[0]+1, position[1]
    if direction == LEFT:
        return position[0], position[1]-1
    raise ValueError('Wrong direction: {}'.format(direction))


def can_move(world, pos, direction):
    return world.map_at(move_from(pos, direction)) != WALL


def manhattan_distance(pos1, pos2):
    return abs(pos1[0]-pos2[0]) + abs(pos1[1]-pos2[1])


def direction_turns(d):
    if d in [LEFT, RIGHT]:
        return [UP, DOWN]
    else:
        return [LEFT, RIGHT]


def direction_back(d):
    return (d+2) % 4


def cell_score(pos, world):
    c = world.map_at(pos)
    if c == PILL:
        return 10
    if c == POWER_PILL:
        return 50
    if c == FRUIT_LOCATION and world.is_fruit_on():
        if world.level > 12:
            return 5000
        else:
            return FRUIT_SCORES[world.level]
    return 0


class Temporary:
    """
    Something influenced by time.
    """
    def get_update_interval(self, **kwargs):
        raise ValueError('You really need to define this')

    def next_self(self, time_delta, **kwargs):
        """
        The method you need to define: what changes?
        :return: the new self
        """
        raise ValueError('What is the point of being time-dependent then?')


class Loop:
    class Entry:
        def __init__(self, mortal, **kwargs):
            self.mortal = mortal
            self.ticks_till_next = mortal.get_update_interval(**kwargs)

        def next_entry(self, mortal, time_delta, **kwargs):
            result = Loop.Entry(mortal, **kwargs)
            result.ticks_till_next = self.ticks_till_next - time_delta
            if result.ticks_till_next < 0:
                raise AssertionError("Another guy missed his time by {}: {}".format(mortal, -result.ticks_till_next))
            return result

    def __init__(self, tracked=None):
        self.tracked = tracked or []

    def add_tracked(self, t, **kwargs):
        self.tracked.append(Loop.Entry(t, **kwargs))

    def entries(self):
        return [e.mortal for e in self.tracked]

    def next_tick_in(self):
        return min([t.ticks_till_next for t in self.tracked])

    def next_self(self, delta_time, mortal_clones=None, **kwargs):
        """
        :param mortal_clones: The pre-filled clones of current objects (maybe with already changed state) to use instead
        stored, immutable copies. A hack to allow La-Man to modify "future Ghosts".
        :type mortal_clones: list(Temporal)
        """
        new_tracked = []
        i = 0
        for t in self.tracked:
            if t.ticks_till_next < delta_time:
                raise AssertionError('Poor guy missed its time: ' + str(t))
            mortal = mortal_clones[i] if mortal_clones and mortal_clones[i] else t.mortal
            if t.ticks_till_next == delta_time:
                new_mortal = mortal.next_self(delta_time, **kwargs)
                new_tracked.append(Loop.Entry(new_mortal, **kwargs))
            else:
                e = t.next_entry(mortal, delta_time, **kwargs)
                new_tracked.append(e)
            i += 1
        return Loop(new_tracked)


class Laman:
    def __init__(self, vitality, pos, direction, lives, score, ghosts_eaten=0):
        self.vitality, self.pos, self.direction, self.lives, self.score = vitality, pos, direction, lives, score
        self.ghosts_eaten = ghosts_eaten
        self.game_over = False

    def ghost_score(self):
        return GHOST_SCORES[-1] if self.ghosts_eaten >= 4 else GHOST_SCORES[self.ghosts_eaten]

    def next_self(self, delta_time, next_direction=None, **kwargs):
        pos = move_from(self.pos, next_direction)
        result = Laman(self.vitality, pos, next_direction, self.lives, self.score)
        return result

    def get_update_interval(self, world=None, **kwargs):
        # TODO: check if it's using correct position
        return 137 if world.map_at(self.pos) in [PILL, POWER_PILL, FRUIT_LOCATION] else 127

    def __str__(self):
        return 'Lambda-Man {}'.format(self.pos)


GHOST_SPEEDS = [130, 132, 134, 136]
GHOST_FRIGHTENED_SPEEDS = [195, 198, 201, 204]


class Ghost:
    def __init__(self, vitality, pos, direction, index):
        self.vitality = vitality
        self.pos = pos
        self.direction = direction
        self.index = index

    def next_self(self, delta_time, world=None, **kwargs):
        turns = direction_turns(self.direction)
        ways_to_go = [d for d in turns + [self.direction] if can_move(world, self.pos, d)]
        if len(ways_to_go) == 0:
            self.direction = direction_back(self.direction)
        elif len(ways_to_go) == 1:
            self.direction = ways_to_go[0]
        else:
            choices = [(d, manhattan_distance(move_from(self.pos, d), world.laman.pos)) for d in ways_to_go]
            self.direction = min(choices, key=lambda x: x[1]) [0]

            # if len(choices) > 1:
            #     choice_names = ','.join([DIRECTION_NAMES[d] for d in ways_to_go])
            #     dname = DIRECTION_NAMES[self.direction]
            #     print('Choice point between {}; chose {}'.format(choice_names, dname))

        return Ghost(self.vitality, move_from(self.pos, self.direction), self.direction, self.index)

    def get_update_interval(self, **kwargs):
        if self.vitality == GHOST_FRIGHTENED:
            return GHOST_FRIGHTENED_SPEEDS[self.index]
        return GHOST_SPEEDS[self.index]

    def __str__(self):
        return 'Ghost #{} {}'.format(self.index, self.pos)


class World:
    def __init__(self, map, laman, ghosts, fruit_status, loop=None):
        self.fruits = fruit_status
        self.ghosts = ghosts
        self.laman = laman
        self.map = map
        self.fruit_status = fruit_status

        self.utc = 0
        self.level = int(len(map) * len(map[0]) / 100)
        self.pill_count = 0
{'fraction_non_alphanumeric': 0.11118210862619808, 'fraction_numerical': 0.02484025559105431, 'mean_word_length': 2.5764067409311626, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6488805', 'n_tokens_mistral': 4461, 'n_tokens_neox': 4050, 'n_words': 1050}