深度优先搜索逻辑递归函数

问题描述 投票:0回答:1

我有一些代码,我在地牢爬行游戏中模拟玩家试图逃离地牢。我想用深度优先搜索来测试玩家能否成功。

我的方法出了问题,在 Dungeon 类中,应该测试走出地牢的every路径是否会成功: 这是我的打印声明:

self = <main_test.GraphTest testMethod=test_can_all_paths_make_it>

    def test_can_all_paths_make_it(self):
        dungeon = self.create_dungeon()
>       self.assertEqual(dungeon.can_all_paths_make_it(Player(11)), False)
E       AssertionError: True != False

coderbyte-tests/main_test.py:140: AssertionError
----------------------------- Captured stdout call -----------------------------
Checking node: <graph.Monster object at 0x7f82158aa190>, Current Health: 11
Checking neighbor: <graph.Monster object at 0x7f82158aa130>
Encountered Monster: <graph.Monster object at 0x7f82158aa130>
Checking node: <graph.Monster object at 0x7f82158aa130>, Current Health: 7
Checking neighbor: <graph.Monster object at 0x7f82158aa040>
Encountered Monster: <graph.Monster object at 0x7f82158aa040>
Checking node: <graph.Monster object at 0x7f82158aa040>, Current Health: 2
Checking neighbor: <graph.Treasure object at 0x7f8215914850>
Processing neighbor: <graph.Treasure object at 0x7f8215914850>
Checking node: <graph.Treasure object at 0x7f8215914850>, Current Health: 2
Found Treasure!
# Will any path make it to the end? Can they choose randomly and always make it?
    def can_all_paths_make_it(self, player: Player) -> bool:
      def dfs(node, current_health):
        if isinstance(node, Treasure):
          return True

        if current_health <= 0:
          return False
        
        if node is not node.next:
          return False
        
        for neighbor in node.next:
                if isinstance(neighbor, Monster):
                    # Simulate a battle with the monster
                    new_health = current_health - neighbor.damage
                    if not dfs(neighbor, new_health):
                        return False
                elif not dfs(neighbor, current_health):
                    return False

        return True

      return dfs(self.monster, player.health)

逻辑好像有点不对,因为有些测试用例失败了。 (测试用例不会准确显示我的错误,除了在输出 False 时期望 True 之外)。

我知道,为了测试是否所有路径都能成功,我需要考虑死胡同、生命值的损失以及它们是否在宝藏。

出了什么问题,如何解决?

这是测试用例

import unittest

从图表导入怪物、宝藏、玩家、地下城

类 GraphTest(unittest.TestCase):

# a(3) -> b(4) -> c(5) -> treasure
def create_dungeon(self) -> Dungeon:
    a = Monster("a", 3)
    b = Monster("b", 4)
    c = Monster("c", 5)
    treasure = Treasure()
    a.append_monster(b)
    b.append_monster(c)
    c.append_treasure(treasure)

    return Dungeon(a)

# a(3) -> b(4)  c(5) -> treasure
def create_dungeon2(self) -> Dungeon:
    a = Monster("a", 3)
    b = Monster("b", 4)
    c = Monster("c", 5)
    treasure = Treasure()
    a.append_monster(b)
    c.append_treasure(treasure)

    return Dungeon(a)

# a(1) -> b(4)
#   |      |
#   v      v
# c(2) -> d(1) -> treasure
def create_dungeon3(self):
    a = Monster("a", 1)
    b = Monster("b", 4)
    c = Monster("c", 2)
    d = Monster("d", 1)
    treasure = Treasure()
    a.append_monster(b)
    a.append_monster(c)
    b.append_monster(d)
    c.append_monster(d)
    d.append_treasure(treasure)

    return Dungeon(a)

# a(1) -> b(4) -> e(1)
#   |      |
#   v      v
# c(2) -> d(1) -> treasure

'''
Probability review: Just because there are 2 different possiblilites does not 
mean that they are equal probability. For example, on any given day, there could be 
rain or no rain. That doesn't imply that rain has a 50% chance.

In this case, there are 3 different paths:
a->c->d->treasure, a->b->d->treasure, and a->b->e. 

Here, a->c->d->tresure has a 50% chance of happening, a->b->e is 25%, and a->b->d->treasure is 25%. 
An easy way to think about it that the probability of A reaching C is 50% and C reaching D is 100%
and D reaching Treasure is 100%. Overall, it would be 50% chance to do A->C->D->Treasure.
'''
def create_dungeon4(self):
    a = Monster("a", 1)
    b = Monster("b", 4)
    c = Monster("c", 2)
    d = Monster("d", 1)
    e = Monster("e", 1)
    treasure = Treasure()
    a.append_monster(b)
    a.append_monster(c)
    b.append_monster(d)
    c.append_monster(d)
    b.append_monster(e)
    d.append_treasure(treasure)

    return Dungeon(a)

# a(1) -> b(5) -> e(1) 
#   |      |       |       
#   v      v       v        
# c(2) -> d(7) -> f(2) -> treasure
# optimal -> a -> b -> e -> f
def create_dungeon5(self):
    a = Monster("a", 1)
    b = Monster("b", 5)
    c = Monster("c", 2)
    d = Monster("d", 7)
    e = Monster("e", 1)
    f = Monster("f", 2)
    treasure = Treasure()
    a.append_monster(b)
    a.append_monster(c)
    b.append_monster(e)
    b.append_monster(d)
    c.append_monster(d)
    d.append_monster(f)
    e.append_monster(f)
    f.append_treasure(treasure)

    return Dungeon(a)

# a(1) -> b(5) -> e(1) ------
#   |      |       |        |
#   v      v       v        v
# c(2) -> d(7) -> f(2) -> treasure
# optimal -> a -> b -> e -> f
def create_dungeon6(self):
    a = Monster("a", 1)
    b = Monster("b", 5)
    c = Monster("c", 2)
    d = Monster("d", 7)
    e = Monster("e", 1)
    f = Monster("f", 2)
    treasure = Treasure()
    a.append_monster(b)
    a.append_monster(c)
    b.append_monster(e)
    b.append_monster(d)
    c.append_monster(d)
    d.append_monster(f)
    e.append_monster(f)
    e.append_treasure(treasure)
    f.append_treasure(treasure)

    return Dungeon(a)

def test_can_at_least_one_path_make_it(self):
    dungeon = self.create_dungeon()
    self.assertEqual(dungeon.can_at_least_one_path_make_it(), True)
    
    dungeon = self.create_dungeon2()
    self.assertEqual(dungeon.can_at_least_one_path_make_it(), False)


def test_can_all_paths_make_it(self):
    dungeon = self.create_dungeon()
    self.assertEqual(dungeon.can_all_paths_make_it(Player(11)), False)

    dungeon = self.create_dungeon()
    self.assertEqual(dungeon.can_all_paths_make_it(Player(12)), True)

    dungeon = self.create_dungeon2()
    self.assertEqual(dungeon.can_all_paths_make_it(Player(7)), False)
    
    dungeon = self.create_dungeon3()
    self.assertEqual(dungeon.can_all_paths_make_it(Player(5)), False)

    dungeon = self.create_dungeon3()
    self.assertEqual(dungeon.can_all_paths_make_it(Player(6)), True)

    dungeon = self.create_dungeon4()
    self.assertEqual(dungeon.can_all_paths_make_it(Player(100)), False)

def test_probability_player_will_make_it(self):
    dungeon = self.create_dungeon()
    self.assertEqual(dungeon.probability_player_will_make_it(Player(12)), 1.0)

    dungeon = self.create_dungeon()
    self.assertEqual(dungeon.probability_player_will_make_it(Player(11)), 0.0)
    
    dungeon = self.create_dungeon2()
    self.assertEqual(dungeon.probability_player_will_make_it(Player(100)), 0.0)

    dungeon = self.create_dungeon3()
    self.assertEqual(dungeon.probability_player_will_make_it(Player(1)), 0.0)

    dungeon = self.create_dungeon3()
    self.assertEqual(dungeon.probability_player_will_make_it(Player(5)), 0.5)

    dungeon = self.create_dungeon3()
    self.assertEqual(dungeon.probability_player_will_make_it(Player(100)), 1.0)

    dungeon = self.create_dungeon4()
    self.assertEqual(dungeon.probability_player_will_make_it(Player(1)), 0.0)

    dungeon = self.create_dungeon4()
    self.assertEqual(dungeon.probability_player_will_make_it(Player(5)), 0.5)

    dungeon = self.create_dungeon4()
    self.assertEqual(dungeon.probability_player_will_make_it(Player(100)), 0.75)

def test_can_make_it(self):
    dungeon = self.create_dungeon5()
    self.assertEqual(dungeon.can_make_it(Player(9)), True)

    dungeon = self.create_dungeon5()
    self.assertEqual(dungeon.can_make_it(Player(8)), False)

    dungeon = self.create_dungeon6()
    self.assertEqual(dungeon.can_make_it(Player(7)), True)

    dungeon = self.create_dungeon6()
    self.assertEqual(dungeon.can_make_it(Player(6)), False)

我自己创建了这个打印语句 def can_all_paths_make_it(self, 玩家: 玩家) -> bool: def dfs(节点, current_health): print(f"正在检查节点:{node},当前运行状况:{current_health}")

    if isinstance(node, Treasure):
        print("Found Treasure!")
        return True

    if current_health <= 0:
        print("Player has lost all health!")
        return False

    if not isinstance(node.next, list):
        print("Invalid path: node.next is not a list")
        return False  # If node.next is not a list, it's not a valid path

    for neighbor in node.next:
        print(f"Checking neighbor: {neighbor}")

        if isinstance(neighbor, Monster):
            print(f"Encountered Monster: {neighbor}")
            # Simulate a battle with the monster
            new_health = current_health - neighbor.damage
            if not dfs(neighbor, new_health):
                return False
        elif not dfs(neighbor, current_health):
            return False

    return True

return dfs(self.monster, player.health)
python algorithm data-structures depth-first-search
1个回答
0
投票

有几个问题:

    当健康状况为零时,
  • if current_health <= 0
    将评估为 True,但这仍然是可接受的健康状况。

  • 生命值只会因邻近怪物的伤害而减少,而不会因第一个怪物的伤害而减少。您应该将该损坏逻辑移出循环并将其应用到当前节点。

  • if node is not node.next:
    没有意义。这个条件永远为真。您需要使用
    if not node.next:

    来测试死胡同

这是更正后的代码:

    def can_all_paths_make_it(self, player: Player) -> bool:
        def dfs(node, current_health):
            if current_health < 0:  # the player died
                return False
            
            if isinstance(node, Treasure):  # bingo!
                return True

            if isinstance(node, Monster):  # have to fight
                current_health -= node.damage
 
            if not node.next:   # dead end
                return False

            return all(dfs(neighbor, current_health) 
                       for neighbor in node.next)

        return dfs(self.monster, player.health)
© www.soinside.com 2019 - 2024. All rights reserved.