コード例 #1
0
def rotate_track(blocks: list, rotation: int) -> list:
    '''
    Rotates the entire track by a given cardinal rotation.
    The rotation happens inside the standard stadium arena size (32, 32, 32).

    The rotation factors in the fact that blocks may
    occupy more than one spot on the map, by rotating
    the block offsets first and then adding the maximum X and Z component
    offset to the original position rotation.

    Args:
        blocks (list): a list of pygbx.MapBlock's
        rotation (int): the cardinal rotation to rotate by

    Returns:
        list: the rotated blocks
    '''
    for block in blocks:
        rotated, _, _ = rotate_block_offsets(
            [block.position, [0, 0, 0], [31, 0, 31]], rotation)
        rotated = rotated[0]

        try:
            offsets = STADIUM_BLOCK_OFFSETS[block.name]
            offsets, _, _ = rotate_block_offsets(offsets, block.rotation)
            _, xoff, zoff = rotate_block_offsets(offsets, rotation)
            block.position = Vector3(rotated[0] + xoff, rotated[1],
                                     rotated[2] + zoff)
        except KeyError:
            block.position = Vector3(rotated[0], rotated[1], rotated[2])

        block.rotation = (block.rotation + rotation) % 4

    return blocks
コード例 #2
0
ファイル: bytereader.py プロジェクト: lostpebble/pygbx
 def read_vec3(self):
     """Reads 12 bytes as 3 floats from the buffer and packs them into a Vector3.
     
     Returns:
         the vector read from the buffer
     """
     return Vector3(self.read_float(), self.read_float(), self.read_float())
コード例 #3
0
def occupied_track_positions(track):
    positions = {}
    for block in track:
        name = get_block_name(block[BID], STADIUM_BLOCKS)
        if not name:
            continue

        try:
            if is_on_ground(block) and name in DYNAMIC_GROUND_OFFSETS:
                offsets = DYNAMIC_GROUND_OFFSETS[name]
            else:
                offsets = STADIUM_BLOCK_OFFSETS[name]
        except KeyError:
            continue

        offsets, _, _ = rotate_block_offsets(offsets, block[BROT])
        block_positions = []
        for offset in offsets:
            block_positions.append(
                Vector3(block[BX] + offset[0], block[BY] + offset[1],
                        block[BZ] + offset[2]))

        positions[block] = block_positions

    return positions
コード例 #4
0
ファイル: block_utils.py プロジェクト: w1lla/TMTrackNN
def block_from_tup(tup):
    block = MapBlock()
    block.name = get_block_name(tup[BID], STADIUM_BLOCKS)
    block.rotation = tup[BROT]
    block.position = Vector3(tup[BX], tup[BY], tup[BZ])
    if len(tup) > 5:
        block.flags = 0x1000 if tup[BFLAGS] == 1 else 0
    return block
コード例 #5
0
def rotate_track(blocks, rotation):
    for block in blocks:
        rotated, _, _ = rotate_block_offsets(
            [block.position, [0, 0, 0], [31, 0, 31]], rotation)
        rotated = rotated[0]

        try:
            offsets = STADIUM_BLOCK_OFFSETS[block.name]
            offsets, _, _ = rotate_block_offsets(offsets, block.rotation)
            _, xoff, zoff = rotate_block_offsets(offsets, rotation)
            block.position = Vector3(rotated[0] + xoff, rotated[1],
                                     rotated[2] + zoff)
        except KeyError:
            block.position = Vector3(rotated[0], rotated[1], rotated[2])

        block.rotation = (block.rotation + rotation) % 4

    return blocks
コード例 #6
0
def block_from_tup(tup: tuple) -> MapBlock:
    '''
    Converts a tuple to a MapBlock instance.

    Args:
        block (tuple): the tuple to convert

    Returns:
        MapBlock: the converted block
    '''
    block = MapBlock()
    block.name = get_block_name(tup[BID], STADIUM_BLOCKS)
    block.rotation = tup[BROT]
    block.position = Vector3(tup[BX], tup[BY], tup[BZ])
    if len(tup) > 5:
        block.flags = 0x1000 if tup[BFLAGS] == 1 else 0
    return block
コード例 #7
0
def occupied_track_positions(track: list) -> dict:
    '''
    Produces a dict of each block and its occupied positions.

    Some blocks may have different offsets depending on whether
    they are on the ground or not.

    Args:
        track (list): the list of block tuples
    
    Returns:
        dict: blocks as keys and their occupied positions as values
    '''
    positions = {}
    for block in track:
        name = get_block_name(block[BID], STADIUM_BLOCKS)
        if not name:
            continue

        try:
            if is_on_ground(block) and name in DYNAMIC_GROUND_OFFSETS:
                offsets = DYNAMIC_GROUND_OFFSETS[name]
            else:
                offsets = STADIUM_BLOCK_OFFSETS[name]
        except KeyError:
            continue

        offsets, _, _ = rotate_block_offsets(offsets, block[BROT])
        block_positions = []
        for offset in offsets:
            block_positions.append(
                Vector3(block[BX] + offset[0], block[BY] + offset[1],
                        block[BZ] + offset[2]))

        positions[block] = block_positions

    return positions
コード例 #8
0
    def build(self, track_len: int, use_seed: bool=False, failsafe: bool=True, verbose: bool=True,
            put_finish: bool=True, progress_callback=None, map_size: tuple=(20, 8, 20)):
        '''
        Builds the track according to the parameters.

        Args:
            track_len (int): the track length, in blocks
            use_seed (bool): whether to use a random seed from the seed data
            failsafe (bool): whether to enable various checking heuristics
            verbose (bool): print additional information while building
            put_finish (bool): whether to put a finish as the last block
            progress_callback: a function that is called whenever a new block is placed
            map_size (tuple): the map size to build the track in
        
        Returns:
            list: the resulting track
        '''
        self.running = True

        fixed_y = random.randrange(1, 7)
        if not self.gmap:
            self.gmap = GameMap(Vector3(map_size[0], map_size[1], map_size[2]), Vector3(0, fixed_y, 0))

        if use_seed and self.seed_data:
            self.gmap.track = self.sample_seed(3)
        elif len(self.gmap) == 0:
            self.gmap.add(self.random_start_block())

        self.gmap.update()

        blacklist = []
        current_block_preds = None
        while len(self.gmap) < track_len:
            if not self.running:
                return None

            end = len(self.gmap) == track_len - 1
            if len(blacklist) >= 10 or (len(blacklist) == 1 and end):
                if verbose:
                    print('More than 10 fails, going back.')

                if len(self.gmap) > track_len - 5:
                    back = 5
                elif end:
                    back = 10
                else:
                    back = random.randrange(2, 6)

                end_idx = min(len(self.gmap) - 1, back)
                if end_idx > 0:
                    del self.gmap.track[-end_idx:len(self.gmap)]

                blacklist = []
                current_block_preds = None

            X_block, X_position = self.prepare_inputs()

            block_override = FINISH_LINE_BLOCK if end and put_finish else -1

            next_block, current_block_preds = self.predict_next_block(
                X_block[:], X_position[:], block_override=block_override, blacklist=blacklist, block_preds=current_block_preds
            )

            self.gmap.add(next_block)
            decoded = self.gmap.decoded

            if failsafe:
                # Do not exceed map size
                if self.gmap.exceeds_map_size():
                    blacklist.append(next_block[BID])
                    self.gmap.pop()
                    continue

                occ = occupied_track_vectors([decoded[-1]])
                if len(occ) > 0:
                    min_y_block = min(occ, key=lambda pos: pos.y).y
                else:
                    min_y_block = decoded[-1][BY]

                # If we are above the ground
                if min_y_block > 1 and next_block[BID] in GROUND_BLOCKS:
                    blacklist.extend(GROUND_BLOCKS)
                    self.gmap.pop()
                    continue

                if (intersects(decoded[:-1], decoded[-1]) or  # Overlaps the track
                        (next_block[BID] == FINISH_LINE_BLOCK and not end)):  # Tries to put finish before desired track length
                    blacklist.append(next_block[BID])
                    self.gmap.pop()
                    continue

                if self.score_prediction(self.gmap[-2], next_block) < 5:
                    blacklist.append(next_block[BID])
                    self.gmap.pop()
                    continue

            blacklist = []
            current_block_preds = None

            next_block = (next_block[BID], next_block[BX], next_block[BY],
                          next_block[BZ], next_block[BROT])

            if progress_callback:
                progress_callback(len(self.gmap), track_len)

            if verbose:
                print(len(self.gmap))

        result_track = self.gmap.center()
        result_track = [block for block in result_track if block[BID] != STADIUM_BLOCKS['StadiumGrass']]
        return result_track
コード例 #9
0
    def build(self,
              track_len,
              use_seed=False,
              failsafe=True,
              verbose=True,
              save=True,
              put_finish=True,
              progress_callback=None,
              map_size=(20, 8, 20)):

        self.running = True

        fixed_y = random.randrange(1, 7)
        if not self.gmap or self.reset:
            self.gmap = GameMap(Vector3(map_size[0], map_size[1], map_size[2]),
                                Vector3(0, fixed_y, 0))

        if use_seed and self.seed_data:
            self.gmap.track = self.sample_seed(3)
        elif len(self.gmap) == 0:
            self.gmap.add(self.random_start_block())

        print(self.gmap.track)
        self.gmap.update()

        blacklist = []
        current_block_preds = None
        while len(self.gmap) < track_len:
            if not self.running:
                return None

            end = len(self.gmap) == track_len - 1
            if len(blacklist) >= 10 or (len(blacklist) == 1
                                        and end) and self.reset:
                if verbose:
                    print('More than 10 fails, going back.')

                if len(self.gmap) > track_len - 5:
                    back = 5
                elif end:
                    back = 10
                else:
                    back = random.randrange(2, 6)

                end_idx = min(len(self.gmap) - 1, back)
                if end_idx > 0:
                    del self.gmap.track[-end_idx:len(self.gmap)]

                blacklist = []
                current_block_preds = None

            X_block, X_position = self.prepare_inputs()

            override_block = FINISH_LINE_BLOCK if end and put_finish else -1

            next_block, current_block_preds = self.predict_next_block(
                X_block[:],
                X_position[:],
                override_block,
                blacklist=blacklist,
                block_preds=current_block_preds)

            self.gmap.add(next_block)
            decoded = self.gmap.decoded

            if failsafe:
                # Do not exceed map size
                if self.gmap.exceeds_map_size():
                    blacklist.append(next_block[BID])
                    self.gmap.pop()
                    continue

                occ = occupied_track_vectors([decoded[-1]])
                if len(occ) > 0:
                    min_y_block = min(occ, key=lambda pos: pos.y).y
                else:
                    min_y_block = decoded[-1][BY]

                # If we are above the ground
                if min_y_block > 1 and next_block[BID] in GROUND_BLOCKS:
                    blacklist.extend(GROUND_BLOCKS)
                    self.gmap.pop()
                    continue

                if (intersects(decoded[:-1], decoded[-1])
                        or  # Overlaps the track
                    (next_block[BID] == FINISH_LINE_BLOCK and not end)
                    ):  # Tries to put finish before desired track length
                    blacklist.append(next_block[BID])
                    self.gmap.pop()
                    continue

                if self.score_prediction(self.gmap[-2], next_block) < 5:
                    blacklist.append(next_block[BID])
                    self.gmap.pop()
                    continue

            blacklist = []
            current_block_preds = None

            next_block = (next_block[BID], next_block[BX], next_block[BY],
                          next_block[BZ], next_block[BROT])

            if progress_callback:
                progress_callback(len(self.gmap), track_len)

            if verbose:
                print(len(self.gmap))

        result_track = self.gmap.center()
        result_track = [
            block for block in result_track
            if block[BID] != STADIUM_BLOCKS['StadiumGrass']
        ]
        return result_track