JAVA数独解题(五):X-wing(矩阵法)

  • 说明
  • 图片
  • 算法代码
    • CalcEnum
    • XwingCalc
    • YwingCalc
    • SudoUtil
    • 测试数据
    • 输出结果
  • 总结
  • 代码详情

说明

参考文章:数独高级技巧:X-wing的原理和应用(19年12月4日)
假设同一列中,一个数字n只能有两个空白格可以填写,并且不在同一宫中。同时存在这个数字n在另外一列由相同的情况,这时,如果四个空白格形成一个矩形。则可以排除顶点所在行的其他空白格中的候选值n。
同理衍生到行的情况,这里代码写作Y-wing。

图片

算法代码

CalcEnum

在 绑定算法 中添加 属性

package com.suduku.calc.enums;import com.suduku.calc.*;
import lombok.AllArgsConstructor;
import lombok.Getter;import java.util.HashMap;
import java.util.Map;/*** 功能描述: 算法枚举 <br/>**/
@Getter
@AllArgsConstructor
public enum CalcEnum {/***/ONLY_NUM(OnlyNumCalc.class, "唯余法", "唯一余数法(当前单元格中,候选数字只有一个)"),ONLY_BOX(OnlyBoxCalc.class, "摒除法", "摒除法(数字在所在行或列或宫中,只有一个空格能够填写,则确定是唯一数字)"),GRID_XY(GridXYCalc.class, "单宫行列法", "单宫行列法()"),SU_DUI(SuDuiCalc.class, "数对法", "数对法(一个区域内,两个数字只能在两个单元格内,则形成数对,其他值不能填入)"),X_WING(XwingCalc.class, "X-wing", "X-wing(如果在同一列,并且不在同一宫中,存在数字n只有两个单元格可以填写;并且不在这两宫的其他列存在相同的情况,则可以排除在这两行中,其他位置的数字n的情况)"),Y_WING(YwingCalc.class, "Y-wing", "X-wing对应"),;private static final Map<Class<? extends AbstractCalc>, CalcEnum> CE_MAP = new HashMap<>(CalcEnum.values().length);static {for(CalcEnum ce : CalcEnum.values()) {CE_MAP.put(ce.getClazz(), ce);}}/*** 功能描述: 通过类,获取枚举 <br/>** @param clazz 类* @return "com.suduku.calc.enums.CalcEnum"*/public static CalcEnum indexOf(Class<? extends AbstractCalc> clazz) {return CE_MAP.get(clazz);}private Class<? extends AbstractCalc> clazz;private String name;private String msg;}

XwingCalc

package com.suduku.calc;import com.suduku.entity.Box;import java.util.*;
import java.util.stream.Collectors;/*** X-wing(如果在同一列,并且不在同一宫中,存在数字n只有两个单元格可以填写;并且不在这两宫的其他列存在相同的情况,则可以排除在这两行中,其他位置的数字n的情况) <br/>* 与X-wing相对应的,横向也是满足的。* 将行和列合并起来,形成矩形。就能够排除4个顶点所在的行列的其余空白格的数字。* 测试数据:DataConstant.OTHER_X_WING_01*/
public class XwingCalc extends AbstractCalc {@OverrideBox solve() {// 遍历数字for(Integer n : Box.INIT_LIST) {Set<Map.Entry<Integer, List<Box>>> entries = getYMap().entrySet();// 遍历区域for(Map.Entry<Integer, List<Box>> e1 : entries) {// 获取当前区域包含数字n的空白格List<Box> b1List = e1.getValue().stream().filter(b -> b.isBlank() && b.getCList().contains(n)).collect(Collectors.toList());// 如果只有两个空白格,并且不在同一宫中if(b1List.size() == 2 && b1List.get(0).getG() != b1List.get(1).getG()) {// 遍历第二遍for(Map.Entry<Integer, List<Box>> e2 : entries) {if(e2.getKey() > e1.getKey()) {// 获取当前区域包含数字n的空白格List<Box> b2List = e2.getValue().stream().filter(b -> b.isBlank() && b.getCList().contains(n)).collect(Collectors.toList());// 如果只有两个空白格,并且不在同一宫中if(b2List.size() == 2 && b2List.get(0).getG() != b2List.get(1).getG()) {// 判断是否在同一行中if(b1List.get(0).getX() == b2List.get(0).getX() && b1List.get(1).getX() == b2List.get(1).getX()) {Box box = clearBoxNum(b1List.get(0), b2List.get(0), n);if(box != null) {return box;}box = clearBoxNum(b1List.get(1), b2List.get(1), n);if(box != null) {return box;}}}}}}}}return null;}/*** 功能描述: 清理数字 <br/>** @param b1 同一列的单元格1* @param b2 同一列的单元格2* @param n 移除的数字* @return "com.suduku.entity.Box"*/private Box clearBoxNum(Box b1, Box b2, Integer n) {List<Box> clearBoxList = getXList(b1).stream().filter(b -> b.isBlank() && b.getI() != b1.getI() && b.getI() != b2.getI() && b.getCList().contains(n)).collect(Collectors.toList());for (Box box : clearBoxList) {getListener().sendMsg("移除第【%d】行的数字:%d\n", (b1.getX() + 1), n);box.getCList().remove(n);return box;}return null;}}

YwingCalc

package com.suduku.calc;import com.suduku.entity.Box;import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;/*** 与X-wing对应* 测试数据:SudoUtil.transpose(DataConstant.OTHER_X_WING_01) 转置后的数独*/
public class YwingCalc extends AbstractCalc {@OverrideBox solve() {// 遍历数字for(Integer n : Box.INIT_LIST) {Set<Map.Entry<Integer, List<Box>>> entries = getXMap().entrySet();// 遍历区域for(Map.Entry<Integer, List<Box>> e1 : entries) {// 获取当前区域包含数字n的空白格List<Box> b1List = e1.getValue().stream().filter(b -> b.isBlank() && b.getCList().contains(n)).collect(Collectors.toList());// 如果只有两个空白格,并且不在同一宫中if(b1List.size() == 2 && b1List.get(0).getG() != b1List.get(1).getG()) {// 遍历第二遍for(Map.Entry<Integer, List<Box>> e2 : entries) {if(e2.getKey() > e1.getKey()) {// 获取当前区域包含数字n的空白格List<Box> b2List = e2.getValue().stream().filter(b -> b.isBlank() && b.getCList().contains(n)).collect(Collectors.toList());// 如果只有两个空白格,并且不在同一宫中if(b2List.size() == 2 && b2List.get(0).getG() != b2List.get(1).getG()) {// 判断是否在同一行中if(b1List.get(0).getY() == b2List.get(0).getY() && b1List.get(1).getY() == b2List.get(1).getY()) {Box box = clearBoxNum(b1List.get(0), b2List.get(0), n);if(box != null) {return box;}box = clearBoxNum(b1List.get(1), b2List.get(1), n);if(box != null) {return box;}}}}}}}}return null;}/*** 功能描述: 清理数字 <br/>** @param b1 同一行的单元格1* @param b2 同一行的单元格2* @param n 移除的数字* @return "com.suduku.entity.Box"*/private Box clearBoxNum(Box b1, Box b2, Integer n) {List<Box> clearBoxList = getYList(b1).stream().filter(b -> b.isBlank() && b.getI() != b1.getI() && b.getI() != b2.getI() && b.getCList().contains(n)).collect(Collectors.toList());for (Box box : clearBoxList) {getListener().sendMsg("移除第【%d】列的数字:%d\n", (b1.getX() + 1), n);box.getCList().remove(n);return box;}return null;}}

由于没有找到Y-wing的案例,所以通过矩阵转置来产生场景。在SoduUtil中添加转置代码

SudoUtil

    /*** 功能描述: 转置 <br/>* * @param str 数独字符串* @return "java.lang.String"*/public static String transpose(String str) {char[] cs = str.toCharArray();char[] rs = new char[cs.length];for (int i = 0; i < cs.length; i++) {// 行列互换rs[(i % 9) * 9 + i / 9] = cs[i];}return new String(rs);}

测试数据

在 DataConstant 中添加

public static final String OTHER_X_WING_01 = "000300100500401090001028600090800001008017002010040800004085000300100040002634000";

输出结果

尝试【X-wing    】
移除第【1】行的数字:9
确认位置【行:1,列:1】  值为:【】    候选值为:【4,6,7,8】
{0}(4678     ) 0 (2467     ) 0 (679      ) |  3 (         ) 0 (5679     ) 0 (69       ) |  1 (         ) 0 (2578     ) 0 (457      ) | 5 (         ) 0 (23678    ) 0 (367      ) |  4 (         ) 0 (67       ) 1 (         ) |  0 (237      ) 9 (         ) 0 (378      ) | 0 (479      ) 0 (347      ) 1 (         ) |  0 (579      ) 2 (         ) 8 (         ) |  6 (         ) 0 (357      ) 0 (3457     ) | 0 (2467     ) 9 (         ) 0 (3567     ) |  8 (         ) 0 (56       ) 0 (236      ) |  0 (3457     ) 0 (3567     ) 1 (         ) | 0 (46       ) 0 (3456     ) 8 (         ) |  0 (59       ) 1 (         ) 7 (         ) |  0 (3459     ) 0 (356      ) 2 (         ) | 0 (267      ) 1 (         ) 0 (3567     ) |  0 (259      ) 4 (         ) 0 (2369     ) |  8 (         ) 0 (3567     ) 0 (35679    ) | 0 (1679     ) 0 (67       ) 4 (         ) |  0 (279      ) 8 (         ) 5 (         ) |  0 (2379     ) 0 (12367    ) 0 (3679     ) | 3 (         ) 0 (5678     ) 0 (5679     ) |  1 (         ) 0 (79       ) 0 (29       ) |  0 (2579     ) 4 (         ) 0 (56789    ) | 0 (1789     ) 0 (57       ) 2 (         ) |  6 (         ) 3 (         ) 4 (         ) |  0 (579      ) 0 (1578     ) 0 (579      ) | 尝试【X-wing    】
移除第【1】行的数字:9
确认位置【行:1,列:6】  值为:【】    候选值为:【6】0 (4678     ) 0 (2467     ) 0 (679      ) |  3 (         ) 0 (5679     ){0}(6        ) |  1 (         ) 0 (2578     ) 0 (457      ) | 5 (         ) 0 (23678    ) 0 (367      ) |  4 (         ) 0 (67       ) 1 (         ) |  0 (237      ) 9 (         ) 0 (378      ) | 0 (479      ) 0 (347      ) 1 (         ) |  0 (579      ) 2 (         ) 8 (         ) |  6 (         ) 0 (357      ) 0 (3457     ) | 0 (2467     ) 9 (         ) 0 (3567     ) |  8 (         ) 0 (56       ) 0 (236      ) |  0 (3457     ) 0 (3567     ) 1 (         ) | 0 (46       ) 0 (3456     ) 8 (         ) |  0 (59       ) 1 (         ) 7 (         ) |  0 (3459     ) 0 (356      ) 2 (         ) | 0 (267      ) 1 (         ) 0 (3567     ) |  0 (259      ) 4 (         ) 0 (2369     ) |  8 (         ) 0 (3567     ) 0 (35679    ) | 0 (1679     ) 0 (67       ) 4 (         ) |  0 (279      ) 8 (         ) 5 (         ) |  0 (2379     ) 0 (12367    ) 0 (3679     ) | 3 (         ) 0 (5678     ) 0 (5679     ) |  1 (         ) 0 (79       ) 0 (29       ) |  0 (2579     ) 4 (         ) 0 (56789    ) | 0 (1789     ) 0 (57       ) 2 (         ) |  6 (         ) 3 (         ) 4 (         ) |  0 (579      ) 0 (1578     ) 0 (579      ) | 尝试【X-wing  】
移除第【8】行的数字:9
确认位置【行:8,列:6】  值为:【】    候选值为:【2】0 (4678     ) 0 (2467     ) 0 (679      ) |  3 (         ) 0 (5679     ) 0 (6        ) |  1 (         ) 0 (2578     ) 0 (457      ) | 5 (         ) 0 (23678    ) 0 (367      ) |  4 (         ) 0 (67       ) 1 (         ) |  0 (237      ) 9 (         ) 0 (378      ) | 0 (479      ) 0 (347      ) 1 (         ) |  0 (579      ) 2 (         ) 8 (         ) |  6 (         ) 0 (357      ) 0 (3457     ) | 0 (2467     ) 9 (         ) 0 (3567     ) |  8 (         ) 0 (56       ) 0 (236      ) |  0 (3457     ) 0 (3567     ) 1 (         ) | 0 (46       ) 0 (3456     ) 8 (         ) |  0 (59       ) 1 (         ) 7 (         ) |  0 (3459     ) 0 (356      ) 2 (         ) | 0 (267      ) 1 (         ) 0 (3567     ) |  0 (259      ) 4 (         ) 0 (2369     ) |  8 (         ) 0 (3567     ) 0 (35679    ) | 0 (1679     ) 0 (67       ) 4 (         ) |  0 (279      ) 8 (         ) 5 (         ) |  0 (2379     ) 0 (12367    ) 0 (3679     ) | 3 (         ) 0 (5678     ) 0 (5679     ) |  1 (         ) 0 (79       ){0}(2        ) |  0 (2579     ) 4 (         ) 0 (56789    ) | 0 (1789     ) 0 (57       ) 2 (         ) |  6 (         ) 3 (         ) 4 (         ) |  0 (579      ) 0 (1578     ) 0 (579      ) | 尝试【X-wing  】
移除第【8】行的数字:9
确认位置【行:8,列:7】  值为:【】    候选值为:【2,5,7】0 (4678     ) 0 (2467     ) 0 (679      ) |  3 (         ) 0 (5679     ) 0 (6        ) |  1 (         ) 0 (2578     ) 0 (457      ) | 5 (         ) 0 (23678    ) 0 (367      ) |  4 (         ) 0 (67       ) 1 (         ) |  0 (237      ) 9 (         ) 0 (378      ) | 0 (479      ) 0 (347      ) 1 (         ) |  0 (579      ) 2 (         ) 8 (         ) |  6 (         ) 0 (357      ) 0 (3457     ) | 0 (2467     ) 9 (         ) 0 (3567     ) |  8 (         ) 0 (56       ) 0 (236      ) |  0 (3457     ) 0 (3567     ) 1 (         ) | 0 (46       ) 0 (3456     ) 8 (         ) |  0 (59       ) 1 (         ) 7 (         ) |  0 (3459     ) 0 (356      ) 2 (         ) | 0 (267      ) 1 (         ) 0 (3567     ) |  0 (259      ) 4 (         ) 0 (2369     ) |  8 (         ) 0 (3567     ) 0 (35679    ) | 0 (1679     ) 0 (67       ) 4 (         ) |  0 (279      ) 8 (         ) 5 (         ) |  0 (2379     ) 0 (12367    ) 0 (3679     ) | 3 (         ) 0 (5678     ) 0 (5679     ) |  1 (         ) 0 (79       ) 0 (2        ) | {0}(257      ) 4 (         ) 0 (56789    ) | 0 (1789     ) 0 (57       ) 2 (         ) |  6 (         ) 3 (         ) 4 (         ) |  0 (579      ) 0 (1578     ) 0 (579      ) | 尝试【X-wing  】
移除第【8】行的数字:9
确认位置【行:8,列:9】  值为:【】    候选值为:【5,6,7,8】0 (4678     ) 0 (2467     ) 0 (679      ) |  3 (         ) 0 (5679     ) 0 (6        ) |  1 (         ) 0 (2578     ) 0 (457      ) | 5 (         ) 0 (23678    ) 0 (367      ) |  4 (         ) 0 (67       ) 1 (         ) |  0 (237      ) 9 (         ) 0 (378      ) | 0 (479      ) 0 (347      ) 1 (         ) |  0 (579      ) 2 (         ) 8 (         ) |  6 (         ) 0 (357      ) 0 (3457     ) | 0 (2467     ) 9 (         ) 0 (3567     ) |  8 (         ) 0 (56       ) 0 (236      ) |  0 (3457     ) 0 (3567     ) 1 (         ) | 0 (46       ) 0 (3456     ) 8 (         ) |  0 (59       ) 1 (         ) 7 (         ) |  0 (3459     ) 0 (356      ) 2 (         ) | 0 (267      ) 1 (         ) 0 (3567     ) |  0 (259      ) 4 (         ) 0 (2369     ) |  8 (         ) 0 (3567     ) 0 (35679    ) | 0 (1679     ) 0 (67       ) 4 (         ) |  0 (279      ) 8 (         ) 5 (         ) |  0 (2379     ) 0 (12367    ) 0 (3679     ) | 3 (         ) 0 (5678     ) 0 (5679     ) |  1 (         ) 0 (79       ) 0 (2        ) |  0 (257      ) 4 (         ){0}(5678     ) | 0 (1789     ) 0 (57       ) 2 (         ) |  6 (         ) 3 (         ) 4 (         ) |  0 (579      ) 0 (1578     ) 0 (579      ) |

最终结果

 尝试【唯余法  】
确认位置【行:9,列:9】  值为:【9】   候选值为:【】8 (         ) 7 (         ) 9 (         ) |  3 (         ) 5 (         ) 6 (         ) |  1 (         ) 2 (         ) 4 (         ) | 5 (         ) 2 (         ) 6 (         ) |  4 (         ) 7 (         ) 1 (         ) |  3 (         ) 9 (         ) 8 (         ) | 4 (         ) 3 (         ) 1 (         ) |  9 (         ) 2 (         ) 8 (         ) |  6 (         ) 5 (         ) 7 (         ) | 2 (         ) 9 (         ) 5 (         ) |  8 (         ) 6 (         ) 3 (         ) |  4 (         ) 7 (         ) 1 (         ) | 6 (         ) 4 (         ) 8 (         ) |  5 (         ) 1 (         ) 7 (         ) |  9 (         ) 3 (         ) 2 (         ) | 7 (         ) 1 (         ) 3 (         ) |  2 (         ) 4 (         ) 9 (         ) |  8 (         ) 6 (         ) 5 (         ) | 9 (         ) 6 (         ) 4 (         ) |  7 (         ) 8 (         ) 5 (         ) |  2 (         ) 1 (         ) 3 (         ) | 3 (         ) 8 (         ) 7 (         ) |  1 (         ) 9 (         ) 2 (         ) |  5 (         ) 4 (         ) 6 (         ) | 1 (         ) 5 (         ) 2 (         ) |  6 (         ) 3 (         ) 4 (         ) |  7 (         ) 8 (         ){9}(         ) | ============数独解题完成,尝试次数为:65============

总结

在写代码的过程中,研究案例,并且思考相关变化。

代码详情

代码地址

JAVA数独解题(五):X-wing(矩阵法)相关推荐

  1. JAVA数独解题(九):数链法(数串、垂直)

    JAVA数独解题(九):数链法(数串.垂直) 说明 图片 算法代码 CalcEnum SuLianVerticalCalc SudoUtil 测试数据 输出结果 总结 代码详情 说明 参考文章:数独高 ...

  2. JAVA数独解题(一):框架搭建

    JAVA数独解题(一):框架搭建 前言 环境 创建工程 实体类 Box Sudo 监听器 SudoListener SudoPrintImpl 核心类 SudoHandler 算法组 Abstract ...

  3. JAVA数独解题(四):数对法

    JAVA数独解题(四):数对法 说明 图片 算法代码 CalcEnum SuDuiCalc SudoUtil 输出结果 总结 代码详情 说明 数对:两个单元格,两个数字.两个数字在当前区域(行.列.宫 ...

  4. JAVA数独解题(七):XYZ-wing

    JAVA数独解题(七):XYZ-wing 说明 图片 算法代码 CalcEnum XYZwingCalc SudoUtil 测试数据 输出结果 总结 代码详情 说明 参考文章:数独高级技巧:XYZ-w ...

  5. 数据结构与算法Java(二)——字符串、矩阵压缩、递归、动态规划

    不定期补充.修正.更新:欢迎大家讨论和指正 本文以数据结构(C语言版)第三版 李云清 杨庆红编著为主要参考资料,用Java来实现 数据结构与算法Java(一)--线性表 数据结构与算法Java(二)- ...

  6. java小球落体问题_[Java 编程基本功] (五) 小球落体, 发奖金, 1,2,3,4 可以组成多少个数...

    [Java 编程基本功] (五) 小球落体, 发奖金, 1,2,3,4 可以组成多少个数 第十三题 一球从 100 米高度自由落下, 每次落地后反跳回原高度的一半; 再落下, 求它在第 10 次落地时 ...

  7. Python学习案例2——数独解题及出题程序

    第二个求解案例,我想到了数独.曾经有一段时间对数独求解非常感兴趣,在学习C++语言时也编写了数独求解程序.本次Python学习,要求比之前高一点,把出题程序也一起编写了吧. 1.数独简介 数独 (英语 ...

  8. Java学习记录五(多线程、网络编程、Lambda表达式和接口组成更新)

    Java学习记录五(多线程.网络编程.Lambda表达式和接口组成更新) Java 25.多线程 25.1实现多线程 25.1.1进程 25.1.2线程 25.1.3多线程的实现 25.1.4设置和获 ...

  9. Effective Java笔记第五章枚举和注解第三节用EnumSet代替位域

    Effective Java笔记第五章枚举和注解 第三节用EnumSet代替位域 在以前如果一个枚举类型的元素主要用在集合中,一般就会使用int枚举模式.比如说: public class Demo ...

最新文章

  1. 产品经理技能树之 数据体系
  2. Django2.0——模板渲染(一)
  3. HDU4549 M斐波那契数列 —— 斐波那契、费马小定理、矩阵快速幂
  4. 三款ActiveX图表控件对比评测 TeeChart VS ProEssentials…
  5. eclipse 函数折叠展开
  6. 每日一题(46)—— volatile
  7. Linux 蓝牙读写,实战Linux Bluetooth编程(三) HCI层编程
  8. 【算法分析与设计】数组循环移位问题
  9. myeclipse2017安装与破解
  10. IPython高级用法(一)定制命令别名及存储别名
  11. 概率论:均值、标准差、方差、协方差、矩
  12. Mismatch between array dtype (‘<U40‘) and format specifier (‘%.18e‘)
  13. Java web 实战项目案例
  14. 430单片机实现三人投票表决器_基于单片机的五人表决器的设计
  15. 郭天祥老师单片机教程之串口练习题
  16. 激活windows 2008 r2
  17. react后台管理项目
  18. 计算机提示无法验证发布者,win10提示无法验证发布者所以windows已阻止此软件的解决方法【图文教程】...
  19. c语言打印日历的程序,简单日历打印(C语言)
  20. 可信平台模块TPM(Trusted Platform Module)介绍及tpm-tools安装使用

热门文章

  1. 页面多个layui数据表格时,根据ID获取对应表格数据
  2. Python 实战开发俄罗斯方块游戏
  3. 电商项目之电子账户的收单模式
  4. 简单的cpu飙高问题定位脚本
  5. 机器学习中SVM+HOG实现对饮料瓶的识别
  6. Beats:如何调试 Beats processors
  7. 2月天猫彩妆类目销量排行榜:销额近16亿,国货品牌入围TOP3
  8. Sphinx到Coreseek安装全解
  9. 【jQuery】鼠标悬停事件
  10. 转:为什么要有Spring?