具有暴力回溯错误的Python Sudoku递归

我正在做功课的数独拼图解决方案,但遇到了一些困难.现在的代码已经超越了解决方案,虽然它确实可以轻松解决问题,而对于更难的谜题,它会因为没有明显原因而被困在几个9中.我将不胜感激任何帮助. (check_cell确定放置是否有效.)

>在此代码中是否正确实现了回溯,如果没有,将如何修复?
>如何阻止求解器冻结?它解决了大约3行然后冻结,将大多数值更改为9s.

一些代码:

def solve_helper(self,row,col):
# Try placing a number in each column of current row
    board = self.the_board
    if board[row][col] != 0:
        ?????
    elif board[row][col] == 0:
        for i in range(1,10):
            print("Setting value at i with ") + str (i) + (" located at " ) + str(row) + str(col)
            self.set_cell(row,col,i)
            self.guesses = self.guesses + 1
            if self.check_cell(row,col):
                if self.solve_helper(row,col): return True
            else:
                self.set_cell(row,0)
    else:
        return self.mover(row,col)
    return False

def mover(self,col):
    if col + 1 != 9:
        return self.solve_helper(row,(col+1))
    elif row + 1 != 9:
        print "Moving to row" + str(row + 1)
        return self.solve_helper((row+1),0)
    else:
        print "SOLUTION FOUND"
        return True
最佳答案
你遇到的麻烦是你的一些递归调用没有正确返回结果,所以你的解决方案一旦被发现,就会被遗忘在递归堆栈的几个层次上.这是您需要的第一个修复,添加返回到移动器中的递归调用:

def mover(self,(col+1))  # added return
    elif row + 1 != 9:
        print "Moving to row" + str(row + 1)
        return self.solve_helper((row+1),0)     # here too
    else:
        print "SOLUTION FOUND"
        return True

在您的solve_helper函数的特殊情况下,您还需要类似的东西,其中您跳过预解码的单元格.函数的结尾应该是:

else:
    return self.mover(row,col)  # added return
return False

编辑:

好的,我在代码中发现了一些问题.其中两个是解算器的逻辑问题,一个是显示问题,除了在解决过程中看起来很奇怪之外不会引起任何实际问题.

问题:

>首先,你是最新的代码,其中solve_helper调用自己,而不是调用mover.这使得它在移动之前需要额外的函数调用(尽管我认为它实际上可能不会破坏解算器).
>其次,如果solve_helper将一个单元格设置为9,但随后又回溯到(在一些后来的单元格无法解决之后),则9在进一步回溯之前不会重置为零.
>最后,显示问题.将单元格设置为0不会停止显示旧值.这看起来很像#2中的问题,(回溯后留下了9s),但实际上它只是装饰性的.

第一个问题很容易解决.只需将solve_helper调用更改为移动器调用即可.这实际上就是你在问题中提出的原始代码中的内容.直接调用solve_helper实际上并没有得到错误的结果(因为solve_helper将第二次跳过已填充的单元格),但它会为递归的每个级别添加一个不必要的额外函数调用.

第二个问题稍微复杂一点,这就是你被困在某些板上的地方.你需要做的是将self.set_cell(row,0)的行移出它当前所在的else块.实际上,如果你愿意的话,你实际上可以完全将它移出循环外(从那以后)如果你在当前单元格的任何值都没有工作的情况下进行回溯,那么它才真正是必要的.以下是我认为这是for循环的最佳排列(也是返回False语句):

for i in range(1,10):
    print("Setting value ") + str (i) + (" at " ) + str(row) + "," + str(col)
    self.set_cell(row,i)
    self.guesses = self.guesses + 1
    if self.check_cell(row,col):
        if self.mover(row,col):
            return True
print "Backtracking"
self.set_cell(row,0)
return False

最后,修复显示问题需要两处更改.首先,摆脱set_cell中的条件.您想要始终更新显示.接下来,在update_textfield中,将删除调用移到if块之外,以便始终发生(将插入保留在if下).这使得将单元格设置为零将擦除先前的值,但不会使其显示实际的0字符(它将不显示任何内容).

我认为应该这样做.请注意,您使用的算法仍然很慢.解决a board I found on the internet in a quick Google search需要122482个猜测和超过5分钟,但它终于工作了.其他板(特别是那些在前几个开放空间需要8s或9s的板)可能需要更长的时间.

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

相关推荐


前言 目前有个python应用需要在容器镜像内拉取git私有仓库的代码,一开始的想法是用GitPython,折腾一番ssh私钥和known_hosts问题后,发现还是在镜像中封装个git最省事,然后用subprocess调用系统命令,镜像体积也没有想象中增加特别多。 准备ssh私钥和known_ho
前言 当网络不稳定或应用页面加载有问题,可以设置等待,避免网络问题导致找不到元素等异常。 隐式等待 隐式等待设置的是最长等待时间,如果在规定时间内网页加载完成,则执行下一步,否则一直等到时间结束。 隐式等待在driver的整个生命周期都有效,初始化的时候设置一次即可。 # 隐式等待10秒 drive
前言 map()、reduce()、filter()是python的三个高阶函数。所谓高阶函数,指的是将函数作为参数并返回函数作为结果的函数。下面代码的sing_ready只是一个简单高阶函数示例: def ready(name): return f"ready,{name}!"
入门使用 # 示例代码 warframe = ["saryn", "wisp", "volt"] counts = [len(n) for n in warframe] for i,j in zip(warframe,counts): pr
前言 功能描述:批量重命名指定目录下的文件,文件名加前缀,默认格式为“目录名_原文件名”。 示例代码 import argparse import os import sys import logging def gen_args(): """ 说明 解析命令行参数 &
前言 常见的应用配置方式有环境变量和配置文件,对于微服务应用,还会从配置中心加载配置,比如nacos、etcd等,有的应用还会把部分配置写在数据库中。此处主要记录从环境变量、.env文件、.ini文件、.yaml文件、.toml文件、.json文件读取配置。 ini文件 ini文件格式一般如下: [
前言 在设计API返回内容时,通常需要与前端约定好API返回响应体内容的格式。这样方便前端进行数据反序列化时相应的解析处理,也方便其它服务调用。不同公司有不同的响应内容规范要求,这里以常见的JSON响应体为例: { "code": 200, "data": {
前言 我们一般使用如下方式点击元素: elem = driver.find_element(...) elem.click() # 或者使用带等待条件的方式 elem = WebDriverWait(driver, 10).until(EC.xxx(...)) elem.click() 正常情况下,
前言 从环境变量和配置文件中获取配置参数,相关库: python-dotenv:第三方库,需要使用pip安装 configparser:标准库 示例代码 test.ini [mysql] host = "192.168.0.10" port = 3306 user = &quot
前言 Relative Locators,相对定位器,是Selenium 4引入的一个新的定位器,相对定位器根据源点元素去定位相对位置的其它元素。 相对定位方法其实是基于JavaScript的 getBoundingClientRect() 而实现,简单的页面还行,复杂页面中可能会定位到需要相同类型
简介 The pytest framework makes it easy to write small, readable tests, and can scale to support complex functional testing for applications and librari
简介 Faker库可用于随机生成测试用的虚假数据。 可生成的数据参考底部的参考链接。 安装: python -m pip install faker 快速入门 from faker import Faker # 实例化一个对象,本地化使用中国 fk - Faker(locale="zh_C
前言 原本应用的日志是全部输出到os的stdout,也就是控制台输出。因其它团队要求也要保留日志文件,便于他们用其他工具统一采集,另一方面还要保留控制台输出,便于出问题的时候自己直接看pod日志。具体需求如下: 日志支持同时控制台输出和文件输出 控制台的输出级别可以高点,比如WARNING,个人这边
按列从多个文件中构建 假设有两个csv文件,列不相同,需要整合为一个dataframe,使用glob模块: from glob import glob import pandas as pd # glob会返回任意排序的文件名,所以需要sort排序 some_files = sorted(glob(
简介 diagrams是python的一个第三方库,用于实现使用代码绘制架构图。 安装 依赖于 Graphviz,安装diagrams之前需要先安装 Graphviz(下载压缩包后,将bin目录添加到系统环境变量Path里即可)。 python3 -m pip install diagrams 快速
前言 最近有个个人需求是要把多个图片文件合并为一个PDF文件,这样方便用PDF阅读器连续看,避免界面点一下,只会图片放大。(比如看漫画) 主要思路是先把单张图片转换成单个PDF文件,然后把PDF文件进行合并。原先是用WPS的转换工具做的,但WPS每次只能批量转换30张,如果有大量图片文件,用WPS就
前言 版本: python:3.9 selenium:4.1.5 获取元素文本 text = driver.find_element(by=By.XPATH, value="").text 获取元素属性值 attr1 = driver.find_element(by=By.XPA
Python中有个内置的函数叫做 enumerate,可以在迭代时返回元素的索引。 # 示例代码01 warframe = ["saryn", "wisp", "volt"] for i,name in enumerate(warframe
前言 版本: python:3.9 selenium:4.1.5 浏览器:firefox 创建浏览器对象 from selenium import webdriver driver = webdriver.Firefox(executable_path=r"C:\software\sele
前言 selenium提供八种元素定位的方法: find_element_by_id(): 通过id定位。一个页面中的id是唯一的。有id的话尽量使用id定位。 find_element_by_xpath(): 通过xpath语法定位(常用) find_element_by_link_text():