利用google or-tools 求解数独难题

6 篇文章 16 订阅
2 篇文章 0 订阅

数独是一种常见的智力游戏,它的规则是:在一个9×9的网格内填入81个1至9的数字,要求每一行的数字不能出现重复,每一列的数字不能出现重新,同时在9×9的大网格内又划分为9个3×3的小网格要求每个小网格内的数字也不能出现重复。游戏开始时在大网格内已填入若干个数字,要求游戏的参与者填充剩余的数字如下图所示:

今天我们用google or-tools的建模语言cp_model来破解 手机app上的数独游戏enjoy sudoku上难度级别最高的maelstorm级的数独难题:


在建模之前,我们首先要明确数独游戏的规则,我们只需把游戏规则告诉cp_model,至于如何破解则不需要我们操心,cp_model会帮你搞定一切.再次确认游戏规则:  

1.在9×9的大网格内:每行、每列元素都不能重复。  
2.在3×3的小网格内:所有元素都不能重复。

 

初始化变量

明确了游戏规则后,我们首先要在代码中定义大网格和小网格的尺寸,以及一个待破解的数独网格,其中未填数字的元素我们会用0来代替:

from ortools.sat.python import cp_model
model = cp_model.CpModel()

#小网格尺寸
cell_size = 3
#大网格每行,每列尺寸
line_size = cell_size**2

line = list(range(0, line_size))
cell = list(range(0, cell_size))

#待破解的数独网格
initial_grid = [[2, 8, 1, 0, 0, 0, 0, 0, 0],
                [7, 9, 6, 1, 0, 4, 0, 3, 5],
                [5, 3, 4, 6, 0, 0, 0, 0, 0], 
                [3, 4, 0, 8, 0, 0, 6, 9, 7],
                [8, 1, 0, 7, 0, 6, 0, 5, 0], 
                [6, 7, 0, 0, 0, 0, 0, 8, 1],
                [0, 0, 7, 0, 0, 8, 0, 2, 0], 
                [1, 2, 8, 3, 0, 7, 5, 4, 0],
                [0, 0, 3, 2, 0, 0, 7, 0, 8]]

定义网格变量

接下来我们要定义一个9×9的大网格变量,它用来存储破解完成以后网格内的所有数字,然后对网格变量赋初始值:

#定义存储破解结果的网格变量
grid = {}
for i in line:
    for j in line:
        grid[(i, j)] = model.NewIntVar(1, line_size, 'grid %i %i' % (i, j))  
        
#初始化网格变量
for i in line:
    for j in line:
        if initial_grid[i][j]:
            model.Add(grid[(i, j)] == initial_grid[i][j])  

添加游戏规则

接下来我们要将游戏规则告诉cp_model,并往网格变量中添加游戏规则的约束:

1.行约束: 每行的元素都不一样。
2.列约束: 每列的元素都不一样。
3.cell(小网格)约束: 每个cell内的元素都不一样。

#行约束: 每行的元素都不一样
for i in line:
    model.AddAllDifferent([grid[(i, j)] for j in line])  
    
#列约束: 每列的元素都不一样
for j in line:
    model.AddAllDifferent([grid[(i, j)] for i in line])  
    

#cell约束: 每个cell内的元素都不一样
for i in cell:
    for j in cell:
        one_cell = []
        for di in cell:
            for dj in cell:
                one_cell.append(grid[(i * cell_size + di,
                                      j * cell_size + dj)])

        model.AddAllDifferent(one_cell) 

求解

设定好游戏规则以后,我们就可以舒舒服服的让or-tools来替我们完成剩下的求解过程,就这么简单!最后我们的程序仅耗时3毫秒就破解了这个数独游戏。

%%time
# 求解
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status == cp_model.OPTIMAL:
    for i in line:
        print([int(solver.Value(grid[(i, j)])) for j in line])

参考资料:

以上代码来自于:https://github.com/google/or-tools/blob/master/examples/python/sudoku_sat.py

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
本 科 生 实 验 报 告 实验课程 Android 课程设计数独游戏 学院名称 信息科学与技术学院 专业名称 物联网工程 学生姓名 学生学号 指导教师 实验地点 实验成绩 二〇一五 年 十 月 二〇一五 年 十二 月 Android 数独游戏 一、数独游戏简介 1. 数独游戏 "数独 Sudoku" 来自日文(すうどく), 但概念源自 "拉丁方块" , 是十八世纪瑞士数学家欧拉发明的,是一种运用纸、笔进行演算的逻辑游戏。数 独盘面是个九宫, 每一宫又分为九个小格。在这八十一格中给出一定的已知数字 和解题条件,利用逻辑和推理,在其他的空格上填入 1-9 的数字。使 1-9 每个数 字在每一行、每一列和每一宫中都只出现一次,所以又称"九宫格" 。谜题中会 预先填入 若干数字,它宫位则留白,玩家得依谜题中的数字分布状况,逻辑推 敲出剩下的空格里是什么数字 2. 该数独游戏是基于 Android 系统,通过过程性设计声明性两种方式来设 计用户界面,采用 Android 2D 绘图来实现数独的游戏界面中的九宫格和数字的 绘制,以及田填充页面的提示等。该数独游戏同时还涉及到活动的创建,游戏框 架的构建,多媒体功能的实现,主要用到了 Android 开发的入门基础知识,同时 设计到开发环境的配置和真机模拟和模拟器两方模拟 二、数独游戏设计 1. 游戏框架设计(以下图片都是通过 Android 真机所得) figure-1 系统框图 figure-2 进入页面 figure -3 新建游戏 figure-4 游戏界面 figure-5 关于游戏 figure-6 设置游戏 2. 游戏程序设计 figure-7 程序设计 figure-8 程序控制程序结构 figure-9 程序样式设置结构 Sudoku.java:程序的主控活动类,初始化游戏,控制其他的 java 类。 PuzzleView.java:2D 绘图的主控类,用来绘制游戏的主界面,包括九宫格、 数字、提示、虚拟键盘等。 Game.java:游戏的算法和难度的控制类。用来初始化游戏界面,控制 PuzzleView 类绘制数字;对当前九宫格的数字输入状态来提供数字的提示功 能,保存当前的状态;并根据首选项的有判断的初始化数独游戏开始界面的 难度。 About.java:主要用于关于游戏的页面的初始化和返回菜单页面。 Keypad.java:主要用于游戏提示键盘的初始化控制,获取输入的当前的数独 的输入数字和判断输入是否有效。 Prefs.java:负责对游戏设置选项的控制处理。 Music.java:多媒体的类,用来控制背景音乐的播放和暂停。 三、数独游戏实现 1. 游戏的界面设计 1)布局方式 LinearLayout(线性布局) :以相对于当行或当列的形式显示子对象,在 本数独游戏设计的开始页面采用该中布局和接下来的布局方式,通过嵌 套来实现。 RelativeLayout(相对布局) :以相对于其他子对象显示子对象。 main.xml: (伪代码) <RelativeLayout//相关布局 xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" ...//布局的设置选项 tools:context="com.example.sudoku.Sudoku" > <LinearLayout //线性布局 ...//设置布局的格式 <TextView ...//设置文本样式 android:text="@string/main_title" /> <Button android:id="@+id/new_button" ...//设置 button 样式 android:textStyle="bold"/> <Button android:id="@+id/about_button" ...//设置 button 样式 android:textStyle="bold"/> </LinearLayout> </RelativeLayout> figure-10 LinearLayout 布局 Button Continue:默认继续进入 easy 的初始化页面,如果新建游戏后,点击 "continue"按钮则进入所进行的页面。 Button Newgame:新建游戏,点击"new game"会出现游戏难易程度的选择。 Button About:数独游戏的介绍 Button Exit:推出
作为一个AI语言模型,我无法直接操作Matlab。但是,我可以为您提供一些有关使用CVX求解数独的信息。 CVX是一种用于凸优化的Matlab软件包。数独问题可以转化为线性规划问题,并且可以使用CVX解决。以下是一些基本的步骤: 1. 定义变量:将每个格子定义为一个变量。例如,对于9 x 9的数独,定义一个9 x 9的变量矩阵X。 2. 添加约束条件:添加数独的规则作为约束条件。例如,每个格子只能填入1到9之间的数字,每行、每列、每个3 x 3的小方格内的数字不能重复。 3. 定义目标函数:由于数独问题没有明显的优化目标,因此可以将目标函数定义为任意常数。 4. 使用CVX求解求解:使用CVX求解器解决线性规划问题。 以下是一个使用CVX求解数独的示例代码: ```matlab %定义数独变量 X = zeros(9,9); for i = 1:9 for j = 1:9 X(i,j) = 10*i+j; %将变量定义为两位数,方便后续处理 end end %添加约束条件 cvx_begin variable X(9,9) integer %每个格子只能填入1到9之间的数字 X >= 11 X <= 99 %每行、每列、每个3 x 3的小方格内的数字不能重复 for i = 1:9 sum(X(i,:)) == 45 sum(X(:,i)) == 45 end for i = 1:3:9 for j = 1:3:9 sum(reshape(X(i:i+2,j:j+2),1,[])) == 45 end end cvx_end %输出结果 disp(X) ``` 注意:该代码只是一个简单的示例,可能无法解决所有数独问题。具体实现需要根据具体情况进行调整和改进。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-派神-

感谢您慷慨解囊,我会更加努力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值