Beispiel #1
0
    /// <summary>
    /// 再帰してミノの配置を全列挙
    /// 負荷削減のために、一度右移動した方向のみにしか移動は不可、回転はあらかじめやっておく
    /// </summary>
    /// <param name="mino">現在のテトリミノ</param>
    /// <param name="field">現在の盤面</param>
    /// <param name="move">今までの移動履歴を収納(ホールドやネクストを含む)</param>
    /// <param name="hashset">重複検知用のDictionary、hashsetではない</param>
    /// <param name="movecount">今までの移動カウント、回転も含む、ホールドも含むはず【要】</param>
    /// <param name="beforeHorizontal">前の移動と反対側に移動できないようにするための前の横移動履歴収納</param>
    /// <param name="beforeEval">前のミノ設置の評価、一部継続させないと一番最後のスコアだけが反映されてしまう</param>
    static private void SearchPattern(
        TetrisEnvironment.Mino mino,
        int[,] field,
        string move,
        Dictionary <string, TetrisEnvironment.Way> hashset,
        int movecount,
        TetrisEnvironment.Move beforeHorizontal,
        float beforeEval
        )
    {
        TetrisEnvironment.Mino mino_clone;
        //ハードドロップ
        {
            mino_clone = TetrisEnvironment.Mino.Clone(mino);

            int count = 0;
            while (true)
            {
                if (TetrisEnvironment.CheckValidPosition(field, mino_clone.positions, new TetrisEnvironment.Vector2(0, count)))
                {
                    count--;
                }
                else
                {
                    count++; break;
                }
            }

            mino_clone.positions[0] += new TetrisEnvironment.Vector2(0, count);
            mino_clone.positions[1] += new TetrisEnvironment.Vector2(0, count);
            mino_clone.positions[2] += new TetrisEnvironment.Vector2(0, count);
            mino_clone.positions[3] += new TetrisEnvironment.Vector2(0, count);

            //ハッシュのため順番を整列
            for (int i = 1; i < 4; i++)
            {
                if (mino_clone.positions[i].x < mino_clone.positions[i - 1].x)
                {
                    TetrisEnvironment.Vector2 temp = mino_clone.positions[i - 1];
                    mino_clone.positions[i - 1] = mino_clone.positions[i];
                    mino_clone.positions[i]     = temp;
                }
            }

            for (int j = 1; j < 4; j++)
            {
                int num = 0;
                if (mino_clone.positions[j].x == mino_clone.positions[j - 1].x)
                {
                    while (j - 1 - num >= 0 && mino_clone.positions[j - num].y < mino_clone.positions[j - 1 - num].y)
                    {
                        TetrisEnvironment.Vector2 temp = mino_clone.positions[j - 1 - num];
                        mino_clone.positions[j - 1 - num] = mino_clone.positions[j - num];
                        mino_clone.positions[j - num]     = temp;
                        num++;
                    }
                }
            }

            string hash = mino_clone.positions[0].x.ToString();
            hash += mino_clone.positions[0].y.ToString();
            hash += mino_clone.positions[1].x.ToString();
            hash += mino_clone.positions[1].y.ToString();
            hash += mino_clone.positions[2].x.ToString();
            hash += mino_clone.positions[2].y.ToString();
            hash += mino_clone.positions[3].x.ToString();
            hash += mino_clone.positions[3].y.ToString();

            TetrisEnvironment.Way output;


            if (hashset.TryGetValue(hash, out output))
            {
                if (output.moveCount > movecount)
                {
                    hashset.Remove(hash);
                    hashset.Add(hash, new TetrisEnvironment.Way(move + (int)TetrisEnvironment.Move.HardDrop, NewEvaluation.Evaluate(field, mino_clone.positions, beforeEval, false), mino_clone.positions, movecount + 1, hash));
                }
            }
            else
            {
                hashset.Add(hash, new TetrisEnvironment.Way(move + (int)TetrisEnvironment.Move.HardDrop, NewEvaluation.Evaluate(field, mino_clone.positions, beforeEval, false), mino_clone.positions, movecount + 1, hash));
            }
        }

        //右移動
        if (beforeHorizontal != TetrisEnvironment.Move.Left && TetrisEnvironment.CheckValidPosition(field, mino.positions, new TetrisEnvironment.Vector2(1, 0)))
        {
            mino_clone = TetrisEnvironment.Mino.Clone(mino);

            mino_clone.positions[0] += TetrisEnvironment.Vector2.X1;
            mino_clone.positions[1] += TetrisEnvironment.Vector2.X1;
            mino_clone.positions[2] += TetrisEnvironment.Vector2.X1;
            mino_clone.positions[3] += TetrisEnvironment.Vector2.X1;

            SearchPattern(mino_clone, field, move + (int)TetrisEnvironment.Move.Right, hashset, movecount + 1, TetrisEnvironment.Move.Right, beforeEval);
        }

        //左移動
        if (beforeHorizontal != TetrisEnvironment.Move.Right && TetrisEnvironment.CheckValidPosition(field, mino.positions, new TetrisEnvironment.Vector2(-1, 0)))
        {
            mino_clone = TetrisEnvironment.Mino.Clone(mino);

            mino_clone.positions[0] += TetrisEnvironment.Vector2.MinusX1;
            mino_clone.positions[1] += TetrisEnvironment.Vector2.MinusX1;
            mino_clone.positions[2] += TetrisEnvironment.Vector2.MinusX1;
            mino_clone.positions[3] += TetrisEnvironment.Vector2.MinusX1;

            SearchPattern(mino_clone, field, move + (int)TetrisEnvironment.Move.Left, hashset, movecount + 1, TetrisEnvironment.Move.Left, beforeEval);
        }
    }
Beispiel #2
0
    static public void Learn()
    {
        int threadCount;
        int threadCount2;

        ThreadPool.GetMaxThreads(out threadCount, out threadCount2);
        Console.WriteLine("スレッド数は" + threadCount + "です。");

        Console.WriteLine("世代数を入力してください。");
        int generationDestination = int.Parse(Console.ReadLine());

        Console.WriteLine("学習を開始します。");


        int nowGenerationIndex = 0;
        int index = 0;

        TetrisEnvironment.MinoKind[]      nexts        = new TetrisEnvironment.MinoKind[5];
        List <TetrisEnvironment.MinoKind> _leftMinoBag = new List <TetrisEnvironment.MinoKind>();

        Chromosome[] nowChromosome = new Chromosome[generationDestination];
        const int    FrameMax      = 10800;

        int[,] field = new int[10, 25];

        Random random = new Random();

        while (true)
        {
            for (int i = 0; i < generationDestination; i++)
            {
                float[] values = new float[11];
                values[0]  = random.Next(-100, 155);
                values[1]  = random.Next(-100, 155);
                values[2]  = random.Next(-100, 155);
                values[3]  = random.Next(-100, 155);
                values[4]  = random.Next(-100, 155);
                values[5]  = random.Next(-100, 155);
                values[6]  = random.Next(-100, 155);
                values[7]  = random.Next(-100, 155);
                values[8]  = random.Next(-100, 155);
                values[9]  = random.Next(-100, 155);
                values[10] = random.Next(-100, 155);

                nowChromosome[i].chromosome = CreateChromosome(values);
            }


Label:
            var values2 = DecodeChromosome(nowChromosome[index].chromosome);

            NewEvaluation.h_sumofheight = values2[0];
            NewEvaluation.h_dekoboko    = values2[1];
            NewEvaluation.h_holeCount   = values2[2];
            NewEvaluation.h_holeup1     = values2[3];
            NewEvaluation.h_holeup2     = values2[4];
            NewEvaluation.h_holeup3     = values2[5];
            NewEvaluation.h_holeup4     = values2[6];
            NewEvaluation.h_line1       = values2[7];
            NewEvaluation.h_line2       = values2[8];
            NewEvaluation.h_line3       = values2[9];
            NewEvaluation.h_line4       = values2[10];

            for (int x = 0; x < 10; x++)
            {
                for (int y = 0; y < 25; y++)
                {
                    field[x, y] = 0;
                }
            }
            Console.Clear();
            Console.WriteLine($"{nowGenerationIndex}世代 {index}/{generationDestination}\r\n\r\n");

            Console.WriteLine($"現在の評価\r\n" +
                              $"高さ合計:{ NewEvaluation.h_sumofheight}\r\n" +
                              $"1ライン消し:{ NewEvaluation.h_line1}\r\n" +
                              $"2ライン消し:{ NewEvaluation.h_line2}\r\n" +
                              $"3ライン消し:{ NewEvaluation.h_line3}\r\n" +
                              $"4ライン消し:{ NewEvaluation.h_line4}\r\n" +
                              $"でこぼこ:{ NewEvaluation.h_dekoboko}\r\n" +
                              $"穴:{ NewEvaluation.h_holeCount}\r\n" +
                              $"穴の上ミノ1:{ NewEvaluation.h_holeup1}\r\n" +
                              $"穴の上ミノ2:{ NewEvaluation.h_holeup2}\r\n" +
                              $"穴の上ミノ3:{ NewEvaluation.h_holeup3}\r\n" +
                              $"穴の上ミノ4:{ NewEvaluation.h_holeup4}\r\n");

            TetrisEnvironment.UpdateNexts(nexts, _leftMinoBag);
            TetrisEnvironment.UpdateNexts(nexts, _leftMinoBag);
            TetrisEnvironment.UpdateNexts(nexts, _leftMinoBag);
            TetrisEnvironment.UpdateNexts(nexts, _leftMinoBag);
            TetrisEnvironment.UpdateNexts(nexts, _leftMinoBag);
            var minotemp = TetrisEnvironment.UpdateNexts(nexts, _leftMinoBag);
            TetrisEnvironment.Mino nowMino = TetrisEnvironment.CreateMino(minotemp);
            bool canhold = true;
            TetrisEnvironment.MinoKind?hold = new TetrisEnvironment.MinoKind?();
            int  frameCount = 0;
            int  score      = 0;
            int  ren        = 0;
            bool backtoback = false;

            while (true)
            {
                var way = NewTetrisAI.Find(field, (int)nowMino.kind, Utility.Enum2IntArray(new TetrisEnvironment.MinoKind[1] {
                    nexts[0]
                }), 0, (int?)hold, canhold);

                way.way = way.way.Substring(0, way.way.IndexOf('5') + 1);
                foreach (char action in way.way)
                {
                    switch (int.Parse(action.ToString()))
                    {
                    case (int)TetrisEnvironment.Move.SoftDrop:
                        if (TetrisEnvironment.CheckValidPosition(field, nowMino.positions, new TetrisEnvironment.Vector2(0, -1)))
                        {
                            nowMino.positions[0] += new TetrisEnvironment.Vector2(0, -1);
                            nowMino.positions[1] += new TetrisEnvironment.Vector2(0, -1);
                            nowMino.positions[2] += new TetrisEnvironment.Vector2(0, -1);
                            nowMino.positions[3] += new TetrisEnvironment.Vector2(0, -1);

                            frameCount += MoveFrame;
                        }
                        break;

                    case (int)TetrisEnvironment.Move.HardDrop:
                        frameCount += MinoSet;
                        canhold     = true;
                        int count = 0;
                        while (true)
                        {
                            if (TetrisEnvironment.CheckValidPosition(field, nowMino.positions, new TetrisEnvironment.Vector2(0, count)))
                            {
                                count--;
                            }
                            else
                            {
                                count++; break;
                            }
                        }

                        nowMino.positions[0] += new TetrisEnvironment.Vector2(0, count);
                        nowMino.positions[1] += new TetrisEnvironment.Vector2(0, count);
                        nowMino.positions[2] += new TetrisEnvironment.Vector2(0, count);
                        nowMino.positions[3] += new TetrisEnvironment.Vector2(0, count);

                        foreach (var position in nowMino.positions)
                        {
                            field[position.x, position.y] = 1;
                        }

                        //ミノ消去ANDスコア加算
                        int clearedCount = TetrisEnvironment.CheckLine(field);

                        if (clearedCount == 4)
                        {
                            backtoback = true;
                        }
                        else
                        {
                            backtoback = false;
                        }

                        if (clearedCount == 0)
                        {
                            ren = 0;
                        }
                        else
                        {
                            ren++;
                        }
                        TetrisEnvironment.UpdateScore(clearedCount, ren, ref score, backtoback);

                        var temp2 = TetrisEnvironment.UpdateNexts(nexts, _leftMinoBag);
                        nowMino = TetrisEnvironment.CreateMino(temp2);

                        if (!TetrisEnvironment.CheckValidPosition(field, nowMino.positions, TetrisEnvironment.Vector2.Zero) || frameCount >= FrameMax)
                        {
                            //死亡


                            if (index == generationDestination - 1)
                            {    //次の世代に移行
                                List <Chromosome> newChromosomes = new List <Chromosome>();
                                List <Chromosome> tempList       = new List <Chromosome>();

                                nowChromosome[index].eval = score;


                                tempList.AddRange(nowChromosome);

                                tempList.Sort((a, b) => b.eval.CompareTo(a.eval));
                                score = 0;

                                //エリート方式で追加
                                for (int i = 0; i < generationDestination - 3; i++)
                                {
                                    newChromosomes.Add(new Chromosome(0, tempList[i].chromosome));
                                }

                                newChromosomes.Add(new Chromosome(0, GeneticAlgorithm.TwoPointCrossOver(tempList[0].chromosome, tempList[1].chromosome)));
                                newChromosomes.Add(new Chromosome(0, GeneticAlgorithm.TwoPointCrossOver(tempList[0].chromosome, tempList[2].chromosome)));
                                if (Probability.Percent(3))
                                {
                                    newChromosomes.Add(new Chromosome(0, GeneticAlgorithm.Mutation(tempList[0].chromosome)));
                                }
                                else
                                {
                                    newChromosomes.Add(new Chromosome(0, tempList[0].chromosome));
                                }


                                nowChromosome = newChromosomes.ToArray();
                                nowGenerationIndex++;
                                index = 0;
                            }
                            else
                            {
                                nowChromosome[index].eval = score;
                            }


                            index++;
                            goto Label;
                        }
                        break;

                    case (int)TetrisEnvironment.Move.Hold:
                        if (canhold)
                        {
                            canhold = false;
                            if (hold == null)
                            {
                                hold = nowMino.kind;

                                var temp = TetrisEnvironment.UpdateNexts(nexts, _leftMinoBag);
                                nowMino = TetrisEnvironment.CreateMino(temp);
                            }
                            else
                            {
                                var temp = nowMino.kind;
                                nowMino = TetrisEnvironment.CreateMino((TetrisEnvironment.MinoKind)hold);
                                hold    = temp;
                            }
                        }
                        break;

                    case (int)TetrisEnvironment.Move.Left:
                        if (TetrisEnvironment.CheckValidPosition(field, nowMino.positions, TetrisEnvironment.Vector2.MinusX1))
                        {
                            nowMino.positions[0] += TetrisEnvironment.Vector2.MinusX1;
                            nowMino.positions[1] += TetrisEnvironment.Vector2.MinusX1;
                            nowMino.positions[2] += TetrisEnvironment.Vector2.MinusX1;
                            nowMino.positions[3] += TetrisEnvironment.Vector2.MinusX1;

                            frameCount += MoveFrame;
                        }
                        break;

                    case (int)TetrisEnvironment.Move.LeftRotate:
                        if (TetrisEnvironment.RotateMino(TetrisEnvironment.Move.LeftRotate, ref nowMino, field))
                        {
                            frameCount += MoveFrame;
                        }
                        break;

                    case (int)TetrisEnvironment.Move.Right:
                        if (TetrisEnvironment.CheckValidPosition(field, nowMino.positions, TetrisEnvironment.Vector2.X1))
                        {
                            nowMino.positions[0] += TetrisEnvironment.Vector2.X1;
                            nowMino.positions[1] += TetrisEnvironment.Vector2.X1;
                            nowMino.positions[2] += TetrisEnvironment.Vector2.X1;
                            nowMino.positions[3] += TetrisEnvironment.Vector2.X1;

                            frameCount += MoveFrame;
                        }
                        break;

                    case (int)TetrisEnvironment.Move.RightRotate:
                        if (TetrisEnvironment.RotateMino(TetrisEnvironment.Move.RightRotate, ref nowMino, field))
                        {
                            frameCount += MoveFrame;
                        }

                        break;
                    }

                    //TetrisEnvironment.Print(field, nowMino.positions, false);
                    //Console.WriteLine("現在のミノ");
                    //Console.Write(nowMino.kind + "\r\n");
                    //Console.WriteLine("ネクスト");
                    //Console.Write(nexts[0]);
                    //Console.Write(nexts[1]);
                    //Console.Write(nexts[2]);
                    //Console.Write(nexts[3]);
                    //Console.Write(nexts[4] + "\r\n");
                    //Console.WriteLine("ホールド");
                    //Console.WriteLine(hold + "\r\n");
                    //Thread.Sleep(10);
                    ////Console.ReadKey();
                }
            }
        }
    }