动力老男孩 发表于 2010/01/03 17:38:09

本来我想把这个攻略做成一个NXT开发的教程,把传感器,电机,发声等部分都介绍一遍。不过现在看来有些同学很心急,希望早点看到“核心代码”,所以我提前把解魔方的算法写出来。其实魔方的算法网上有很多,只要你耐心并且有效的使用搜索引擎,会发现上个世纪就已经有人公布算法或源代码了,例如
算法:http://www.zunny.com/RUBIK.HTM
代码:http://tomas.rokicki.com/cubecontest/

不过我做第一版的时候,还是决定自己动手写算法。原因很简单:我玩魔方很多年了,把玩法转成算法也是我的目标之一。在写程序之前,我画了以下的几张草图:

魔方算法的草稿

话说曾经有位同事本打算和我一起做萝卜头的,看了这些草图以后,决定还是继续打游戏更靠谱。这不禁让我想起一首歌“1979年,那是一个春天,有一位老人在中国的南海边画了一个圈…” 这位老同志一定是资深软件架构师,改革开放这么宏伟的事情,画个圈就搞定了。
这样说来我这个草图是太复杂了,难怪把人吓跑了。今天特地又重画了些好看的图,以便大家理解。

魔方表示法
算法的第一个问题就是,怎么用数学方式描述一个魔方状态。我的做法是把魔方想象成一个纸盒子,沿边缝剪开铺平,就形成了六个面,我按照图里的顺序给它们编了号。
每个面又包含了9个颜色小方块,我也按照图中的顺序给它们编了号。

魔方的数组表示法

这样一来,立体的魔方就变成了一个 6*9 的数组。例如下面是一个普通的被打乱的魔方:

  1. static String SideColors[] = {
  2. "orgorwwoo",
  3. "oyggbobrg",
  4. "yyrgowwbw",
  5. "yrybgybbo",
  6. "gwwyybror",
  7. "bgrwwrbgy"
static String SideColors[] = {
  "orgorwwoo",
  "oyggbobrg",
  "yyrgowwbw",
  "yrybgybbo",
  "gwwyybror",
  "bgrwwrbgy"

魔方坐标系:
啥?怎么又有坐标系,刚才的表示法不就完全描述了一个魔方吗?没错,但是咱们的萝卜头每次只能旋转魔方的最下面一层,假设我们需要旋转最上面一层,就必须先把它翻到下面。
请注意在翻跟头的过程中,魔方本身并没有变化,只是坐标系变了。所以还需要一个坐标系来对应萝卜头的空间:

魔方坐标系

状态变化
正如刚才所说,魔方在萝卜头的数字世界里有两种变化形式:1,翻跟头;2,旋转某一面。
每次状态变化都会造成SideColors数组发生变化,这种转换用最简单的查表法就可以搞定:

坐标变化的大概示意图,坐标变化没啥难度,主要看耐心

例如,这是一段旋转底面后状态转换的代码:

  1. public static void RotateBottomSide(boolean ClockWise) throws Exception
  2. {
  3. int temp=0;
  4. int i;
  5. CopyMatrics(2,6,ClockWise?2:1); //Bottom ClockWise = Top Anti-ClockWise
  6. CopyMatrics(6,2,0);
  7. if(ClockWise)
  8. {
  9. for(i=0;i<3;i++)
  10. {
  11. temp=Sides[5][0][i];
  12. Sides[5][0][i]=Sides[3][2-i][0];
  13. Sides[3][2-i][0]=Sides[4][2][2-i];
  14. Sides[4][2][2-i]=Sides[1][i][2];
  15. Sides[1][i][2]=temp;
  16. }
  17. }
  18. else
  19. {
  20. for(i=0;i<3;i++)
  21. {
  22. temp=Sides[5][0][i];
  23. Sides[5][0][i]=Sides[1][i][2];
  24. Sides[1][i][2]=Sides[4][2][2-i];
  25. Sides[4][2][2-i]=Sides[3][2-i][0];
  26. Sides[3][2-i][0]=temp;
  27. }
  28. }
  29. }
public static void RotateBottomSide(boolean ClockWise) throws Exception
{
 int temp=0;
 int i;

 CopyMatrics(2,6,ClockWise?2:1); //Bottom ClockWise = Top Anti-ClockWise
 CopyMatrics(6,2,0);
 if(ClockWise)
 {
  for(i=0;i<3;i++)
  {
   temp=Sides[5][0][i];
   Sides[5][0][i]=Sides[3][2-i][0];
   Sides[3][2-i][0]=Sides[4][2][2-i];
   Sides[4][2][2-i]=Sides[1][i][2];
   Sides[1][i][2]=temp;
  }
 }
 else
 {
  for(i=0;i<3;i++)
  {
   temp=Sides[5][0][i];
   Sides[5][0][i]=Sides[1][i][2];
   Sides[1][i][2]=Sides[4][2][2-i];
   Sides[4][2][2-i]=Sides[3][2-i][0];
   Sides[3][2-i][0]=temp;
  }
 }
}

CFOP解法
这是由一位叫Jessica Fridrich女士发明的一种速解法,是目前世界上最流行的方块解法。
CROSS:字面上的意思为“十字”,是Fridrich Method中的第一步骤。
F2L:是“First 2 Layer”的缩写,意思为“一、二层”,是Fridrich Method中的第二步骤。
OLL:是“Orientation of Last Layer”的缩写,意思为“最后一层的角块排序”,这是Fridrich Method中的第三个步骤。
PLL:是“Permutation of Last Layer”的缩写,意思为“最后一层的排序”,这是Fridrich Method中的第四步骤。
CFOP:是Fridrich Method的的别称,就是四个步骤“Cross、F2L、OLL、PLL”原文的第一个字母合起来而成的。

上面这些文字比较费解,看下面的图就比较清楚了:

魔方的CFOP入门解法

或者你可以去魔方小站或者魔方吧看更详细的教程。

CFOP解法的实现
这一部分比较繁琐,输入玩法公式的输入,按照上面的步骤实现以下函数:

  1. TopCross();
  2. TopCorner();
  3. SecondLayer();
  4. BottomCross();
  5. BottomCorner();
  6. ThirdLayerCorner();
  7. ThirdLayerCornerSnap();
  8. ThirdLayerBorderSnap();
TopCross();
TopCorner();
SecondLayer();
BottomCross();
BottomCorner();
ThirdLayerCorner();
ThirdLayerCornerSnap();
ThirdLayerBorderSnap();

CFOP算法的源代码可以点这里下载
通过这个CFOP算法,萝卜头完成了第一版:http://v.youku.com/v_show/id_XNDcwMDQ3NDQ=.html

这个算法的最大问题就是步骤太多,一般来说要120步左右,平均时间12分钟,大多数观众等不到转完就睡着了……
因为这个原因,我改用了一个更快的算法。写博客真是挺累啊,这个算法下次再介绍,心急的同学请看下面这个链接:
http://tomas.rokicki.com/cubecontest/ 点最上面的Winners,我用的是第二名的算法。

解魔方的机器人攻略17 – 魔方CFOP算法的更多相关文章

  1. 解魔方的机器人攻略13 – 安装Lejos(上)

    由 动力老男孩 发表于 2009/12/27 16:58:23 Firmware(固件)相当于是机器人的操作系统,乐高NXT出厂时已经内置了一套Firmware,并且配备了非常强大的LabVIEW开发 ...

  2. 解魔方的机器人攻略15 – 安装 Eclipse

    由 动力老男孩 发表于 2009/12/27 17:40:49 在远古时代,程序员们通常用写字板来编写Java程序,然后用Javac.exe和Java.exe来编译和执行.对于NXT来说,对应的命令是 ...

  3. 解魔方的机器人攻略14 – 安装Lejos(下)

    由 动力老男孩 发表于 2009/12/27 17:16:11 第四步:安装Lejos 登陆 Lejos 主页点击 NXT 图片进入 Lejos 下载页面,点击 NXJ 的下载链接: 下载完成后将下载 ...

  4. VSCode插件开发全攻略(一)概览

    文章索引 VSCode插件开发全攻略(一)概览 VSCode插件开发全攻略(二)HelloWord VSCode插件开发全攻略(三)package.json详解 VSCode插件开发全攻略(四)命令. ...

  5. linux shell 脚本攻略学习20--awk命令入门详解

    awk生于1977年,创始人有三个,分别为 Alfred Aho,Peter Weinberger, 和 Brian Kernighan,名称源于三个创始人的姓的首字母. 作用:处理文本文件. awk ...

  6. Python 自动化测试全攻略:五种自动化测试模型实战详解

    随着移动互联网的发展,软件研发模型逐步完善,软件交付质量越来越受到软件公司的重视,软件测试技术特别是自动化测试技术开始在软件系统研发过程中发挥着越来越重要的作用. 与传统的手工测试技术相比,自动化测试 ...

  7. 使用python3.7配置开发钉钉群自定义机器人(2020年新版攻略)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_132 最近疫情比较严重,很多公司依靠阿里旗下的办公软件钉钉来进行远程办公,当然了,钉钉这个产品真的是让人一言难尽,要多难用有多难用 ...

  8. VSCode插件开发全攻略(三)package.json详解

    更多文章请戳VSCode插件开发全攻略系列目录导航. package.json 在详细介绍vscode插件开发细节之前,这里我们先详细介绍一下vscode插件的package.json写法,但是建议先 ...

  9. 图文详解:阿里宠儿【小兔】RabbitMQ的养成攻略

随机推荐

  1. shell文本处理工具总结

    shell文本处理工具总结 为了效率,应该熟练的掌握自动化处理相关的知识和技能,能力就表现在做同样的一件事情,可以做的很好的同时,耗时还很短. 再次总结shell文本处理的相关规则,对提高软件调试效率 ...

  2. NVIDIA/DIGITS:Building DIGITS

    在 Prerequisites中的 sudo apt-get update命令发生错误: W: GPG 错误:http://developer.download.nvidia.com/compute/ ...

  3. Edu 0空投合约源码

    https://etherscan.io/address/0xa0872ee815b8dd0f6937386fd77134720d953581#code pragma solidity ^0.4.18 ...

  4. 【bzoj4756】[Usaco2017 Jan]Promotion Counting 离散化+树状数组

    原文地址:http://www.cnblogs.com/GXZlegend/p/6832263.html 题目描述 The cows have once again tried to form a s ...

  5. JS获取照片拍摄的角度属性,用于旋转控制

    我工作十余年,从负责一个模块,到负责一个产品,再到负责整个支付平台的架构设计,包括业务架构.产品架构到应用架构,再到技术架构,是一个从点到面逐渐转型的过程,同样是个“自相似”的现象,我一开始写博客,再 ...

  6. [poj] 3068 "Shortest" pair of paths || 最小费用最大流

    [原题](http://poj.org/problem?id=3068) 给一个有向带权图,求两条从0-N-1的路径,使它们没有公共点且边权和最小 . //是不是像传纸条啊- 是否可行只要判断最后最大 ...

  7. BZOJ 1876 [SDOI2009] SuperGcd | PY好题

    题面就是让你求两个超级大整数,求GCD 题解: 题目本意应该是出题人想考考高精度取膜 但是可以通过一种神奇的Stein算法来做 由J. Stein 1961年提出的Stein算法很好的解决了欧几里德算 ...

  8. Educational Codeforces Round 22 E. Army Creation

    Educational Codeforces Round 22 E. Army Creation 题意:求区间[L,R]内数字次数不超过k次的这些数字的数量的和 思路:和求区间内不同数字的数量类似,由 ...

  9. 叶落归根(hometown)

    叶落归根(hometown) 题目描述 叶落归根——树叶从树根生发出来,凋落后最终还是回到树根.比喻事物总有一定的归宿.接下来是题目. 给定一个n个点的有向图G(点的编号为1~n),一开始落叶(仅作为 ...

  10. git bash 如何进入某个盘的特定文件夹

    下面是用gitbash进入E:\the fifth version of ecard\epayment这个文件夹下 命令如下图所示: