前阵子,我用C#在Unity写了一个魔方小游戏,写到了后期我想写魔方的还原算法,但一开始就遇到难题,要想还原魔方首先就要知道魔方的状态,人是很容易识别魔方的颜色从而确定魔方的状态的,但要想机器也能看懂魔方的状态是件难事。
下面的是麻烦的推理,若不想看,可直接看:魔方状态2
看了很多贴,想借鉴一下前辈们的经验,但要么对于我说来很难,比如用机器直接识别魔方的颜色,用魔方的颜色反推魔方的状态,要么只有理论,没有一个确切的实现理论依据,思来想去决定自己写。
下面由我来描述一下我原创的魔方状态表示法:
最开始时,我首先想到的是用魔方块的所处位置(坐标)和魔方块在该位置时的旋转状态(旋转角度)来确定一个魔方块的唯一状态,理论可行我编写了魔方的一键打乱和状态保存及状态复原功能,以上三个功能全部实现,实践也可行。
接下来我就想,能不能反推,用魔方的坐标和魔方在该坐标的所处旋转状态,用确定魔方的唯一状态,最终在今天早上成功实现了,证明反推它也是可行的,只是整个过程有点艰辛。
开始的时候用的是四元数来保存旋转角度,那简直是一头雾水,根本找不到规律可言,但我还是找到了一条规律:一个欧拉角可用两个四元数来表示,然后就项目就推不下去了,我就去问了我的指导老师(当时我将这项目报了比赛,遗憾没选上),指导老师说不一定要用四元数,后来我改用了欧拉角。
果然很快发现了一个规律:
当要检测某个魔方块是否被还原,也就是检测魔方块的坐标和旋转角度是否正确。
棱块坐标还原检测:
如:要检测红白棱块,可以将红色魔方块的中心块的坐标加上白色魔方块的中心块的坐标,得到红白棱块坐标。
角块坐标还原检测:
如:要检测红白绿棱块,可以将红色魔方块的中心块的坐标加上白色魔方块的中心块的坐标加上绿色魔方块的中心块的坐标,得到红白绿棱块坐标。
棱块、角块旋转角度还原检测:
只要棱块或角块的旋转角度跟魔方最中心的魔方块旋转角度一样即为已还原。
当上述两个检测通过则表示某个魔方块成功被还原,那样能实时检测20个魔方块的实时还原情况。
但还是没有完成我要检测魔方状态的功能,而接下要讲的较为复杂:
由于我不知道如何反推,我采用了最笨的方法:穷尽法。
我先利用我写的一键打乱魔方功能,每次将魔方打乱12000次,利用unity的日志功能,记录每个魔方块旋转状态共有多少种,27个魔方块我都测试了,得出了一个结论:27个魔方块共有24种旋转状态
24是个神奇的数字,为什么每个魔方块都只有24种旋转状态呢?
后来我又想到棱块只能转到棱块位置,角块只能转到角块位置,则棱块有12种位置,角块有8种位置,棱块有两个面,角块有三个面,由是我有下面的猜想:
棱块12种位置*棱块两个面=24
角块8种位置*角块三个面=24
我罗列了48条记录,发现真的可以分类,且发现了个规律:
一个棱块在某个位置,有着两种旋转状态.
一个角块在某个位置,有着三种旋转状态.
后面实践证明每个棱块和角块都有这种特性。
刚开始我就在想,为什么会有这种情况的发生,经过反复猜想和证实,明白了:
棱块有:白红、白绿、白蓝、白橙、黄红、黄绿、黄蓝、黄橙、红绿、绿橙、蓝红、橙蓝
角块有:白绿橙、白橙蓝、白蓝红、白红绿、黄绿橙、黄橙蓝、黄蓝红、黄红绿
棱块的位置有:UF、UR、UB、UL、DF、DR、DB、DL、FR、FL、BR、BL
角块的位置有:UFR、URB、UBL、ULF、DRF、DBR、DLB、DFL
以白色做为还原底,则白色中心块作为底面(D),黄色中心块为顶面(U),绿色中心块为前面(F),则:
棱块的正方向定义为:U、D、F、B
角块的正方向定义为:U、D
这样就可以定义一个魔方块的状态了,注意以上顺序不能随意对换,这样会导致最后反推结果是错误的。
如白红魔方块:
当它位置处于顶面时,若白色面处于U则为旋转状态为0,红色面处于U则为旋转状态为1;
当它位置处于底面时,若白色面处于D则为旋转状态为0,红色面处于D则为旋转状态为1;
当它位置处于前面时,若白色面处于F则为旋转状态为0,红色面处于F则为旋转状态为1;
当它位置处于后面时,若白色面处于B则为旋转状态为0,红色面处于B则为旋转状态为1;
如白绿红魔方块:
当它位置处于顶面时,若白色面处于U则为旋转状态为0,绿色面处于U则为旋转状态为-1,
红色面处于U则为旋转状态为1;
当它位置处于底面时,若白色面处于D则为旋转状态为0,绿色面处于D则为旋转状态为-1,
红色面处于D则为旋转状态为1;
这也就是说,只要我将20个魔方块的状态全部罗列出来,就可以用魔方的坐标反推出它的旋转状态,由是我写了个程序,让程序让它帮我罗列了出来,总有480种(由于我不小心将红和橙混了,所以下面的结果,红这字与橙这字对调即可,只有图片有问题,其它没问题):
上面的图:24个位置是写错了,应该是24种旋转状态。