コード例 #1
0
ファイル: algorithm.py プロジェクト: Tordensky/laby
    def __init__(self, lab):
        # The start position
        self.x = 0
        self.y = 0

        # A map over the tiles we know about.
        # Implemented as a double-dict (A dict of dicts).
        # The key x, y is the position.
        # 1, 0 is one tile to the west.
        # -1, 0 is one tile to the east.
        # 0, 1 is one tile to the north.
        # 0, -1 is one tile to the south.
        # The value is what we know about the tile.
        # A list of value meanings:
        # 0 = unknown
        # 1 = tile
        # 2 = wall
        # 3 = trap
        # 4 = toby
        # 5 = grue
        # 6 = start_block
        # 7 = next_block
        # 8 = third_block
        # ....
        self.map = DoubleDict()
        self.map.set(self.x, self.y, 6) # Set the starting tile
        self.next_node = 6 # Sets the first node number

        # Holds the labyrinth object
        self.lab = lab

        # How many lives the palyer has left
        self.lives = 5

        # Are there any grues biting the player?
        self.biting_grue = False
コード例 #2
0
ファイル: algorithm.py プロジェクト: Tordensky/laby
class Algorithm:
    def __init__(self, lab):
        # The start position
        self.x = 0
        self.y = 0

        # A map over the tiles we know about.
        # Implemented as a double-dict (A dict of dicts).
        # The key x, y is the position.
        # 1, 0 is one tile to the west.
        # -1, 0 is one tile to the east.
        # 0, 1 is one tile to the north.
        # 0, -1 is one tile to the south.
        # The value is what we know about the tile.
        # A list of value meanings:
        # 0 = unknown
        # 1 = tile
        # 2 = wall
        # 3 = trap
        # 4 = toby
        # 5 = grue
        # 6 = start_block
        # 7 = next_block
        # 8 = third_block
        # ....
        self.map = DoubleDict()
        self.map.set(self.x, self.y, 6) # Set the starting tile
        self.next_node = 6 # Sets the first node number

        # Holds the labyrinth object
        self.lab = lab

        # How many lives the palyer has left
        self.lives = 5

        # Are there any grues biting the player?
        self.biting_grue = False

    def get_next_node(self):
        self.next_node = self.next_node + 1
        return self.next_node

    def go(self, move, look):
        '''
        Makes the player go in a given direction.
        The first argument is the direction, and has to be
        one of 'north', 'south', 'west' or 'east'.
        The second argument is a boolean value indicating if 
        the player shuld look around afterwards.
        '''
        assert move in ['north', 'south', 'west', 'east']

        # Go to the next tile.
        # Set x and y to the tile we intended to go to.
        if move == 'north':
            tmp = self.lab.north()
            x = self.x
            y = self.y + 1
        elif move == 'south':
            tmp = self.lab.south()
            x = self.x
            y = self.y - 1
        elif move == 'west':
            tmp = self.lab.west()
            x = self.x + 1
            y = self.y
        elif move == 'east':
            tmp = self.lab.east()
            x = self.x - 1
            y = self.y

        # Make shure we stepped into something we know about.
        assert tmp[0] in ['tile', 'wall'], 'I found a ' + tmp[0]
        assert tmp[1] in ['safe', 'trap'], 'I found a ' + tmp[1]
        assert tmp[2] in ['safe', 'grue'], 'I found a ' + tmp[2]

        # What did we go into?
        if tmp[0] == 'tile':
            # Set the new position
            self.y = y
            self.x = x
            if self.map.get(self.x, self.y) == 0:
                self.map.set(self.x, self.y, 1)
        elif tmp[0] == 'wall':
            self.map.set(x, y, 2)
        # Did we go into a trap?
        if tmp[1] == 'trap':
            self.lives = self.lives - 1
        # Did we walk into a grue?
        if tmp[2] == 'grue':
            self.biting_grue = True
            self.remove_grue()

        if look:
            self.look()

    def remove_grue(self):
        assert self.biting_grue, 'Why do we light a match if there is no grue?'

        if self.lab.inventory() > 0:
            self.lab.fire()
            self.biting_grue = False

    def look(self):
        look = self.lab.look()

        for i in look:
            assert i[0] in ['north', 'south', 'east', 'west'], 'Where do you go if you dont go north, south, east or west?'
            assert i[1] in ['tile', 'wall', 'toby'], 'I found a ' + i[1]
            assert i[2] in ['trap', 'safe'], 'I found a ' + i[2]

            # Where are we looking?
            if i[0] == 'north':
                x = self.x
                y = self.y + 1
            elif i[0] == 'south':
                x = self.x
                y = self.y - 1
            elif i[0] == 'west':
                x = self.x + 1
                y = self.y
            elif i[0] == 'east':
                x = self.x - 1
                y = self.y

            # What is around?
            if i[1] == 'tile':
                if self.map.get(x, y) == 0:
                    self.map.set(x, y, 1)
            elif i[1] == 'wall':
                self.map.set(x, y, 2)
            elif i[1] == 'toby':
                self.map.set(x, y, 4)
                # Goto Toby immedeatly.
                self.goto(x, y, 4, False)
            # Are there any traps around?
            if i[2] == 'trap':
                self.map.set(x, y, 3)

    def goto(self, x, y, node_number, look):
        '''
        Tries to go to a position x, y.
        Returns True if we can,
        returns False if we meet a wall.
        returns False if we try to go into another rectangle.
        returns false if ...
        '''
        #GO EAST
        while self.x > x:
            if not self.map.get(self.x-1, self.y) in [0, 1, node_number]:
                return False
            tmpx = self.x
            self.go('east', look)
            if self.x != tmpx-1:
                return False
        #GO WEST
        while self.x < x:
            if not self.map.get(self.x+1, self.y) in [0, 1, node_number]:
                return False
            tmpx = self.x
            self.go('west', look)
            if self.x != tmpx+1:
                return False
        #GO SOUTH
        while self.y > y:
            if not self.map.get(self.x, self.y-1) in [0, 1, node_number]:
                return False
            tmpy = self.y
            self.go('south', look)
            if self.y != tmpy-1:
                return False
        #GO NORTH
        while self.y < y:
            if not self.map.get(self.x, self.y+1) in [0, 1, node_number]:
                return False
            tmpy = self.y
            self.go('north', look)
            if self.y != tmpy+1:
                return False
        return True

    def search(self):
        '''
        Start the search algorithm.
        '''

        #The current tile need to be numbered for the function to search out the current rectange.
        #Numbering of the first tile is done in the __init__() function.
        #Numbering of the rest of the tiles are done in check_tile().

        self.find_rectangle()
        self.search_neighbor_rectangles()

    def find_rectangle(self):
        self.foundNorth = False
        self.foundWest = False
        self.foundSouth = False
        self.foundEast = False

        self.lineWestX = self.x
        self.lineEastX = self.x
        self.lineSouthY = self.y
        self.lineNorthY = self.y

        self.rectangle_number = self.map.get(self.x, self.y)

        print 'Completing rectangle ' + str(self.rectangle_number)

        # Check that we are not in a narrow corridor
        self.look()
        if self.map.get(self.x, self.y + 1) != 1:
            self.foundNorth = True
        if self.map.get(self.x, self.y - 1) != 1:
            self.foundSouth = True
        if self.map.get(self.x + 1, self.y) != 1:
            self.foundWest = True
        if self.map.get(self.x - 1, self.y) != 1:
            self.foundEast = True

        #Dont search-out a rectangle if it is 1 by 1
        if not((self.foundNorth and self.foundSouth) or (self.foundWest and self.foundEast)):
            if not self.foundNorth:
                #Start the spiral-search
                self.box_search_north()
            elif not self.foundWest:
                #Start the spiral-search
                self.box_search_west()
            elif not self.foundSouth:
                #Start the spiral-search
                self.box_search_south()
            elif not self.foundEast:
                #Start the spiral-search
                self.box_search_east()

        print 'Rectangle found'

    def check_tile(self, tile_x, tile_y, rec_x, rec_y, tile):
        '''
        Check a tile if you can run a rectange function on it.

        (tileX, tileY) is the position of the tile we are checking.
        (recX, recY) is the position of the closest tile in the current rectangle.
        Use tile = 1 if you want to go to tiles that has not been searched out.
        Use tile = 3 if you want to go through traps.
        '''
        assert (tile_x == rec_x + 1) or (tile_x == rec_x - 1) or (tile_y == rec_y + 1) or (tile_y == rec_y - 1), 'The tiles have to be close.'

        #Store the current rectangle number
        rectangleNumber = self.map.get(self.x, self.y)
        
        # Which way are we going?
        if tile == 3:
            if tile_x == rec_x + 1:
                way = 'west'
            elif tile_x == rec_x - 1:
                way = 'east'
            elif tile_y == rec_y + 1:
                way = 'north'
            elif tile_y == rec_y - 1:
                way = 'south'

        # Is this a tile we have not visited?
        if self.map.get(tile_x, tile_y) == tile:
            # Get a nodenumber for the next rectangle.
            next_node = self.get_next_node()

            #Go close to the next rectangle
            self.goto(rec_x, rec_y, rectangleNumber, False)
            #Dissarm
            if (self.lives == 1) and (tile == 3):
                self.lab.disarm(way)
            #Set next rectangle number
            self.map.set(tile_x, tile_y, next_node)
            #Go into next rectangle
            self.goto(tile_x, tile_y, next_node, False)
            # Check that we are where we are suppose to be.
            assert self.map.get(self.x, self.y) == next_node, 'this is not the next node'
            #Complete the next rectangle
            self.search()
            #Go back
            self.goto(tile_x, tile_y, next_node, False)
            self.goto(rec_x, rec_y, rectangleNumber, False)

    def search_neighbor_rectangles(self):
        # These are the current rectangle. Note that self.lineSouthY, ... can change under recursive calls
        lineSouthY = self.lineSouthY
        lineNorthY = self.lineNorthY
        lineWestX = self.lineWestX
        lineEastX = self.lineEastX

        #Check adjacent tiles (AKA depth first search)
        for x in range(lineEastX, lineWestX + 1):
            self.check_tile(x, lineNorthY+1, x, lineNorthY, 1)

        for x in range(lineEastX, lineWestX + 1):
            self.check_tile(x, lineSouthY-1, x, lineSouthY, 1)

        for y in range(lineSouthY, lineNorthY + 1):
            self.check_tile(lineEastX-1, y, lineEastX, y, 1)

        for y in range(lineSouthY, lineNorthY + 1):
            self.check_tile(lineWestX+1, y, lineWestX, y, 1)

        # If we have to disarm any adjacent tiles we do it after we have tried all the other ways
        for x in range(lineEastX, lineWestX+1):
            self.check_tile(x, lineNorthY+1, x, lineNorthY, 3)

        for x in range(lineEastX, lineWestX+1):
            self.check_tile(x, lineSouthY-1, x, lineSouthY, 3)

        for y in range(lineSouthY, lineNorthY + 1):
            self.check_tile(lineEastX-1, y, lineEastX, y, 3)

        for y in range(lineSouthY, lineNorthY+1):
            self.check_tile(lineWestX+1, y, lineWestX, y, 3)

#############################################################
#  The recursice rectangle search functions:
##############################################################
    def box_search_north(self):
        assert not self.foundNorth, 'north is already found'

        #Do we need to seach?
        #if self.map.get(self.lineEastX, self.lineNorthY + 1) in [2, 3]:
         #   self.foundNorth = True
        #Goto north east
        self.goto(self.lineEastX, self.lineNorthY, self.rectangle_number, False)
        if not self.goto(self.lineEastX, self.lineNorthY + 1, self.rectangle_number, True):
            self.foundNorth = True
        #Search north line
        elif not self.goto(self.lineWestX, self.lineNorthY + 1, self.rectangle_number, True):
            self.foundNorth = True
            self.go('south', False)

        if not self.foundNorth:
            #Expand the rectangle towards north
            self.lineNorthY = self.lineNorthY + 1
            #Fill the matrix
            for x in range(self.lineEastX, self.lineWestX + 1):
                self.map.set(x, self.lineNorthY, self.rectangle_number)

        # Where to search next
        if not self.foundWest:
            self.box_search_west()
        elif not self.foundNorth:
            self.box_rsearch_north()
        elif not self.foundSouth:
            self.box_search_south()
        elif not self.foundEast:
            self.box_rsearch_east()
        # else: return to complete_rectangle

    def box_rsearch_north(self):
        assert not self.foundNorth, 'north is already found'

        #Goto north west
        self.goto(self.lineWestX, self.lineNorthY, self.rectangle_number, False)
        if not self.goto(self.lineWestX, self.lineNorthY + 1, self.rectangle_number, True):
            self.foundNorth = True

        #Search north line
        elif not self.goto(self.lineEastX, self.lineNorthY + 1, self.rectangle_number, True):
            self.foundNorth = True
            self.go('south', False)

        if not self.foundNorth:
            #Expand the rectangle towards north
            self.lineNorthY = self.lineNorthY + 1
            #Fill the matrix
            for x in range(self.lineEastX, self.lineWestX + 1):
                self.map.set(x, self.lineNorthY, self.rectangle_number)

        # Where to search next
        if not self.foundEast:
            self.box_rsearch_east()
        elif not self.foundNorth:
            self.box_search_north()
        elif not self.foundSouth:
            self.box_rsearch_south()
        elif not self.foundWest:
            self.box_search_west()
        # else: return to complete_rectangle

    def box_search_west(self):
        assert not self.foundWest, 'west is already found'

        #Goto west north
        self.goto(self.lineWestX, self.lineNorthY, self.rectangle_number, False)
        if not self.goto(self.lineWestX + 1, self.lineNorthY, self.rectangle_number, True):
            self.foundWest = True

        #Search west line
        elif not self.goto(self.lineWestX + 1, self.lineSouthY, self.rectangle_number, True):
            self.foundWest = True
            self.go('east', False)

        if not self.foundWest:
            #Expand the rectangle towards west
            self.lineWestX = self.lineWestX + 1
            #Fill the matrix
            for y in range(self.lineSouthY, self.lineNorthY + 1):
                self.map.set(self.lineWestX, y, self.rectangle_number)
        
        # Where to search next
        if not self.foundSouth:
            self.box_search_south()
        elif not self.foundWest:
            self.box_rsearch_west()
        elif not self.foundEast:
            self.box_search_east()
        elif not self.foundNorth:
            self.box_rsearch_north()
        # else: return to complete_rectangle

    def box_rsearch_west(self):
        assert not self.foundWest, 'west is already found'

        #Goto west south
        self.goto(self.lineWestX, self.lineSouthY, self.rectangle_number, False)
        if not self.goto(self.lineWestX + 1, self.lineSouthY, self.rectangle_number, True):
            self.foundWest = True

        elif not self.goto(self.lineWestX +1, self.lineNorthY, self.rectangle_number, True):
            self.foundWest = True
            self.go('east', False)

        if not self.foundWest:
            #Expand the rectangle towards west
            self.lineWestX = self.lineWestX + 1
            #Fill the matrix
            for y in range(self.lineSouthY, self.lineNorthY + 1):
                self.map.set(self.lineWestX, y, self.rectangle_number)

        # Where to serach next
        if not self.foundNorth:
            self.box_rsearch_north()
        elif not self.foundWest:
            self.box_search_west()
        elif not self.foundEast:
            self.box_rsearch_east()
        elif not self.foundSouth:
            self.box_search_south()
        # else: return to complete_rectangle

    def box_search_south(self):
        assert not self.foundSouth, 'south is already found'

        #Goto south west
        self.goto(self.lineWestX, self.lineSouthY, self.rectangle_number, False)
        if not self.goto(self.lineWestX, self.lineSouthY - 1, self.rectangle_number, True):
            self.foundSouth = True

        #Search south line
        elif not self.goto(self.lineEastX, self.lineSouthY - 1, self.rectangle_number, True):
            self.foundSouth = True
            self.go('north', False)

        if not self.foundSouth:
            #Expand the rectangle towards south
            self.lineSouthY = self.lineSouthY - 1
            #Fill the matrix
            for x in range(self.lineEastX, self.lineWestX + 1):
                self.map.set(x, self.lineSouthY, self.rectangle_number)
            
        # Where to search next
        if not self.foundEast:
            self.box_search_east()
        elif not self.foundSouth:
            self.box_rsearch_south()
        elif not self.foundNorth:
            self.box_search_north()
        elif not self.foundWest:
            self.box_rsearch_west()
        # else: return to complete_rectangle

    def box_rsearch_south(self):
        assert not self.foundSouth, 'south is already found'

        #Goto south east
        self.goto(self.lineEastX, self.lineSouthY, self.rectangle_number, False)
        if not self.goto(self.lineEastX, self.lineSouthY - 1, self.rectangle_number, True):
            self.foundSouth = True

        #Search south line
        elif not self.goto(self.lineWestX, self.lineSouthY - 1, self.rectangle_number, True):
            self.foundSouth = True
            self.go('north', False)

        if not self.foundSouth:
            #Expand the rectangle toward south
            self.lineSouthY = self.lineSouthY - 1
            #Fill the matrix
            for x in range(self.lineEastX, self.lineWestX + 1):
                self.map.set(x, self.lineSouthY, self.rectangle_number)
        
        # Where to serach next
        if not self.foundWest:
            self.box_rsearch_west()
        elif not self.foundSouth:
            self.box_search_south()
        elif not self.foundNorth:
            self.box_rsearch_north()
        elif not self.foundEast:
            self.box_search_east()
        # else: return to complete_rectangle

    def box_search_east(self):
        assert not self.foundEast, 'east is already found'

        #Goto east south
        self.goto(self.lineEastX, self.lineSouthY, self.rectangle_number, False)
        if not self.goto(self.lineEastX - 1, self.lineSouthY, self.rectangle_number, True):
            self.foundEast = True

        #Search east line
        elif not self.goto(self.lineEastX - 1, self.lineNorthY, self.rectangle_number, True):
            self.foundEast = True
            self.go('west', False)

        if not self.foundEast:
            #Expand the rectangle towards east
            self.lineEastX = self.lineEastX - 1
            #Fill the matrix
            for y in range(self.lineSouthY, self.lineNorthY + 1):
                self.map.set(self.lineEastX, y, self.rectangle_number)

        # Where to search next
        if not self.foundNorth:
            self.box_search_north()
        elif not self.foundEast:
            self.box_rsearch_east()
        elif not self.foundWest:
            self.box_search_west()
        elif not self.foundSouth:
            self.box_rsearch_south()
        # else: return to complete_rectangle

    def box_rsearch_east(self):
        assert not self.foundEast, 'east is already found'

        #Goto east north
        self.goto(self.lineEastX, self.lineNorthY, self.rectangle_number, False)
        if not self.goto(self.lineEastX - 1, self.lineNorthY, self.rectangle_number, True):
            self.foundEast = True

        #Search east line
        elif not self.goto(self.lineEastX - 1, self.lineSouthY, self.rectangle_number, True):

            self.foundEast = True
            self.go('west', False)

        if not self.foundEast:
            #Expand the rectange towards east
            self.lineEastX = self.lineEastX - 1
            #Fill the matrix
            for y in range(self.lineSouthY, self.lineNorthY + 1):
                self.map.set(self.lineEastX, y, self.rectangle_number)

        # Where to search next
        if not self.foundSouth:
            self.box_rsearch_south()
        elif not self.foundEast:
            self.box_search_east()
        elif not self.foundWest:
            self.box_rsearch_west()
        elif not self.foundNorth:
            self.box_search_north()