Пример #1
0
class HamiltonSolver(BaseSolver):
    def __init__(self, snake, shortcuts=True):
        if snake.map.num_rows % 2 != 0 or snake.map.num_cols % 2 != 0:
            raise ValueError("num_rows and num_cols must be even.")
        super().__init__(snake)
        self.__shortcuts = shortcuts
        self.__path_solver = PathSolver(snake)
        self.__table = [[_TableCell() for _ in range(snake.map.num_cols)]
                        for _ in range(snake.map.num_rows)]
        self.__build_cycle()

    @property
    def table(self):
        return self.__table

    def next_direc(self):
        head = self.snake.head()
        nxt_direc = self.__table[head.x][head.y].direc

        # Take shorcuts when the snake is not too long
        if self.__shortcuts and self.snake.len() < 0.5 * self.map.capacity:
            path = self.__path_solver.shortest_path_to_food()
            if path:
                tail, nxt, food = self.snake.tail(), head.adj(
                    path[0]), self.map.food
                tail_idx = self.__table[tail.x][tail.y].idx
                head_idx = self.__table[head.x][head.y].idx
                nxt_idx = self.__table[nxt.x][nxt.y].idx
                food_idx = self.__table[food.x][food.y].idx
                # Exclude one exception
                if not (len(path) == 1 and abs(food_idx - tail_idx) == 1):
                    head_idx_rel = self.__relative_dist(
                        tail_idx, head_idx, self.map.capacity)
                    nxt_idx_rel = self.__relative_dist(tail_idx, nxt_idx,
                                                       self.map.capacity)
                    food_idx_rel = self.__relative_dist(
                        tail_idx, food_idx, self.map.capacity)
                    if nxt_idx_rel > head_idx_rel and nxt_idx_rel <= food_idx_rel:
                        nxt_direc = path[0]

        return nxt_direc

    def __build_cycle(self):
        """Build a hamiltonian cycle on the map."""
        path = self.__path_solver.longest_path_to_tail()
        cur, cnt = self.snake.head(), 0
        for direc in path:
            self.__table[cur.x][cur.y].idx = cnt
            self.__table[cur.x][cur.y].direc = direc
            cur = cur.adj(direc)
            cnt += 1
        tail = self.snake.tail()
        self.__table[tail.x][tail.y].idx = cnt
        self.__table[tail.x][tail.y].direc = self.snake.direc

    def __relative_dist(self, ori, x, size):
        if ori > x:
            x += size
        return x - ori
Пример #2
0
 def __init__(self, snake):
     super().__init__(snake)
     self._path_solver = PathSolver(snake)
     self.open_ = [Node(self.snake.head(), 0, 0, 0, self.snake.head())]
     self.closed_ = []
     self.closed_dict = {}
     self.flag_new = True
     self.path = []
Пример #3
0
 def __init__(self, snake, shortcuts=True):
     if snake.map.num_rows % 2 != 0 or snake.map.num_cols % 2 != 0:
         raise ValueError("num_rows and num_cols must be even.")
     super().__init__(snake)
     self.__shortcuts = shortcuts
     self.__path_solver = PathSolver(snake)
     self.__table = [[_TableCell() for _ in range(snake.map.num_cols)]
                     for _ in range(snake.map.num_rows)]
     self.__build_cycle()
Пример #4
0
    def __init__(self, snake, shortcuts=True):
        if snake.map.num_rows % 2 != 0 or snake.map.num_cols % 2 != 0:
            raise ValueError("num_rows and num_cols must be even.")
        super().__init__(snake)

        self._shortcuts = shortcuts
        self._path_solver = PathSolver(snake)
        self._table = [[_TableCell() for _ in range(snake.map.num_cols)]
                        for _ in range(snake.map.num_rows)]
        self._build_cycle()
Пример #5
0
class GreedySolver(BaseSolver):

    def __init__(self, snake):
        super().__init__(snake)
        self._path_solver = PathSolver(snake)

    def next_direc(self):
        # Create a virtual snake
        s_copy, m_copy = self.snake.copy()

        # Step 1
        self._path_solver.snake = self.snake
        path_to_food = self._path_solver.shortest_path_to_food()

        if path_to_food:
            # Step 2
            s_copy.move_path(path_to_food)
            if m_copy.is_full():
                return path_to_food[0]

            # Step 3
            self._path_solver.snake = s_copy
            path_to_tail = self._path_solver.longest_path_to_tail()
            if len(path_to_tail) > 1:
                return path_to_food[0]

        # Step 4
        self._path_solver.snake = self.snake
        path_to_tail = self._path_solver.longest_path_to_tail()
        if len(path_to_tail) > 1:
            return path_to_tail[0]

        # Step 5
        head = self.snake.head()
        direc, max_dist = self.snake.direc, -1
        for adj in head.all_adj():
            if self.map.is_safe(adj):
                dist = Pos.manhattan_dist(adj, self.map.food)
                if dist > max_dist:
                    max_dist = dist
                    direc = head.direc_to(adj)
        return direc
Пример #6
0
class HamiltonSolver(BaseSolver):

    def __init__(self, snake, shortcuts=True):
        if snake.map.num_rows % 2 != 0 or snake.map.num_cols % 2 != 0:
            raise ValueError("num_rows and num_cols must be even.")
        super().__init__(snake)

        self._shortcuts = shortcuts
        self._path_solver = PathSolver(snake)
        self._table = [[_TableCell() for _ in range(snake.map.num_cols)]
                        for _ in range(snake.map.num_rows)]
        self._build_cycle()

    @property
    def table(self):
        return self._table

    def next_direc(self):
        head = self.snake.head()
        nxt_direc = self._table[head.x][head.y].direc

        # Take shorcuts when the snake is not too long
        if self._shortcuts and self.snake.len() < 0.5 * self.map.capacity:
            path = self._path_solver.shortest_path_to_food()
            if path:
                tail, nxt, food = self.snake.tail(), head.adj(path[0]), self.map.food
                tail_idx = self._table[tail.x][tail.y].idx
                head_idx = self._table[head.x][head.y].idx
                nxt_idx = self._table[nxt.x][nxt.y].idx
                food_idx = self._table[food.x][food.y].idx
                # Exclude one exception
                if not (len(path) == 1 and abs(food_idx - tail_idx) == 1):
                    head_idx_rel = self._relative_dist(tail_idx, head_idx, self.map.capacity)
                    nxt_idx_rel = self._relative_dist(tail_idx, nxt_idx, self.map.capacity)
                    food_idx_rel = self._relative_dist(tail_idx, food_idx, self.map.capacity)
                    if nxt_idx_rel > head_idx_rel and nxt_idx_rel <= food_idx_rel:
                        nxt_direc = path[0]

        return nxt_direc

    def _build_cycle(self):
        """Build a hamiltonian cycle on the map."""
        path = self._path_solver.longest_path_to_tail()
        cur, cnt = self.snake.head(), 0
        for direc in path:
            self._table[cur.x][cur.y].idx = cnt
            self._table[cur.x][cur.y].direc = direc
            cur = cur.adj(direc)
            cnt += 1
        # Process snake bodies
        cur = self.snake.tail()
        for _ in range(self.snake.len() - 1):
            self._table[cur.x][cur.y].idx = cnt
            self._table[cur.x][cur.y].direc = self.snake.direc
            cur = cur.adj(self.snake.direc)
            cnt += 1

    def _relative_dist(self, ori, x, size):
        if ori > x:
            x += size
        return x - ori
Пример #7
0
 def __init__(self, snake):
     super().__init__(snake)
     self._path_solver = PathSolver(snake)
Пример #8
0
class AStarSolver(BaseSolver):
    def __init__(self, snake):
        super().__init__(snake)
        self._path_solver = PathSolver(snake)
        self.open_ = [Node(self.snake.head(), 0, 0, 0, self.snake.head())]
        self.closed_ = []
        self.closed_dict = {}
        self.flag_new = True
        self.path = []

    def g(self, parent):
        return parent.g + 1

    def h(self, pos):
        # Manhattan distance between pos and food
        return abs(pos.x - self.map.food.x) + abs(pos.y - self.map.food.y)

        # Euclidean distance between pos and food
        # return math.sqrt(abs(pos.x - self.map.food.x) ** 2 + abs(pos.y - self.map.food.y) ** 2)

    def append_(self, node, list_):
        for i in range(len(list_)):
            if node.f < list_[i].f:
                list_.insert(i, node)
                return 1
            elif node.f == list_[i].f and node.g + self.euclidean_dist(
                    node.pos, self.map.food
            ) <= list_[i].g + self.euclidean_dist(list_[i].pos, self.map.food):
                list_.insert(i, node)
                return 1
        list_.append(node)
        return 1

    def euclidean_dist(self, pos1, pos2):
        return math.sqrt(abs(pos1.x - pos2.x)**2 + abs(pos1.y - pos2.y)**2)

    def print_list(self, list_):
        print("[", end="")
        for node in list_:
            print("(%d, %d)" % (node.pos.x, node.pos.y), end=" ")
        print("\b]")

    def print_list_f(self, list_):
        print("[", end="")
        for node in list_:
            print("%d(%d, %d)" % (node.f, node.pos.x, node.pos.y), end=" ")
        print("\b]")

    def get_path(self, pos1, pos2):
        path = []
        while pos1.x != pos2.x or pos1.y != pos2.y:
            path.insert(0, pos2)
            pos2 = self.closed_dict[pos2].parent
        return path

    def next_direc(self):
        head = self.snake.head()
        if self.flag_new:
            self.open_ = [Node(self.snake.head(), 0, 0, 0, self.snake.head())]
            self.closed_ = []
            self.closed_dict = {}
            self.path = []
        else:
            if len(self.path) == 0:
                print(self.snake.direc)
                return self.snake.direc
            elif len(self.path) > 1:
                next_pos = self.path[0]
                self.path.pop(0)
                print(head.direc_to(next_pos))
                return head.direc_to(next_pos)
            else:
                next_pos = self.path[0]
                self.path.pop(0)
                print(head.direc_to(next_pos))
                print()
                self.flag_new = True
                return head.direc_to(next_pos)
        self.flag_new = False
        while self.open_:
            least_node = self.open_[0]
            self.open_.remove(least_node)
            print("head (%d, %d), least_node %d(%d, %d)" %
                  (head.x, head.y, least_node.f, least_node.pos.x,
                   least_node.pos.y))
            self.print_list_f(self.open_)
            self.print_list(self.closed_)
            for adj in least_node.pos.all_adj():
                print("(" + str(adj.x) + ", " + str(adj.y) + ")", end=" ")
                if not self.map.is_safe(adj):
                    print("not safe")
                    continue
                g = self.g(least_node)
                h = self.h(adj)
                f = g + h
                print("%d = %d + %d" % (f, g, h), end=" ")
                adj_node = Node(adj, g, h, f, least_node.pos)
                if self.map.food.x == adj.x and self.map.food.y == adj.y:
                    self.append_(least_node, self.closed_)
                    self.closed_dict[least_node.pos] = least_node
                    least_node = adj_node
                    print("FOOD")
                    print("head (%d, %d), least_node %d(%d, %d)" %
                          (head.x, head.y, least_node.f, least_node.pos.x,
                           least_node.pos.y))
                    self.print_list_f(self.open_)
                    self.print_list(self.closed_)
                    self.append_(least_node, self.closed_)
                    self.closed_dict[least_node.pos] = least_node
                    self.path = self.get_path(head, adj)
                    print(self.path)
                    if len(self.path) > 1:
                        next_pos = self.path[0]
                        self.path.pop(0)
                        print(head.direc_to(next_pos))
                        return head.direc_to(next_pos)
                    else:
                        next_pos = self.path[0]
                        self.path.pop(0)
                        print(head.direc_to(next_pos))
                        print()
                        self.flag_new = True
                        return head.direc_to(next_pos)
                flag = False
                for i in range(len(self.open_)):
                    node = self.open_[i]
                    if node.pos.x == adj.x and node.pos.y == adj.y:
                        if node.f < f:
                            flag = True
                        else:
                            self.open_.pop(i)
                        break
                for i in range(len(self.closed_)):
                    node = self.closed_[i]
                    if node.pos.x == adj.x and node.pos.y == adj.y:
                        if node.f < f:
                            flag = True
                        else:
                            self.closed_dict[node.pos] = adj_node
                            # self.closed_.pop(i)
                        break
                if flag:
                    print("flag")
                    continue
                self.append_(adj_node, self.open_)
                print("appended")
            self.append_(least_node, self.closed_)
            self.closed_dict[least_node.pos] = least_node
        print("No path")
        self.flag_new = True
        self._path_solver.snake = self.snake
        path_to_tail = self._path_solver.longest_path_to_tail()
        if len(path_to_tail) > 0:
            print(path_to_tail[0])
            return path_to_tail[0]
        else:
            for adj in head.all_adj():
                if self.map.is_safe(adj):
                    print(head.direc_to(adj))
                    return head.direc_to(adj)
            print(self.snake.direc)
            return self.snake.direc