懒得玩游戏--帮我做数独

目录

  • 简介
  • 自动解数独思路
    • 核心思路
    • 输入
    • 解析
    • 打印
  • 完整代码

简介

最近玩上了一款类似于数独的微信小程序游戏,名字叫数独趣味闯关,过了数独的关卡之后会给拼图,玩了几关之后摸清套路了就有点累了,但是还想集齐拼图,所以就编了个程序自动解数独。

图片
数独的关卡如上图所示,每个位置分为【空】、【□】、【x】三种状态,每行/列开始有个数字,代表该行/列有几个连续的【□】,如果有两个数字就代表这两个连续n个【□】块之间隔了至少一个【x】,规则简单,就是高难度的玩着眼花。

自动解数独思路

核心思路

核心思路就是尝试所有排列组合,记录哪些位置能够确定是【□】或者【x】。例如下图所示,假设共有8个格,该行前数字为【5,1】。则有三种组合方式,以此能推断出位置【1,2,3,4】肯定为【□】,其他为待定,逐行逐列循环以得到所有位置的填充方式。

图片

输入

目前输入只能将每行/列前数字手动输入,为了输入方便,单个数字以整形直接输入,多个数字以字符串形式输入,用空格分割。如下图所示为输入样例

row = [3, 5, 6, 9, 10, 12, '5 3 3', '10 1', '3 5 1', '2 4 1 1', '3 1 3 1', '3 1 1', '3 1', '2 1', 11]
col = [6, 8, '4 5', '5 1', '8 1', '10 1', '6 3 1', '11 1', '9 1', '6 1', '3 1 1', '3 3 1', '3 1 1', '2 1', 7]

row = [[int(i) for i in s.split()] if type(s) is str else [s] for s in row]
col = [[int(i) for i in s.split()] if type(s) is str else [s] for s in col]
图片

解析

  • 对于一个新棋盘,逐行逐列扫描,以得到每个确定的位置。对于不同个数的数字,用不同层数的循环来解析。
  • 具体来说,对于某一行/列,循环得出每个可能的填充方式,用一个长度为行数的列表,列表中每个元素为一个元组来记录每个位置可能的填充,如果该位置只有一种【□】或者【x】,就将其填入到棋盘中。若该位置有两种,则视为不确定,不进行填充。
  • 由于扫描一次之后棋盘上某些位置已经确定填充,若循环得到的填充方式与现有棋盘相悖,则跳过当前循环,以此方式得到最终所有位置的填充。

打印

  • 为了更直观的观看以便自己在手机上通关,所以做的更整齐一些。如下图所示。
图片

完整代码

import numpy as np

row = [3, 5, 6, 9, 10, 12, '5 3 3', '10 1', '3 5 1', '2 4 1 1', '3 1 3 1', '3 1 1', '3 1', '2 1', 11]
col = [6, 8, '4 5', '5 1', '8 1', '10 1', '6 3 1', '11 1', '9 1', '6 1', '3 1 1', '3 3 1', '3 1 1', '2 1', 7]

row = [[int(i) for i in s.split()] if type(s) is str else [s] for s in row]
col = [[int(i) for i in s.split()] if type(s) is str else [s] for s in col]

map_size = len(row)
row_maxlen = max([len(i) for i in row])
col_maxlen = max([len(i) for i in col])
map_default_str = '-'
map = np.full([map_size, map_size], map_default_str)
num = [0]

def map_print():
    candi_list = [1] * map_size  # col中是否有超过10的数字,需要额外多一个空格
    for i in range(map_size):
        for j in col[i]:
            if j >= 10:
                candi_list[i] = 2

    f = ''
    for i in range(1, col_maxlen + 1):
        cur_num_str = ''
        for j in range(map_size):
            if len(col[j]) >= i:
                cur_num_str += str(col[j][-i]) + ' ' + ' ' * candi_list[j]
                if col[j][-i] >= 10:
                    cur_num_str = cur_num_str[:-1]
            else:
                cur_num_str += ' ' * 2 + ' ' * candi_list[j]
        f = '     ' + '   ' * (row_maxlen - 1) + cur_num_str + '\n' + f
    print(f)

    f = ''
    for i in range(map_size):
        cur_num_str = ''
        for j in range(row_maxlen):
            if len(row[i]) >= row_maxlen - j:
                if row[i][j + len(row[i]) - row_maxlen] >= 10:
                    cur_num_str = cur_num_str[:-1]
                cur_num_str += str(row[i][j + len(row[i]) - row_maxlen]) + ' ' * 2
            else:
                cur_num_str += ' ' * 2 + ' ' * candi_list[j]
        cur_num_str += ' '
        for j in range(map_size):
            # cur_num_str += str(int(map[i][j])) + '  '
            cur_num_str += ' ' * candi_list[j] + map[i][j] + ' '
        f += cur_num_str + '\n'
    print(f)

def simple_scan(idx, is_row=True):
    map_list_tmp = np.full(map_size, 'x')  # 当前行或列的值,用'x'初始化后,循环用'o'替换
    cur_list = [set() for _ in range(map_size)]  # 扫描多次保存可能填充的值
    if is_row:
        row_col_tmp = row.copy()
        map_row_col = map[idx]
    else:
        row_col_tmp = col.copy()
        map_row_col = map[:, idx]

    if len(row_col_tmp[idx]) == 1:
        for i in range(map_size - sum(row_col_tmp[idx]) + 1):
            map_list_tmp[i: i + row_col_tmp[idx][0]] = 'o'
            if is_require(map_list_tmp, map_row_col):
                cur_list = merge_list(cur_list, map_list_tmp)
            map_list_tmp = np.full(map_size, 'x')
    elif len(row_col_tmp[idx]) == 2:
        for i in range(map_size - sum(row_col_tmp[idx]) + 1 - len(row_col_tmp[idx]) + 1):
            for j in range(i + row_col_tmp[idx][0] + 1, map_size - row_col_tmp[idx][1] + 1):
                map_list_tmp[i: i + row_col_tmp[idx][0]] = 'o'
                map_list_tmp[j: j + row_col_tmp[idx][1]] = 'o'
                if is_require(map_list_tmp, map_row_col):
                    cur_list = merge_list(cur_list, map_list_tmp)
                map_list_tmp = np.full(map_size, 'x')
    elif len(row_col_tmp[idx]) == 3:
        for i in range(map_size - sum(row_col_tmp[idx]) + 1 - len(row_col_tmp[idx]) + 1):  # 8-2+1-2+1
            for j in range(i + row_col_tmp[idx][0] + 1, map_size - sum(row_col_tmp[idx][1:]) + 1 - len(row_col_tmp[idx][1:]) + 1):
                for k in range(j + row_col_tmp[idx][1] + 1, map_size - sum(row_col_tmp[idx][2:]) + 1 - len(row_col_tmp[idx][2:]) + 1):
                    map_list_tmp[i: i + row_col_tmp[idx][0]] = 'o'
                    map_list_tmp[j: j + row_col_tmp[idx][1]] = 'o'
                    map_list_tmp[k: k + row_col_tmp[idx][2]] = 'o'
                    if is_require(map_list_tmp, map_row_col):
                        cur_list = merge_list(cur_list, map_list_tmp)
                    map_list_tmp = np.full(map_size, 'x')
    elif len(row_col_tmp[idx]) == 4:
        for i in range(map_size - sum(row_col_tmp[idx]) + 1 - len(row_col_tmp[idx]) + 1):  # 8-2+1-2+1
            for j in range(i + row_col_tmp[idx][0] + 1, map_size - sum(row_col_tmp[idx][1:]) + 1 - len(row_col_tmp[idx][1:]) + 1):
                for k in range(j + row_col_tmp[idx][1] + 1, map_size - sum(row_col_tmp[idx][2:]) + 1 - len(row_col_tmp[idx][2:]) + 1):
                    for l in range(j + row_col_tmp[idx][2] + 1, map_size - sum(row_col_tmp[idx][3:]) + 1 - len(row_col_tmp[idx][3:]) + 1):
                        map_list_tmp[i: i + row_col_tmp[idx][0]] = 'o'
                        map_list_tmp[j: j + row_col_tmp[idx][1]] = 'o'
                        map_list_tmp[k: k + row_col_tmp[idx][2]] = 'o'
                        map_list_tmp[l: l + row_col_tmp[idx][3]] = 'o'
                        if is_require(map_list_tmp, map_row_col):
                            cur_list = merge_list(cur_list, map_list_tmp)
                        map_list_tmp = np.full(map_size, 'x')

    for i in range(map_size):
        if is_row:
            if len(cur_list[i]) == 1 and map[idx][i] == map_default_str:
                map[idx][i] = list(cur_list[i])[0]
                num[0] += 1
        else:
            if len(cur_list[i]) == 1 and map[i][idx] == map_default_str:
                map[i][idx] = list(cur_list[i])[0]
                num[0] += 1

def merge_list(l, n):
    for i in range(len(l)):
        l[i] = l[i].union(set(n[i]))
    return l

def is_require(l1, l2):
    for i in range(map_size):
        if l2[i] != map_default_str and l1[i] != l2[i]:
            return False
    return True

if __name__ == '__main__':
    while True:
        for i in range(map_size):
            simple_scan(i, is_row=True)
        for j in range(map_size):
            simple_scan(j, is_row=False)
        map_print()
        if num[0] == map_size * map_size:
            break

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/325762.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

为什么使用 atan2(sin(z), cos(z)) 进行角度归一化?

文章目录 为什么使用 atan2(sin(z), cos(z)) 进行归一化?为什么归一化后的角度等于原始角度? atan2 方法返回 -π 到 π 之间的值,代表点 (x, y) 相对于正X轴的偏移角度。这个角度是逆时针测量的,以弧度为单位。关于 atan2 函数为…

【第十四课】并查集(acwing-836合并集合 / 做题思路 /c++代码)

目录 错误思路(但能骗分emm)--邻接矩阵(可以跳过) 思路 存在的问题 代码如下 并查集 思路 代码如下 一些解释 错误思路(但能骗分emm)--邻接矩阵(可以跳过) 思路 刚看到这道题我自己做的时候,因为之前学的trie树的时候意识到使用二维数组的含义,…

群发邮件的免费软件?做外贸用什么邮箱好?

群发邮件的免费软件有哪些?好用的邮件群发软件? 在数字时代,邮件已成为人们沟通的主要方式之一。有时候,我们需要给大量的联系人发送信息,这时候,群发邮件就显得格外重要。接下来蜂邮就来探讨一下那些值得…

初学者必知的微软.NET6开发环境相关技术介绍

我是荔园微风,作为一名在IT界整整25年的老兵,看到不少初学者在学习编程语言的过程中如此的痛苦,我决定做点什么,我小时候喜欢看小人书(连环画),在那个没有电视、没有手机的年代,这是…

[我的rust付费栏目]rust跟我学(一)已上线

大家好,我是开源库get_local_info的作者带剑书生,get_local_info诞生半个月,现在已经获得500的下载量,并获社区日更前五名,后被西安城市开发者社区收录(【我的Rust库】get_local_info 0.1.5发布_rust_科比布…

ChatGPT:人工智能划时代的标志(文末送书)

🌈个人主页:聆风吟 🔥系列专栏:网络奇遇记、数据结构 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 一. 什么是ChatGPT?二. ChatGPT是如何工作的?三. ChatGPT的应用领域四. ChatGPT的优缺点…

自创C++题目——风扇

预估难度 简单 题目描述 有一个风扇,它有个旋转叶片,每个旋转叶片的编号是,请输出它旋转后,中心点与地面的直线距离哪个叶片最近,输出此旋转叶片的编号。默认以“”的形式。 当时: 当或时,…

运筹说 第46期 | 目标规划-数学模型

经过前几期的学习,想必大家已经对线性规划问题有了详细的了解,但线性规划作为一种决策工具,在解决实际问题时,存在着一定的局限性:(1)线性规划只能处理一个目标,而现实问题往往存在多个目标;(2)…

vtk9.3 配置 visual studio 2019 运行环境 和运行实例详解

(1)包含文件配置: 项目--属性--VC目录,在包含目录中把include文件夹的地址加进去,一直要到下一级 vtk-9.3目录下, 小知识: 在Visual Studio 2019中运行项目时,如果项目中使用了第三…

CTF CRYPTO 密码学-2

题目名称:enc 题目描述: 字符 ZZZZ X XXZ ZZ ZXZ Z ZXZ ZX ZZX XXX XZXX XXZ ZX ZXZZ ZZXZ XX ZX ZZ 分析 此字段是由Z和X组成的字符,联想到莫斯密码是由.和-组成的所以接下来可以尝试莫斯密码解题 解题过程: Step1:…

济南元宇宙赋能新型工业化,助力工业制造业高质量发展

济南工业元宇宙赋能新型工业化,助力工业制造业高质量发展。随着科技的不断发展,新型工业化已成为推动经济发展的重要力量。济南市作为山东省的省会城市,拥有得天独厚的地理优势和资源优势,积极布局工业元宇宙领域,赋能…

12.云原生之kubesphere中应用部署方式

云原生专栏大纲 文章目录 k8s中应用部署Kubernetes常用命令 kubesphere中可视化部署应用创建工作负载服务暴露 helm部署应用helm命令行部署应用kubesphere中使用应用仓库 k8s中应用部署 在k8s中要想部署应用,需要编写各种yaml文件,一旦应用依赖比较复杂…

36V/1.6A两通道H桥驱动芯片-SS8812T可替代DRV8812

由工采网代理的SS8812T是一款双通道H桥电流控制电机驱动器;每个 H 桥可提供输出电流 1.6A,可驱动两个刷式直流电机,或者一个双极步进电机,或者螺线管或者其它感性负载;双极步进电机可以以整步、2 细分、4 细分运行&…

yarn包管理器在添加、更新、删除模块时,在项目中是如何体现的

技术很久不用,就变得生疏起来。对npm深受其害,决定对yarn再整理一遍。 yarn包管理器 介绍安装yarn帮助信息最常用命令 介绍 yarn官网:https://yarn.bootcss.com,学任何技术的最新知识,都可以通过其对应的网站了解。无…

Docker部署Jira、Confluence、Bitbucket、Bamboo、Crowd,Atlassian全家桶

文章目录 省流:注意:解决方案: 1.docker-compose文件2.其他服务都正常启动,唯独Bitbucket不行。日志错误刚启动时候重启后查询分析原因再针对第一点排查看样子是安装的bitbucket和系统环境有冲突问题? 结论&#xff1a…

晶圆表面缺陷检测现状概述

背景: 晶圆表面缺陷检测设备主要检测晶圆外观呈现出来的缺陷,损伤、毛刺等缺陷,主要设备供应商KLA,AMAT,日立等,其中KLA在晶圆表面检测设备占有市场52%左右。 检测设备分类: 电子束设备和光学…

MAC iterm 显示git分支名

要在Mac上的iTerm中显示Git分支名,您需要使用一个名为“Oh My Zsh”的插件。Oh My Zsh是一个流行的Zsh框架,它提供了许多有用的功能和插件,包括在终端中显示Git分支名。 以下是在iTerm中显示Git分支名的步骤: 1、安装Oh My Zsh&…

系统架构11 - 数据库基础(上)

数据库基础 数据库基本概念概述三级模式、两级映像概念模式外模式内模式二级映像逻辑独立性物理独立性 数据库设计需求分析概念结构设计逻辑结构设计物理设计数据库实施阶段据库运行和维护阶段 数据模型E-R模型关系模型模型转换E-R图的联系 关系代数 数据库基本概念 概述 数据…

可持续技术:2024 年技术趋势的绿色创新

随着我们步入2024年,对可持续技术解决方案的关注从未如此强烈。从可再生能源到环保小工具,科技行业正朝着更环保、更可持续的未来大步迈进。 在快速发展的技术领域,创新是推动我们走向可持续未来的动力。随着我们步入2024年,对可持…

高效工作法:占位图片生成工具助力项目快速迭代

在现代设计和开发项目中,图片资源的重要性不言而喻。然而,项目中经常会遇到寻找合适图片、调整图片尺寸和格式等问题,这些问题不仅耗时耗力,还可能影响到项目的进度和质量。此时,占位图片生成工具应运而生,…