虚拟魔方状态表示法

本文介绍了魔方状态表示法的推导过程,包括建立魔方基准、已复原魔方状态表示、单个魔方块的状态表示以及结论的使用。通过魔方块的方位、颜色和状态来表示魔方的状态,可用于任意阶数的魔方。关键在于建立基准,确定魔方块的读取顺序,并根据颜色和位置推导出状态。示例中详细解释了棱块和角块的状态表示方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        已经过了大半年了,当初我想实现的魔方游戏自己复原也已经实现了,便对与魔方的状态表示当时也是一知半解,对之前的魔方状态法是不满意的,前几天有了思路就推导了出来, 不过没有之前踩的坑,也不会有现在的结论。

        这个魔方状态表示法,不以整体为推导法,而是以魔方块为导论,很早之前我就知道了一个结论,一个魔方块有24种状态(三阶魔方),但是不知道为何不知,现在大差不差,就以魔方块而言,有棱块与角块:

棱块:2种状态(0或1),12个可移动位置

角块:3种状态(0或1或2),8个可移动位置

中心块状态没太大意义。

三阶状态读取以实现,Demo源码请看:GitHub - 10555gff/mofanCubeStata

注:此结论可任意选择F面,得到的读取结果同样适用,也可用于2-多阶魔方的状态读取

注要看MofanRestore这文件,主要用到的代码是这一段

​
using System;
using UnityEngine;

public class MofanRestore : MonoBehaviour
{
    public static MofanRestore Instance = null;
    //当前读取的魔方块
    Transform curCubetransform;
    int curMoIndex;

    string str;
    string mofanColor;
    private void Start()
    {
        MofanRestore.Instance = this;
    }
    public string MofanStata(string mofanName)
    {
        int n= int.Parse(mofanName.Substring(1)) - 1;
        curCubetransform = GameManager.Instance.cubePrefabList[n].transform;
        mofanColor = mofanReColor(mofanName);
        //区别棱块与角块
        switch (mofanColor.Length)
        {
            case 2:
                curMoIndex = mofancubeStat();
                return string.Format("{0}{1}{2}{3}", str[0], mofanColor[curMoIndex], str[1], mofanColor[curMoIndex ^ 1]);
            case 3:
                string tmpStr = swapStr();
                return string.Format("{0}{1}{2}{3}{4}{5}", str[0], mofanColor[curMoIndex], str[1], tmpStr[0], str[2], tmpStr[1]);
        }
        return null;
    }

    //点乘判断,用得1或-1,返回0
    int reAbs(Vector3 v1, Vector3 v2)
    {
        return (int)Mathf.Abs(Vector3.Dot(v1, v2)) ^ 1;
    }
    #region 棱块判断块
    //用点乘判断是棱块状态
    int mofancubeStat()
    {
        Vector3 v3 = reInitVector();
        Vector3 v3fu = isCenter() ? this.transform.forward : this.transform.up;
        return reAbs(v3, v3fu);
    }

    //中间棱块与其它棱块分别定义初始轴
    Vector3 reInitVector()
    {
        switch (curCubetransform.name)
        {
            //中间层定义初始轴方向
            case "M20":
            case "M2":
            case "M26":
            case "M8":
                return curCubetransform.forward;
            //其它层定义初始轴方向
            default:
                return curCubetransform.up;
        }
    }

    //棱块的位置,是位置!!! 是否在中间层
    bool isCenter()
    {
        str = pType(curCubetransform.position.ToString());
        if (str[0] != 'F' && str[0] != 'B') return false;
        return true;
    }
    #endregion

    #region 角块判断块
    //用点乘判断是角块状态
    int mofancubeSamStat()
    {
        Vector3 v1 = curCubetransform.up;
        Vector3 v2 = curCubetransform.forward;
        Vector3 v3 = curCubetransform.right;
        Vector3 vtup = this.transform.up;
        //依次对比
        if (reAbs(v1, vtup) == 0)
        {
            //未旋转
            return 0;
        }else if (reAbs(v2, vtup) == 0)
        {
            //顺时钟旋转
            return 1;
        }
        else if (reAbs(v3, vtup) == 0)
        {
            //逆时钟旋转
            return 2;
        }
        return -1;
    }

    string swapStr()
    {
        str = pType(curCubetransform.position.ToString());
        curMoIndex = mofancubeSamStat();
        char a = mofanColor[(curMoIndex + 1) % 3];
        char b = mofanColor[(curMoIndex + 2) % 3];
        //判断某个角块所处位置,同一个角块,不同位置有着两种不同状态
        switch (str)
        {
            case "UFR":
            case "DFL":
            case "DBR":
            case "UBL":
                return isEn() ? $"{a}{b}" : $"{b}{a}";
            case "DFR":
            case "UFL":
            case "UBR":
            case "DBL":
                return isEn() ? $"{b}{a}" : $"{a}{b}";
        }
        return "  ";
    }

    //判断相反,旁边全是敌人,对面才是友军
    bool isEn()
    {
        switch (curCubetransform.name) {
            case "M21":
            case "M9":
            case "M1":
            case "M25":
                return true;
            case "M3":
            case "M27":
            case "M19":
            case "M7":
                return false;
        }
        return false;
    }
    #endregion

    //总20个位置,位置转成可读字符编号
    public string pType(string s)
    {
        switch (s)
        {
            #region 棱块
            //顶棱
            case "(0.0, 1.0, -1.0)":
                return "UF";
            case "(1.0, 1.0, 0.0)":
                return "UR";
            case "(0.0, 1.0, 1.0)":
                return "UB";
            case "(-1.0, 1.0, 0.0)":
                return "UL";
            //底棱
            case "(0.0, -1.0, -1.0)":
                return "DF";
            case "(1.0, -1.0, 0.0)":
                return "DR";
            case "(0.0, -1.0, 1.0)":
                return "DB";
            case "(-1.0, -1.0, 0.0)":
                return "DL";
            //前侧棱
            case "(1.0, 0.0, -1.0)":
                return "FR";
            case "(-1.0, 0.0, -1.0)":
                return "FL";
            //后侧棱
            case "(1.0, 0.0, 1.0)":
                return "BR";
            case "(-1.0, 0.0, 1.0)":
                return "BL";
            #endregion
            #region 角块
            //顶角块
            case "(1.0, 1.0, -1.0)":
                return "UFR";
            case "(-1.0, 1.0, -1.0)":
                return "UFL";
            case "(1.0, 1.0, 1.0)":
                return "UBR";
            case "(-1.0, 1.0, 1.0)":
                return "UBL";

            //底角块
            case "(1.0, -1.0, -1.0)":
                return "DFR";
            case "(-1.0, -1.0, -1.0)":
                return "DFL";
            case "(1.0, -1.0, 1.0)":
                return "DBR";
            case "(-1.0, -1.0, 1.0)":
                return "DBL";
            #endregion
            default:
                return "";
        }
    }

    //魔方块编号转对应颜色
    public string mofanReColor(string mofanName)
    {
        switch (mofanName)
        {
            #region 中心块
            case "M11":
                return "绿";
            case "M15":
                return "黄";
            case "M5":
                return "红";
            case "M23":
                return "橙";
            case "M17":
                return "蓝";
            case "M13":
                return "白";
            #endregion
            #region 角块
            case "M21":
                return "黄绿橙";
            case "M3":
                return "黄绿红";
            case "M27":
                return "黄蓝橙";
            case "M9":
                return "黄蓝红";
            case "M19":
                return "白绿橙";
            case "M1":
                return "白绿红";
            case "M25":
                return "白蓝橙";
            case "M7":
                return "白蓝红";
            #endregion
            #region 棱块
            case "M20":
                return "绿橙";
            case "M2":
                return "绿红";
            case "M26":
                return "蓝橙";
            case "M8":
                return "蓝红";

            case "M12":
                return "黄绿";
            case "M24":
                return "黄橙";
            case "M6":
                return "黄红";
            case "M18":
                return "黄蓝";

            case "M10":
                return "白绿";
            case "M22":
                return "白橙";
            case "M4":
                return "白红";
            case "M16":
                return "白蓝";
                #endregion
        }
        return "";
    }

    internal string readMofanOrder(string v)
    {
        throw new NotImplementedException();
    }

    internal string readMofanFixed(string v, bool isHaveColour)
    {
        throw new NotImplementedException();
    }
}

​

现在开始推:

1、建立魔方基准

        给两个已复原一模一样的魔方,如何确认这两个魔方的状态相同,即两个魔方可以重叠在一起,这样就要确保两个魔方的方位是相同的,如何保证方位是相同,那就基准,如果基准是相同的,那么两个魔方状态相同,这里用到的是魔方的F面与U面为基准,若两个魔方的F面和U面方位相同,则两个魔方状态相同。

        同理,要想表示魔方的状态,必然要建立一个基准,则以魔方为原点坐标,魔方的绿色面为F面,魔方的黄色面为U面为基准。

        当基准建立好后,还要确立魔方块的读取符号的先后顺序,类型于运算符的优先级,这个也很重要,则以  U/D 与 F/B 与 R/L (从左到右)依次降级。

2、已复原魔方状态表示

按照上面的基准,则可表示为:

F          U        L        R        B         D

绿        黄       红      橙       蓝        白

---------------------------------------------------------------------------------------------------------------------------------

棱块:                                                    对应的符号:

绿橙、绿红、蓝橙、蓝红                       FR、FL、BR、BL     

黄绿、黄橙、黄红、黄蓝                       UF、UR、UL、UB     

白绿、白橙、白红、白蓝                       DF、DR、DL、DB     

---------------------------------------------------------------------------------------------------------------------------------

角块:                                                    对应的符号:

黄绿橙、黄绿红、黄蓝橙、黄蓝红        UFR、UFL、UBR、UBL

白绿橙、白绿红、白蓝橙、白蓝红        DFR、DFL、DBR、DBL

3、单个魔方块的状态表示

当上述的基准完成后,就可以尝试着去表示魔方块的状态了。

一个棱块有2种状态,一个角块有3种状态,那以绿红棱块为例去推导,在绿红棱块在已复原的位置,可以出现两种状态,一种是绿红(对应上面)、另一种是红绿,设绿红为状态0,那么红绿就是状态1,经过推导,得出以下结论:

当棱块在中间层时------》向F或B面开枪,击中棱块的某种颜色

当棱块在顶或底层时------》向U或D面开枪,击中棱块的某种颜色

棱块的某种颜色是同一种颜色。

举例:

绿橙棱块,击中绿色为状态0,橙色为状态1

F绿L橙棱块,在F面开枪,则击中绿色,状态则为0

F橙L绿棱块,在F面开枪,则击中橙色,状态则为1

U绿F橙棱块,在U面开枪,则击中绿色,状态则为0

U橙F绿棱块,在U面开枪,则击中橙色,状态则为1

即绿橙为状态0,橙绿为状态1。

这个时候可能就有人说了,什么就状态0和状态1了,有没有科学根据的。

不过这个确实有,它所确认状态依靠的是之前建立的基准,就像是二维坐标有X轴与Y轴,就可以表示一个点,这里类似如此,还是以绿橙棱块为例,它的绿色面作法向量,当绿橙棱块在中间层时,让它的法向量与F面法向量作比较,若平行则为状态0,垂直相交则为状态1;当绿橙棱块在顶或底层时,让它的法向量与U面法向量作比较,若平行则为状态0,否则为状态1(垂直)。

用的就是它的相对方向的关系,有点局部坐标的意思。

---------------------------------------------------------------------------------------------------------------------------------

当角块在顶或底层时------》向U或D面开枪,击中棱块的某种颜色

棱块的某种颜色对应着魔方块的某种状态

举例:

黄绿橙角块,击中黄色为状态0,绿色为状态1,橙色为状态2

---------------------------------------------------------------------------------------------------------------------------------

4、结论的使用

随机抽取一个棱块黄红色,假设这个魔方是游戏引擎创建出来的,若知道这个黄红色魔方块在UF位置,该如何读取此魔方块的状态。

 前面第二节可知,黄红对应状态为0,红黄状态为1,再用第三个点,当棱块在顶或底层时------》向U或D面开枪,击中棱块的某种颜色,在U面开枪击中黄色,则状态为0,它的黄色面法向量与U面法向量平行。

位置是UF,状态为0,状态为0对应则为黄红,则魔方块状态为U黄F红。

---------------------------------------------------------------------------------------------------------------------------------

再抽取一个棱块绿红色:

 前面第二节可知,绿红对应状态为0,红绿状态为1,击中颜色为红色,读出状态为1,在位置处于FR,状态为1,则对应红绿,则魔方块状态为F红R绿。

这个方法可以在确认基准后,将魔方的状态转换为位置加一个状态数,就可以表示魔方块的状态,很简明的读取到魔方的状态信息;基准也很容易换,只要将F/B与U/D与L/R对应好颜色即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值