コード例 #1
0
                private BlockSet ExploreNewCoset(BlockSet startState, CubeAction generator)
                {
                    bool foundNew = false;

                    var newState = new BlockSet(startState);

                    generator.Act(newState.State);

                    // To verify generators truely stablizes Stablized BlockSet
                    if (Utils.ShouldVerify())
                    {
                        foreach (var stablePos in Stablized.Indexes)
                        {
                            if (!newState.State.Blocks[stablePos]
                                .Equals(startState.State.Blocks[stablePos]))
                            {
                                throw new ArgumentException();
                            }
                        }
                    }

                    if (!OrbitToCoset.ContainsKey(newState))
                    {
                        foundNew = true;

                        var startCoset = OrbitToCoset[startState];
                        Utils.DebugAssert(startCoset != null);

                        var newCoset = generator.Mul(startCoset);
                        newCoset.Simplify(CubeAction.SimplifyLevel.Level0);
                        OrbitToCoset.Add(newState, newCoset);
                    }

                    return(foundNew ? newState : null);
                }
コード例 #2
0
                private HashSet <BlockSet> ExploreExistingCosetsByNewGenerator(CubeAction newGenerator)
                {
                    var newStates = new HashSet <BlockSet>();

                    int walkedCount    = 0;
                    var needWalkStates = new HashSet <BlockSet>(OrbitToCoset.Keys);

                    foreach (var startState in needWalkStates)
                    {
                        walkedCount++;

                        var newState = ExploreNewCoset(startState, newGenerator);
                        if (newState != null)
                        {
                            newStates.Add(newState);

                            Console.WriteLine(
                                $"Stablized[{Stablized.Indexes.Count}] " +
                                $"ExploreNewGeneratorOnExistingCosets: foundCount/needWalk/total=" +
                                $"{newStates.Count}/{needWalkStates.Count - walkedCount}/{OrbitToCoset.Count} " +
                                $"newState=[{newState}] newCoset=[{OrbitToCoset[newState].Count()}] " +
                                $"startState=[{startState}] generator=[{newGenerator.Count()}]");
                        }
                    }

                    return(newStates);
                }
コード例 #3
0
                private HashSet <CubeAction> ObtainGeneratorsOfStablizerSubgroupIncrementally(
                    CubeAction newGenerator, HashSet <BlockSet> newStates)
                {
                    var newSubgroupGenerators = new HashSet <CubeAction>();

                    foreach (var generator in Generators)
                    {
                        bool isNewGenerator = generator.Equals(newGenerator);
                        foreach (var state in OrbitToCoset.Keys)
                        {
                            var leftCoset = OrbitToCoset[state];
                            Utils.DebugAssert(leftCoset != null);

                            if (!isNewGenerator && !newStates.Contains(state))
                            {
                                // Old generator, old coset state
                                continue;
                            }

                            var subgroupGenerator = ObtainGeneratorOfStablizerSubgroup(generator, leftCoset);
                            if (!subgroupGenerator.Equals(new CubeAction()) && !newSubgroupGenerators.Contains(subgroupGenerator))
                            {
                                Utils.DebugAssert(ToStablize.IsStablizedBy(subgroupGenerator));
                                newSubgroupGenerators.Add(subgroupGenerator);

                                /* No need to print because we don't know whether the generator is redundant here. */
                            }
                        }
                    }

                    return(newSubgroupGenerators);
                }
コード例 #4
0
            public static void VerifyGroupActionAssociaty()
            {
                for (int caseIdx = 0; caseIdx < 100; caseIdx++)
                {
                    CubeAction a = CubeAction.Random(Utils.GlobalRandom.Next(1, 20));
                    CubeAction b = CubeAction.Random(Utils.GlobalRandom.Next(1, 15));
                    CubeAction c = CubeAction.Random(Utils.GlobalRandom.Next(1, 10));

                    CubeAction ab = a.Mul(b);
                    CubeAction bc = b.Mul(c);

                    CubeState origState = CubeAction.RandomCube(Utils.GlobalRandom.Next(1, 20));

                    CubeState a_b_c_state = new CubeState(origState);
                    c.Act(a_b_c_state);
                    b.Act(a_b_c_state);
                    a.Act(a_b_c_state);

                    CubeState ab_c_state = new CubeState(origState);
                    c.Act(ab_c_state);
                    ab.Act(ab_c_state);

                    CubeState a_bc_state = new CubeState(origState);
                    bc.Act(a_bc_state);
                    a.Act(a_bc_state);

                    Utils.DebugAssert(a_b_c_state.Equals(ab_c_state));
                    Utils.DebugAssert(a_b_c_state.Equals(a_bc_state));
                }
            }
コード例 #5
0
        public override LocalAction checkMutation(LocalApplication app, Index p, Vector3 diff, float voxelSize)
        {
            CubeApp cApp = (CubeApp)app;
            CubeAction action = new CubeAction();
            if (p.depth >= app.tree.maximumDetail)
                voxelSize *= 0.5f;

            action.percentInside = 1;
            bool outside = false;
            bool inside = true;

            action.percentInside *= 1 - (2 - percentOverlapping(diff.x, cApp.halfDimension.x, voxelSize, ref outside, ref inside)
                - percentOverlapping(-diff.x, cApp.halfDimension.x, voxelSize, ref outside, ref inside));
            if (outside) return action;
            action.percentInside *= 1 - (2 - percentOverlapping(diff.y, cApp.halfDimension.y, voxelSize, ref outside, ref inside)
                - percentOverlapping(-diff.y, cApp.halfDimension.y, voxelSize, ref outside, ref inside));
            if (outside) return action;
            action.percentInside *= 1 - (2 - percentOverlapping(diff.z, cApp.halfDimension.z, voxelSize, ref outside, ref inside)
                - percentOverlapping(-diff.z, cApp.halfDimension.z, voxelSize, ref outside, ref inside));
            if (outside) return action;

            action.modify = true;
            if (!overwriteShape || !inside)
                action.doTraverse = true;
            return action;
        }
コード例 #6
0
            public static void VerifyOpCountForAccelerationMap()
            {
                CubeState state = new CubeState();

                CubeAction actionNoAcc = CubeAction.Random(CubeAction.OpCountForAccelerationMap - 1);
                CubeAction actionAcc   = CubeAction.Random(CubeAction.OpCountForAccelerationMap);

                Console.WriteLine(
                    "Expecting timeNoAcc is similar to timeAcc, " +
                    "otherwise adjust CubeAction.OpCountForAccelerationMap");

                for (int i = 0; i < 5; i++)
                {
                    long timeStart = Utils.CurrentTimeMillis();

                    for (int j = 0; j < 500; j++)
                    {
                        actionNoAcc.Act(state);
                    }
                    long timeNoAcc = Utils.CurrentTimeMillis();

                    for (int j = 0; j < 500; j++)
                    {
                        actionAcc.Act(state);
                    }
                    long timeAcc = Utils.CurrentTimeMillis();

                    Console.WriteLine($"timeNoAcc={timeNoAcc - timeStart}ms, timeAcc={timeAcc - timeNoAcc}ms");
                }
            }
コード例 #7
0
            // Returns (i, j) that, i is the first element that the action doesn't stablize.
            // j is what it maps to at i. Obviously j > i. Note: returning (-1, -1) means the
            // action stablizes all
            public Tuple <int, int> GetActionPair(CubeAction action)
            {
                int pair_i = -1;
                int pair_j = -1;

                var actionMap = action.GetAccelerationMap();

                for (int idxInStablizerOrder = 0; idxInStablizerOrder < StablizingOrder.Count; idxInStablizerOrder++)
                {
                    int idxInActionMap = StablizingOrder[idxInStablizerOrder];
                    if (actionMap.ColorMap[idxInActionMap] == idxInActionMap)
                    {
                        continue;
                    }

                    pair_i = idxInStablizerOrder;
                    int pair_j_inActionMap = actionMap.ColorMap[idxInActionMap];
                    pair_j = IdxInStablizingOrder(pair_j_inActionMap);

                    Utils.DebugAssert(pair_j > pair_i);
                    break;
                }

                return(new Tuple <int, int>(pair_i, pair_j));
            }
コード例 #8
0
            public bool IsStablizedBy(CubeAction action)
            {
                var actionCopy = new BlockSet(this);

                action.Act(actionCopy.State);

                return(this.Equals(actionCopy));
            }
コード例 #9
0
            public static void VerifyCubeTurnAround()
            {
                for (int caseIdx = 0; caseIdx < 100; caseIdx++)
                {
                    CubeState cubeState = CubeAction.RandomCube(Utils.GlobalRandom.Next(1, 30));
                    foreach (CubeOp.Type op in Enum.GetValues(typeof(CubeOp.Type)))
                    {
                        var       action       = new CubeAction(new int[] { (int)op });
                        CubeState newCubeState = new CubeState(cubeState);

                        for (int i = 0; i < CubeState.TurnAround; i++)
                        {
                            action.Act(newCubeState);
                        }

                        Utils.DebugAssert(newCubeState.Equals(cubeState));
                    }
                }

                for (int caseIdx = 0; caseIdx < 100; caseIdx++)
                {
                    CubeState cubeState = CubeAction.RandomCube(Utils.GlobalRandom.Next(1, 30));
                    foreach (CubeOp.Type op in Enum.GetValues(typeof(CubeOp.Type)))
                    {
                        var       action       = new CubeAction(new int[] { (int)op, (int)op, (int)op });
                        CubeState newCubeState = new CubeState(cubeState);

                        for (int i = 0; i < CubeState.TurnAround; i++)
                        {
                            action.Act(newCubeState);
                        }

                        Utils.DebugAssert(newCubeState.Equals(cubeState));
                    }
                }

                for (int caseIdx = 0; caseIdx < 100; caseIdx++)
                {
                    CubeState cubeState = CubeAction.RandomCube(Utils.GlobalRandom.Next(1, 30));
                    foreach (CubeOp.Type op in Enum.GetValues(typeof(CubeOp.Type)))
                    {
                        var       action       = new CubeAction(new int[] { (int)op, (int)op });
                        CubeState newCubeState = new CubeState(cubeState);

                        for (int i = 0; i < CubeState.TurnAround / 2; i++)
                        {
                            action.Act(newCubeState);
                        }

                        Utils.DebugAssert(newCubeState.Equals(cubeState));
                    }
                }
            }
コード例 #10
0
    public void UndoLastMove()
    {
        if (currentAction == null && actionList.Count != 0)
        {
            //Debug.Log("Trying Replay");
            CubeAction lastAction = actionList[actionList.Count - 1];
            actionList.Remove(lastAction);
            lastAction.GetUndoAction().StartAction();
            currentAction = lastAction.GetUndoAction();
        }

        processUndoRedoPossible(actionList.Count > 0);
    }
コード例 #11
0
            public static void VerifyIdentity()
            {
                for (int caseIdx = 0; caseIdx < 100; caseIdx++)
                {
                    CubeAction a  = CubeAction.Random(Utils.GlobalRandom.Next(1, 10));
                    CubeAction id = new CubeAction();

                    CubeAction aid = a.Mul(id);
                    CubeAction ida = id.Mul(a);

                    Utils.DebugAssert(a.Equals(aid));
                    Utils.DebugAssert(a.Equals(ida));
                }
            }
コード例 #12
0
            public static void VerifyAssociaty()
            {
                for (int caseIdx = 0; caseIdx < 100; caseIdx++)
                {
                    CubeAction a = CubeAction.Random(Utils.GlobalRandom.Next(1, 10));
                    CubeAction b = CubeAction.Random(Utils.GlobalRandom.Next(1, 15));
                    CubeAction c = CubeAction.Random(Utils.GlobalRandom.Next(1, 20));

                    CubeAction ab_c = a.Mul(b).Mul(c);
                    CubeAction a_bc = a.Mul(b.Mul(c));

                    Utils.DebugAssert(ab_c.Equals(a_bc));
                    Utils.DebugAssert(a_bc.Equals(ab_c));
                }
            }
コード例 #13
0
            public static void VerifyReverse()
            {
                for (int caseIdx = 0; caseIdx < 100; caseIdx++)
                {
                    CubeAction a  = CubeAction.Random(Utils.GlobalRandom.Next(1, 20));
                    CubeAction ra = a.Reverse();
                    CubeAction id = new CubeAction();

                    CubeAction ara = a.Mul(ra);
                    CubeAction raa = ra.Mul(a);

                    Utils.DebugAssert(id.Equals(ara));
                    Utils.DebugAssert(id.Equals(raa));
                }
            }
コード例 #14
0
        public override Voxel mutate(LocalApplication app, Index p, LocalAction action, Voxel original)
        {
            CubeAction cAction      = (CubeAction)action;
            byte       newOpacity   = (byte)((original.averageOpacity() * (1 - cAction.percentInside) + value.averageOpacity() * (cAction.percentInside)));
            byte       newSubstance = original.averageMaterialType();

            if (newOpacity >= 2 * original.averageOpacity() ||
                (overwriteSubstance && cAction.percentInside > 0.5))
            {
                newSubstance = value.averageMaterialType();
            }
            if (!overwriteShape)
            {
                newOpacity = original.averageOpacity();
            }
            return(new Voxel(newSubstance, newOpacity));
        }
コード例 #15
0
        private void ForEachInCube(CubeAction action)
        {
            for (var y = 0; y < _area.Height; y++)
            {
                for (var x = 0; x < _area.Width; x++)
                {
                    var offset = _area.GetOffset(x, y);

                    var plantInfo = _plantInfos[offset];
                    var blockInfo = _blockInfos[offset];

                    action(x, y, ref plantInfo, ref blockInfo);

                    _plantInfos[offset] = plantInfo;
                    _blockInfos[offset] = blockInfo;
                }
            }
        }
コード例 #16
0
                /// <summary>
                /// By (slightly changed version of) Prop 4.7 in Group Theory J.S. Milne, we know the
                /// orbit of the blocks we are observing, is 1-on-1 mapping to the set of *right* cosets
                /// divided by stablizer subgroup of the blocks we are observing.
                ///
                /// See: https://www.jmilne.org/math/CourseNotes/GT310.pdf
                ///
                /// In this way, by traversal through each possible state of the the blocks we are observing,
                /// we can discover each of the cosets of the stablizer subgroup, which will later be input
                /// into Schreier subgroup lemma to obtain the stablizer subgroup's generators.
                /// </summary>
                private HashSet <BlockSet> ExploreOrbitToCosetIncrementally(CubeAction newGenerator)
                {
                    if (null == OrbitToCoset)
                    {
                        OrbitToCoset = new Dictionary <BlockSet, CubeAction>()
                        {
                            { new BlockSet(ToStablize), new CubeAction() }
                        };
                    }

                    var newStates         = new HashSet <BlockSet>();
                    var fullyWalkedStates = new HashSet <BlockSet>(OrbitToCoset.Keys);

                    while (true)
                    {
                        int foundCount = 0;

                        if (!Generators.Contains(newGenerator))
                        {
                            var localNewStates = ExploreExistingCosetsByNewGenerator(newGenerator);

                            foundCount += localNewStates.Count;
                            newStates.UnionWith(localNewStates);

                            Generators.Add(newGenerator);
                        }

                        {
                            var localNewStates = ExploreNewCosetsByExistingGenerator(fullyWalkedStates);

                            foundCount += localNewStates.Count;
                            newStates.UnionWith(localNewStates);

                            fullyWalkedStates = new HashSet <BlockSet>(OrbitToCoset.Keys);
                        }

                        if (foundCount <= 0)
                        {
                            break;
                        }
                    }

                    return(newStates);
                }
コード例 #17
0
                private CubeAction DetermineBelongingCoset(CubeAction e)
                {
                    var eState = new BlockSet(ToStablize);

                    e.Act(eState.State);

                    if (!OrbitToCoset.ContainsKey(eState))
                    {
                        return(null);
                    }

                    var cosetRepresentative = OrbitToCoset[eState];

                    if (Utils.ShouldVerify())
                    {
                        {
                            var cosetReprState = new BlockSet(ToStablize);
                            cosetRepresentative.Act(cosetReprState.State);
                            Utils.DebugAssert(cosetReprState.Equals(eState));
                        }

                        {
                            // States in orbit 1-to-1 maps to each *left* coset (gH). I.e.
                            // iff. e^(-1) * cosetRepresentative stablizes the BlockSet being
                            // observed.  This deduces that, group actions in same *left*
                            // coset, always act the BlockSet being observed to the same state.
                            var reCosetRep = e.Reverse().Mul(cosetRepresentative);
                            Utils.DebugAssert(Stablized.IsStablizedBy(reCosetRep));
                        }

                        {
                            // Iff. e * cosetRepresentative^(-1) stablizes the BlockSet being
                            // observed. This is the condition for *right* coset. It is not what
                            // we need here, and group actions in same *right* coset, may act the
                            // BlockSet being observed to different states.
                            var eRCosetRep = e.Mul(cosetRepresentative.Reverse());
                            // Utils.DebugAssert(observed.IsStablizedBy(eRCosetRep));  // Doesn't hold
                        }
                    }

                    return(cosetRepresentative);
                }
コード例 #18
0
                /// <summary>
                /// To obtain the generators of stablizer subgroup, by Schreier subgroup lemma as stated
                /// at https://www.jaapsch.net/puzzles/schreier.htm. We need to input the generators of
                /// group, and the sets of cosets of the stablizer subgroup.
                /// </summary>
                private CubeAction ObtainGeneratorOfStablizerSubgroup(
                    CubeAction generator, CubeAction leftCoset)
                {
                    // To match naming in Schreier subgroup lemma;
                    var s  = generator;
                    var r  = leftCoset;
                    var sr = s.Mul(r);

                    // In theory, sr's coset should always be already known. Because each known
                    // coset representative is generated by permutations of known generators.
                    // And we have already explore that. So permutations of known generators,
                    // i.e. sr, should never give us any new coset.
                    var cosetReprSr = DetermineBelongingCoset(sr);

                    Utils.DebugAssert(cosetReprSr != null);

                    var rCosetReprSr      = cosetReprSr.Reverse();
                    var subgroupGenerator = rCosetReprSr.Mul(sr);

                    return(subgroupGenerator);
                }
コード例 #19
0
        public override LocalAction checkMutation(LocalApplication app, Index p, Vector3 diff, float voxelSize)
        {
            CubeApp    cApp   = (CubeApp)app;
            CubeAction action = new CubeAction();

            if (p.depth >= app.tree.maxDetail)
            {
                voxelSize *= 0.5f;
            }

            action.percentInside = 1;
            bool outside = false;
            bool inside  = true;

            action.percentInside *= 1 - (2 - percentOverlapping(diff.x, cApp.halfDimension.x, voxelSize, ref outside, ref inside)
                                         - percentOverlapping(-diff.x, cApp.halfDimension.x, voxelSize, ref outside, ref inside));
            if (outside)
            {
                return(action);
            }
            action.percentInside *= 1 - (2 - percentOverlapping(diff.y, cApp.halfDimension.y, voxelSize, ref outside, ref inside)
                                         - percentOverlapping(-diff.y, cApp.halfDimension.y, voxelSize, ref outside, ref inside));
            if (outside)
            {
                return(action);
            }
            action.percentInside *= 1 - (2 - percentOverlapping(diff.z, cApp.halfDimension.z, voxelSize, ref outside, ref inside)
                                         - percentOverlapping(-diff.z, cApp.halfDimension.z, voxelSize, ref outside, ref inside));
            if (outside)
            {
                return(action);
            }

            action.modify = true;
            if (!inside)
            {
                action.doTraverse = true;
            }
            return(action);
        }
コード例 #20
0
    public CubeAction generateRandomAction()
    {
        int        random = UnityEngine.Random.Range(0, 5);
        CubeAction action = null;

        if (random == 0)
        {
            action = new ActionRotateZXClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetRowTiles(cubeTiles[UnityEngine.Random.Range(0, cubeTiles.Count - 1)])), true);
        }
        else if (random == 1)
        {
            action = new ActionRotateZXCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetRowTiles(cubeTiles[UnityEngine.Random.Range(0, cubeTiles.Count - 1)])), true);
        }
        else if (random == 2)
        {
            action = new ActionRotateZYClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnXTiles(cubeTiles[UnityEngine.Random.Range(0, cubeTiles.Count - 1)])), true);
        }
        else if (random == 3)
        {
            action = new ActionRotateZYCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnXTiles(cubeTiles[UnityEngine.Random.Range(0, cubeTiles.Count - 1)])), true);
        }
        else if (random == 4)
        {
            action = new ActionRotateYXClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnZTiles(cubeTiles[UnityEngine.Random.Range(0, cubeTiles.Count - 1)])), true);
        }
        else if (random == 5)
        {
            action = new ActionRotateYXCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnZTiles(cubeTiles[UnityEngine.Random.Range(0, cubeTiles.Count - 1)])), true);
        }
        if (action == null)
        {
            Debug.Log("ERROR");
        }
        action.SetTimeToComplete(0.3f);
        return(action);
    }
コード例 #21
0
    public static ActionSaveData CreateSaveData(CubeAction cubeAction)
    {
        ActionSaveData savedata = new ActionSaveData();

        if (cubeAction.GetType() == typeof(ActionRotateZXClockWise))
        {
            savedata.action = (int)ActionType.ZXClock;
        }
        else if (cubeAction.GetType() == typeof(ActionRotateZXCounterClockWise))
        {
            savedata.action = (int)ActionType.ZXCounterClock;
        }
        else if (cubeAction.GetType() == typeof(ActionRotateZYClockWise))
        {
            savedata.action = (int)ActionType.ZYClock;
        }
        else if (cubeAction.GetType() == typeof(ActionRotateZYCounterClockWise))
        {
            savedata.action = (int)ActionType.ZYCounterClock;
        }
        else if (cubeAction.GetType() == typeof(ActionRotateYXClockWise))
        {
            savedata.action = (int)ActionType.YXClock;
        }
        else if (cubeAction.GetType() == typeof(ActionRotateYXCounterClockWise))
        {
            savedata.action = (int)ActionType.YXCounterClock;
        }

        foreach (var cubeTile in cubeAction.GetCubeTileListReference())
        {
            savedata.cubeCollection.Add(cubeTile.GetComponent <CubeTileInfo>().GetID());
        }

        return(savedata);
    }
コード例 #22
0
    internal void LoadGame(MagicCubeSaveData savedata)
    {
        bIsLoading = true;
        foreach (var item in cubeTiles)
        {
            UnityEngine.Object.Destroy(item);
        }

        cubeTiles.Clear();
        collectionHelper = new CubeCollectionHelper(0);

        for (int i = 0; i < savedata.positions.Count; i++)
        {
            var temp = GameObject.Instantiate(cubeTileRef,
                                              savedata.positions[i].ToVector3()
                                              , savedata.rotations[i].ToQuaternion());
            collectionHelper.ProcessCubeTile(temp, temp.transform.position);
            temp.transform.SetParent(ownHolder.transform);
            cubeTiles.Add(temp);
            temp.GetComponent <CubeTileInfo>().SetID(savedata.cubeTileIDs[i]);
        }

        actionList.Clear();
        for (int i = 0; i < savedata.undoActions.Count; i++)
        {
            CubeAction        action             = null;
            List <GameObject> cubeTilesForAction = new List <GameObject>();
            foreach (var cubeID in savedata.undoActions[i].cubeCollection)
            {
                cubeTilesForAction.Add(cubeTiles.Find(ct => ct.GetComponent <CubeTileInfo>().GetID() == cubeID));
            }
            switch (savedata.undoActions[i].action)
            {
            case (int)ActionSaveData.ActionType.ZXClock:
                action = new ActionRotateZXClockWise(ownHolder, this, cubeTilesForAction, true);
                break;

            case (int)ActionSaveData.ActionType.ZXCounterClock:
                action = new ActionRotateZXCounterClockWise(ownHolder, this, cubeTilesForAction, true);
                break;

            case (int)ActionSaveData.ActionType.YXClock:
                action = new ActionRotateYXClockWise(ownHolder, this, cubeTilesForAction, true);
                break;

            case (int)ActionSaveData.ActionType.YXCounterClock:
                action = new ActionRotateYXCounterClockWise(ownHolder, this, cubeTilesForAction, true);
                break;

            case (int)ActionSaveData.ActionType.ZYClock:
                action = new ActionRotateZYClockWise(ownHolder, this, cubeTilesForAction, true);
                break;

            case (int)ActionSaveData.ActionType.ZYCounterClock:
                action = new ActionRotateZYCounterClockWise(ownHolder, this, cubeTilesForAction, true);
                break;
            }
            if (action == null)
            {
                actionList.Clear();
                break;
            }
            action.CompleteActionNoAnimation();
            actionList.Add(action);
        }

        timePassed = savedata.time;
        seconds    = savedata.time;
        updateTime(seconds);
        processUndoRedoPossible(actionList.Count > 0);
        bIsLoading = false;
    }
コード例 #23
0
    public void QuerySliceRotation(GameObject cubeTile, Collider startFace, MagicCubeBehaviour.SwipeDragDirection direction)
    {
        MagicCubeSide side = GetWhichSide(startFace);

        switch (side)
        {
        case MagicCubeSide.PosX:
            switch (direction)
            {
            case MagicCubeBehaviour.SwipeDragDirection.UP:
                currentAction = new ActionRotateYXClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnZTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.DOWN:
                currentAction = new ActionRotateYXCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnZTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.LEFT:
                currentAction = new ActionRotateZXClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetRowTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.RIGHT:
                currentAction = new ActionRotateZXCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetRowTiles(cubeTile)), true);
                break;

            default:
                break;
            }
            break;

        case MagicCubeSide.NegX:
            switch (direction)
            {
            case MagicCubeBehaviour.SwipeDragDirection.UP:
                currentAction = new ActionRotateYXClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnZTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.DOWN:
                currentAction = new ActionRotateYXCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnZTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.LEFT:
                currentAction = new ActionRotateZXClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetRowTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.RIGHT:
                currentAction = new ActionRotateZXCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetRowTiles(cubeTile)), true);
                break;

            default:
                break;
            }
            break;

        case MagicCubeSide.PosY:
            switch (direction)
            {
            case MagicCubeBehaviour.SwipeDragDirection.UP:
                currentAction = new ActionRotateYXClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnZTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.DOWN:
                currentAction = new ActionRotateYXCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnZTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.LEFT:
                currentAction = new ActionRotateZYClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnXTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.RIGHT:
                currentAction = new ActionRotateZYCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnXTiles(cubeTile)), true);
                break;

            default:
                break;
            }
            break;

        case MagicCubeSide.NegY:
            switch (direction)
            {
            case MagicCubeBehaviour.SwipeDragDirection.UP:
                currentAction = new ActionRotateYXClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnZTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.DOWN:
                currentAction = new ActionRotateYXCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnZTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.LEFT:
                currentAction = new ActionRotateZYClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnXTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.RIGHT:
                currentAction = new ActionRotateZYCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnXTiles(cubeTile)), true);
                break;

            default:
                break;
            }
            break;

        case MagicCubeSide.PosZ:
            switch (direction)
            {
            case MagicCubeBehaviour.SwipeDragDirection.UP:
                currentAction = new ActionRotateZYClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnXTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.DOWN:
                currentAction = new ActionRotateZYCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnXTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.LEFT:
                currentAction = new ActionRotateZXClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetRowTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.RIGHT:
                currentAction = new ActionRotateZXCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetRowTiles(cubeTile)), true);
                break;

            default:
                break;
            }
            break;

        case MagicCubeSide.NegZ:
            switch (direction)
            {
            case MagicCubeBehaviour.SwipeDragDirection.UP:
                currentAction = new ActionRotateZYClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnXTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.DOWN:
                currentAction = new ActionRotateZYCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetColumnXTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.LEFT:
                currentAction = new ActionRotateZXClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetRowTiles(cubeTile)), true);
                break;

            case MagicCubeBehaviour.SwipeDragDirection.RIGHT:
                currentAction = new ActionRotateZXCounterClockWise(ownHolder, this, new List <GameObject>(collectionHelper.GetRowTiles(cubeTile)), true);
                break;

            default:
                break;
            }
            break;

        default:
            break;
        }

        if (currentAction != null)
        {
            AddActionToUndoList(currentAction);
        }
    }
コード例 #24
0
        static void Main(string[] args)
        {
            string CONSOLE_OUTPUT_FILE = "console.out.txt";

            using (var fileWriter = new StreamWriter(File.Create(CONSOLE_OUTPUT_FILE)))
            {
                //
                // Setup
                //

                fileWriter.AutoFlush = true;

                var consoleMirrorFile = new Utils.MirroredWriter(fileWriter, Console.Out);
                Console.SetOut(consoleMirrorFile);

                //
                // Verifying basics
                //

                GroupTests.VerifyAll();

                //
                // Calculating the map to solve Rubik's Cube
                //

                CubeSolution cs = new CubeSolution();
                cs.SolveCosetMap();

                Console.Out.Flush();

                //
                // Dump the solved coset map of the cube
                //

                cs.DumpGSteps();
                Console.Out.Flush();

                //
                // Solve a Rubik's Cube
                //

                const int SETUP_ACTION_LENGTH_LIMIT = 1000;
                const int CASE_COUNT = 2;

                for (int caseIdx = 0; caseIdx < CASE_COUNT; caseIdx++)
                {
                    var setupAction = CubeAction.Random(
                        Utils.GlobalRandom.Next(SETUP_ACTION_LENGTH_LIMIT));
                    Console.WriteLine(
                        $"SolvingCube[case={caseIdx}]: " +
                        $"setupAction=[Size={setupAction.Count()}, Action=[{setupAction}]]");

                    CubeState setupState = new CubeState();
                    setupAction.Act(setupState);

                    CubeState solvingState = new CubeState(setupState);
                    var       steps        = cs.SolveCube(solvingState);

                    int stepIdx = 0;
                    foreach (var step in steps)
                    {
                        string actionStr = step.Item1.ToStringWithFormula();

                        Console.WriteLine(
                            $"SolvingCube[case={caseIdx}]: stepIdx={stepIdx} " +
                            $"stepAction=[Size={step.Item1.Count()}, Action=[{actionStr}]] " +
                            $"cubeState=[");
                        Console.WriteLine($"{step.Item2}]");

                        stepIdx++;
                    }

                    Console.Out.Flush();
                }

                //
                // Simplify the generate cosets
                //

                cs.SimplifyCosets();
                Console.Out.Flush();
            }
        }
コード例 #25
0
            public CubeAction FilterGeneratorIncrementally(CubeAction newGenerator)
            {
                if (AcceptedGeneratorCount >= GeneratorCountLimit)
                {
                    Utils.DebugAssert(AcceptedGeneratorCount == GeneratorCountLimit);
                    if (!Utils.ShouldVerify())
                    {
                        // To verify if generator limit reached, we won't be able to
                        // add more generators
                        return(null);
                    }
                }

                var pair = GetActionPair(newGenerator);

                if (pair.Item1 < 0)
                {
                    if (Utils.ShouldVerify())
                    {
                        Utils.DebugAssert(newGenerator.Equals(new CubeAction()));
                    }

                    return(null);
                }
                if (pair.Item1 <= StablizedIdx)
                {
                    // This means the newGenerator didn't stablize the required cube blocks
                    throw new ArgumentException();
                }

                CubeAction replacedGenerator;
                var        existingGenerator = ActionGrid[pair.Item1, pair.Item2];

                if (null == existingGenerator)
                {
                    Utils.DebugAssert(null == ActionGrid[pair.Item2, pair.Item1]);

                    var cyclePath = DetectCycle(
                        pair.Item1, pair.Item1, pair.Item2,
                        new List <Tuple <int, int> >()
                    {
                        new Tuple <int, int>(pair.Item1, pair.Item2)
                    });

                    if (null == cyclePath)
                    {
                        // Note: g's ActionPair is (i, j) doesn't means g^(-1) ActionPair is (j, i).
                        // We store g^(-1) here just for convenience. But g^(-1) must map j to i.
                        ActionGrid[pair.Item1, pair.Item2] = newGenerator;
                        ActionGrid[pair.Item2, pair.Item1] = newGenerator.Reverse();

                        Utils.DebugAssert(AcceptedGeneratorCount < GeneratorCountLimit);
                        AcceptedGeneratorCount++;

                        return(newGenerator);
                    }
                    else
                    {
                        //
                        // Temporarily put the newGenerator in. We will remove another generator
                        // to break the cycle.
                        //

                        ActionGrid[pair.Item1, pair.Item2] = newGenerator;
                        ActionGrid[pair.Item2, pair.Item1] = newGenerator.Reverse();

                        cyclePath         = RearrangeCycleFromSmallest(cyclePath);
                        replacedGenerator = CalculateCyclePathProduct(cyclePath);

                        ActionGrid[cyclePath[0].Item1, cyclePath[0].Item2] = null;
                        ActionGrid[cyclePath[0].Item2, cyclePath[0].Item1] = null;

                        if (Utils.ShouldVerify())
                        {
                            var replacedPair = GetActionPair(replacedGenerator);
                            if (replacedPair.Item1 >= 0)
                            {
                                // This ensures the recursive call will end
                                Utils.DebugAssert(replacedPair.Item1 > cyclePath[0].Item1);
                            }
                        }
                    }
                }
                else
                {
                    var reversedExistingGenerator = ActionGrid[pair.Item2, pair.Item1];
                    if (Utils.ShouldVerify())
                    {
                        Utils.DebugAssert(reversedExistingGenerator.Equals(existingGenerator.Reverse()));
                    }

                    replacedGenerator = reversedExistingGenerator.Mul(newGenerator);

                    if (Utils.ShouldVerify())
                    {
                        var replacedPair = GetActionPair(replacedGenerator);
                        if (replacedPair.Item1 >= 0)
                        {
                            // This ensures the recursive call will end
                            Utils.DebugAssert(replacedPair.Item1 > pair.Item1);
                        }
                    }
                }

                JumpCount++;
                return(FilterGeneratorIncrementally(replacedGenerator));
            }
コード例 #26
0
    public void AddActionToUndoList(CubeAction action)
    {
        actionList.Add(currentAction);

        processUndoRedoPossible(actionList.Count > 0);
    }
コード例 #27
0
                /// <summary>
                /// Stablizer chain algorithm templated from https://www.jaapsch.net/puzzles/schreier.htm.
                ///
                /// __Basic stablizer chain algorithm__
                ///
                /// Each GStep in the stablizer chain corresponds to gradually more blocks were rotated to
                /// the ideal cube position. Since the next GStep stablizes more blocks, it's the subgroup
                /// of the previous GStep.
                ///
                /// To obtain the next GStep, we obtain its generators. Subgroup generators can be obtained
                /// by Schreier subgroup lemma. It needs the set of cosets, i.e. coset representatives, and
                /// the parent group generators.
                ///
                /// Coset representatives can be obtained by repeating permutation of parent group generators.
                /// We know coset representatives are 1-on-1 mapping to block states we are trying to stablize.
                /// So we can find whether coset representatives are equal, or whether we walked all of them.
                ///
                /// So, giving parent group generators, we can obtain subgroup generators. Recursively, we
                /// walk along the stablizer chain of GSteps, until we solved all blocks.
                ///
                /// __Incremental stablizer chain algorithm__
                ///
                /// The problem is, the count of generators grow exponentially along the stablizer chain.
                /// We want to know whether a generator is not necessary, i.e. this generator and all descendants
                /// generators discovered by it, won't help us find any new cosets.
                ///
                /// The cosets at each GStep stablizer chain are the final results we want. Because given a cube
                /// state, we use 1-on-1 mapping to know its coset representative, We use the reverse of the coset
                /// representative to rotate the cube to ideal position. We do it along the stablizer chain, we
                /// then solve the cube.
                ///
                /// That's why, if a generator discovers no new coset, the generator is not necessary. We can then
                /// rewrite the algorithm in the new way, to incrementally add generators one by one. If a generator
                /// is found not necessary, we then discard it, so that it won't further exponentially increase our
                /// computation overhead.
                /// </summary>
                public int AddGeneratorIncrementally(CubeAction newGenerator, List <ProgressInfo> progressInfoList)
                {
                    if (null == Generators)
                    {
                        Generators = new HashSet <CubeAction>();
                    }

                    if (null == RejectedGenerators)
                    {
                        RejectedGenerators = new HashSet <CubeAction>();
                    }
                    if (RejectedGenerators.Contains(newGenerator))
                    {
                        return(0);
                    }

                    if (PrintProgress)
                    {
                        foreach (var p in progressInfoList)
                        {
                            Console.Write($"{p.StablizedCount}:{p.CompletedWork}/{p.TotalWork} ");
                        }
                        Console.WriteLine();

                        Console.WriteLine(
                            $"{new string(' ', Stablized.Indexes.Count)}" +
                            $"{Stablized.Indexes.Count} - G:{newGenerator.Count()} " +
                            $"FC:{GeneratorFilter.JumpCount} GC:{Generators.Count} " +
                            $"CC:{(OrbitToCoset != null ? OrbitToCoset.Count : 0)} RJ:{RejectedGenerators.Count}");
                    }

                    var filteredGenerator = GeneratorFilter.FilterGeneratorIncrementally(newGenerator);

                    if (filteredGenerator != null)
                    {
                        newGenerator = filteredGenerator;
                    }
                    else
                    {
                        RejectedGenerators.Add(newGenerator);
                        return(0);
                    }

                    if (Generators.Contains(newGenerator))
                    {
                        Utils.DebugAssert(false);
                        return(0);
                    }

                    ProgressInfo progressInfo    = null;
                    int          foundStateCount = 0;

                    {
                        var newStates = ExploreOrbitToCosetIncrementally(newGenerator);
                        foundStateCount += newStates.Count;

                        var newSubgroupGenerators = ObtainGeneratorsOfStablizerSubgroupIncrementally(
                            newGenerator, newStates);

                        if (Next != null)
                        {
                            progressInfo = new ProgressInfo(Stablized.Indexes.Count, newSubgroupGenerators.Count);
                            progressInfoList.Add(progressInfo);
                            foreach (var subgroupGenerator in newSubgroupGenerators)
                            {
                                foundStateCount += Next.AddGeneratorIncrementally(subgroupGenerator, progressInfoList);
                                progressInfo.CompletedWork++;
                            }
                        }
                    }

                    Utils.DebugAssert(GeneratorFilter.AcceptedGeneratorCount == Generators.Count);
                    Console.WriteLine(
                        $"Stablized[{Stablized.Indexes.Count}] " +
                        $"AddGeneratorIncrementally: Accepted new generator: " +
                        $"foundStateCount={foundStateCount} Generators={Generators.Count} " +
                        $"Cosets={OrbitToCoset.Count} FilterCount={GeneratorFilter.JumpCount} " +
                        $"newGenerator=[{newGenerator.Count()}]");

                    if (progressInfo != null)
                    {
                        progressInfoList.RemoveAt(progressInfoList.Count - 1);
                    }
                    return(foundStateCount);
                }
コード例 #28
0
    public void Update()
    {
        if (bProcessingRandomActions)
        {
            randomActionsTimePassed += Time.deltaTime;
            if (randomActionsTimePassed > randomActionTimer)
            {
                bProcessingRandomActions = false;
                return;
            }
            if (currentAction != null)
            {
                if (!currentAction.IsActionDone())
                {
                    currentAction.Update();
                }
                else
                {
                    currentAction = null;
                }
            }

            if (currentAction == null)
            {
                currentAction = generateRandomAction();
            }
            return;
        }

        if (currentAction != null)
        {
            if (!currentAction.IsActionDone())
            {
                currentAction.Update();
            }
            else
            {
                currentAction = null;

                //After a move is fully completed check whether the game is finished or not
                if (CheckIfGameIsFinished())
                {
                    FinishGame();
                }
            }
        }

        if (!bGameIsFinished)
        {
            timePassed += Time.deltaTime;
            if ((int)timePassed > seconds)
            {
                seconds = (int)timePassed;
                updateTime(seconds);
            }
        }
        bool bIsPinching = Input.touchCount >= 2;

        if (Input.GetMouseButtonDown(1) && !bIsPinching)
        {
            MainGameLogic.GetMainCamera().GetComponent <UIManager>().OpenGameMenu();
        }
    }