微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

所以我试图做一个递归函数,但它导致无限循环 游戏戏剧结束游戏问题分析

如何解决所以我试图做一个递归函数,但它导致无限循环 游戏戏剧结束游戏问题分析

我正在尝试编码挑战Link

对于没有帐户的人,这里是复制的: 彼得和亨利正在玩一个长度为 n 的字符串 s 的游戏,该字符串由字符 '0' 和 '1' 组成。两名玩家轮流轮流,但彼得在第一个回合。

在每一轮中,玩家都可以对字符串执行以下操作之一:

选择任何 i,其中 s[i]= '0' 并将 s[i] 更改为 '1' 并支付 1 卢比。另一个操作是反转整个字符串并支付 0 卢比。仅当字符串当前不是回文并且上次执行的操作未反转时才允许此操作。如果彼得把绳子倒过来,那么亨利在下一回合就不能把绳子倒过来,反之亦然。

反转字符串意味着将其字母从尾到尾重新排序。比如“01001”反转后会变成“10010”。

当字符串的每个字符都变成“1”时,游戏结束。到此为止花费最少卢比的玩家赢得游戏,如果双方花费相等的卢比,则为平局。如果两个玩家都发挥最佳,确定谁是赢家,或者是平局。

输入格式

第一行包含一个整数 t 。然后是 t 个测试用例。

每个测试用例的第一行包含一个整数 n 。

每个测试用例的第二行包含长度为 n 的字符串 s,由字符 '0' 和 '1' 组成。保证字符串s至少包含一个'0'。

输出格式

对于每个测试用例,在新行中打印一个单词:

“PETER”,如果彼得赢得比赛,“HENRY”,如果亨利赢得比赛,“平局”,如果比赛以平局结束。

样本输入 0

2 3 110 2 00

样本输出 0

彼得 亨利

说明 0

在示例的第一个测试用例中,在第一次移动中,Peter 将使用第二次操作来反转字符串,因为执行第一次操作无论如何都会导致他的损失。这也迫使亨利使用第一个操作。在第二步中,亨利必须执行第一次操作,因为第二次操作不能连续执行两次。字符串的所有字符都是'1',游戏结束。彼得花费 0 卢比,而亨利花费 1 卢比。因此,彼得获胜。

这是代码,我是递归函数的新手,这段代码导致最大递归限制。任何帮助将不胜感激。

def Winner(c,counter):
    if sum(c) == b:
        if len(set(counter.values)) == 1:
            print("DRAW")
            return
        else:
            d=index(min(counter.values()))
            print(counter.keys(d))
            return
    if c == c[::-1]:
        for i in c:
            if i==0:
                c[i] =1
            break
        counter["PETER"] +=1
        c=c[::-1]
        print(c)
        Winner(c,counter)
    else:
        c= c[::-1]
        for i in c:
            if i==0:
                c[i]=1
            break
        counter["HENRY"] +=1
        Winner(c,counter)
a=int(input())
p,h=0,0
counter={"PETER":0,"HENRY":0}
global b
for i in range(a):
    b=int(input())
    c=list(map(int,input().strip().split()))
    Winner(c,counter)

解决方法

我花了几天时间试图理解您的代码及其逻辑,但由于它无法运行,而且布局的逻辑似乎有缺陷,这使我受阻。因此,我自己分析游戏问题并构建自己的解决方案。为此,并明确说明我认为的游戏规则,我已尽可能简洁明了地重申了规则:

游戏

Peter 和 Henry 在长度为 n 的字符串 s 上玩游戏,字符串 s 由字符 '0' 和 '1' 组成。两名玩家轮流进行,但彼得总是先玩第一回合。

戏剧

在每一轮中,玩家都可以对字符串执行以下操作之一:

  1. 选择任何 i,其中 s[i]= '0' 并将 s[i] 更改为 '1' 并支付 1 卢比。
  2. 反转整个字符串并支付 0 卢比。如果出现以下情况,则不允许使用此选项:
    • 前一个玩家颠倒了字符串
    • 字符串是回文

结束游戏

当字符串的每个字符都变成'1'时,游戏结束。
花费最少的玩家获胜。如果双方支出相等,则平局。

问题

如果两个玩家都发挥最佳,确定谁会赢或比赛结果是否平局。

分析

假设以上准确描述了游戏玩法:
任何解决方案都需要解决的第一个问题是确定“最佳玩法”的含义。 通过初步观察,我们可以推断出对于任何玩家来说,最佳玩法都必须遵守与:

  1. 如果可能,选择字符串反转 - 这会迫使对手在惩罚下进行数字选择
  2. 如果反转不是一个选项,请选择一个数字来反转导致回文。这需要对手也交换一个数字,这样惩罚是平等的
  3. 如果不能创建回文,选择一个索引并以1的惩罚值更改值

但是,经过进一步评估,这不一定是正确的优先级,例如以下内容:

开始:10100,
玩家 0 播放 00101 score(0,0)
玩家 1 播放 10101 分数(0,1)
玩家 0 播放 11101 score(1,1)
玩家 1 播放 10111 分数(1,1)
玩家 0 播放 11111 score(2,1)
玩家 1 获胜

或者
玩家 0 播放 10101 分数(1,0)
玩家 1 播放 11101 分数(1,1)
玩家 0 播放 10111 score(1,1)
玩家 1 播放 11111 分数(1,1)
玩家 0 获胜

如上所示,玩家 0 可以通过在第一步创建回文而不是反转字符串来改善结果。因此,最佳的定义取决于游戏的最终结果,而不是简单地从任何给定游戏阶段的可用选项中选择最佳游戏。

实现此逻辑的方法要求首先确定所有游戏状态,然后在每个回合中为玩家选择最佳的最终游戏解决方案。

然后第一步需要我们创建一个所有游戏状态的连通图(GameTree)。为了在游戏的每一步跟踪游戏状态,我创建了一个 GameState 类。此类的一个实例将用于定义 GameTree 的每个节点。每个 GameState 实例将定义:

  • 输入得分 [玩家 1,玩家 2]
  • 在此状态下移动的玩家
  • 输入字符串
  • 之前的举动是反向标志真/假
  • 之前的游戏状态
  • 儿童游戏状态
  • 每个孩子的终点分数

因此,使用上面的示例,生成的简化树将符合以下条件,其中每个节点由 (Player,String_state,score,children) 描述:

GS0=[0: '10100',(0,0),[GS1,..]]  
    GS1 = [1: '00101',[GS3,..]]  
         GS3 = [0,'10101',1),[GS4,..]]  
               GS4 = [1: '11101',(1,1). [GS5]]  
                     GS5 = [0: '10111',[GS6,..]]  
                           GS6 = [1: '11111',(2,[]]  
               
         
    GS2 = [1: '10101',[GS7,..]]  
          GS7 = [0: '11101',[GS8,..]] 
                GS8 = [1: '10111',[GS9]]  
                     GS9 = [0: '11111',2),[]]
    

一旦定义了 GameTree 图,就可以使用深度优先搜索 (DFS) 算法沿着树的每个分支向下移动,直到找到叶节点(即没有子节点的节点),然后返回到前一个节点的叶节点得分。在每个有多个选项可用的节点上,tghe 函数将为玩家选择最佳解决方案并将该解决方案传递给前一个节点,这将继续返回,直到搜索到所有路径并且第一个玩家的最佳结束游戏移动可以是决定。以下代码实现了这种方法。

# Utility functions to assist in implementing optimal play
def is_palindrome(z):
    # Returns True if s is a palindrome
    return z == z[::-1]

def find_palindrome(s):
    """ Returns a list of indexes that if switched 
    will result in a palindrome position"""
    rslt = []
    k = ''
    for i,d in enumerate(s):
        k += d
        if d == '0':
            j = k[:i] + '1' + s[i+1:]
            if is_palindrome(j):
                rslt.append(i)
    return rslt    

    
def get_bestScore(l,plr):
    """ Return best score for existing move options"""
    best = None
    scr = None
    for sc in l:
        rslt = sc[(plr+1)%2] - sc[plr]
        if best == None:
           best = rslt
           scr = sc 
        else:
            if rslt > best:
                best = rslt
                scr = sc
    return scr

def find_BestMove(node):
    # Recursive function to search for leaf nodes and bactrack to define best play option
    ptr = 0
    if node.children:
        while len(node._end_options) < len(node.children):
            node._end_options.append(find_BestMove(node.children[ptr]))
            ptr += 1
        return get_bestScore(node._end_options,node.player)                        
    else:
        return node.score   

#Class to maintain game tree node states
class GameState:

    def __init__(self,parent,str_in,rvflg,score):
        self._prior = parent
        self._str = str_in
        self._player = 0
        self._score = score
        self._rvflg = rvflg
        self._children = []
        self._end_options = []
        
        if self._prior:
            self._player = (self._prior.player + 1)%2
        self._children.extend(self.get_move_options())
        
    def __gt__(self,other):
        return self.score[self.player] < other.score[other.player]
    
    def __repr__(self):
        return f"GS{self._id:02} - [{self.player}: {self.state_string} => {self.score}"
    
    def get_move_options(self):
        ''' return a list of next game states for each possible move 
        from current postion.  The list is sorted so that the best moves are
        at the begining of the list'''   
        mv_opts = []
        if not self.rvflg and not is_palindrome(self._str):
            mv_opts.append(GameState(self,self._str[::-1],True,self.score))
        sc = self._score.copy()
        sc[self._player] += 1
        popts = find_palindrome(self._str)
        for i,d in enumerate(self._str):
            if d == '0' and i not in popts:
                popts.append(i)
        for m in popts:
            nw_str = self._str[:m]+'1'+self._str[m+1:]
            mv_opts.append(GameState(self,nw_str,False,sc))  
        return mv_opts
    
    
    @property
    def state_string(self):
        return self._str
    
    @property
    def rvflg(self):
        return self._rvflg
    
    @property
    def score(self):
        return self._score
    
    @property
    def player(self):
        return self._player
    
    @property
    def  children(self):
        return self._children

def playGame(instr):
    # Function to play the Game by building the Gamestate tree and playing optimum moves
    players = ["Peter",'Henry']          
    cgs = GameState(None,instr,[0,0])
    rslt = find_BestMove(cgs)
    out_str = ''
    if rslt[0] == rslt[1]:
        out_str = 'Draw'
    elif rslt[0] < rslt[1]:
        out_str = players[0]
    else:
        out_str = players[1]
    return out_str  

以上面代码为例:

test_cases = [('00','Henry'),('100',"Draw"),('10100','Peter'),('0010','Peter')]
for tc in test_cases:
    print(f"For Input String '{tc[0]}',Expected {tc[1]} and got: {playGame(tc[0])}")

产生以下输出:

For Input String '00',Expected Henry and got: Henry
For Input String '100',Expected Draw and got: Draw
For Input String '10100',Expected Peter and got: Peter
For Input String '0010',Expected Peter and got: Peter
​

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?