static private void Search(int[,] field, int nowmino, int[] nexts, int ojama, float beforeEval, string moveajust = "") { TetrisEnvironment.Mino mino = TetrisEnvironment.CreateMino((TetrisEnvironment.MinoKind)nowmino); Dictionary <string, TetrisEnvironment.Way> ways = new Dictionary <string, TetrisEnvironment.Way>(); SearchPattern(mino, field, moveajust, ways, 0, TetrisEnvironment.Move.Null, beforeEval); var minoclone = TetrisEnvironment.Mino.Clone(mino); //右回転 if (TetrisEnvironment.RotateMino(TetrisEnvironment.Move.RightRotate, ref mino, field)) { SearchPattern(mino, field, moveajust + "3", ways, 1, TetrisEnvironment.Move.Null, beforeEval); //180回転 if (TetrisEnvironment.RotateMino(TetrisEnvironment.Move.RightRotate, ref mino, field)) { SearchPattern(mino, field, moveajust + "33", ways, 2, TetrisEnvironment.Move.Null, beforeEval); } } //左回転 if (TetrisEnvironment.RotateMino(TetrisEnvironment.Move.LeftRotate, ref minoclone, field)) { SearchPattern(minoclone, field, moveajust + "4", ways, 1, TetrisEnvironment.Move.Null, beforeEval); } //ネクストが残っていたら if (!CheckNextIsEmpty(nexts)) { var nexts_clone = (int[])nexts.Clone(); int newmino = nexts_clone[0]; for (int i = 0; i < nexts_clone.Length - 1; i++) { nexts_clone[i] = nexts_clone[i + 1]; } nexts_clone[nexts.Length - 1] = (int)TetrisEnvironment.MinoKind.Empty; foreach (var value in ways.Values) { var field_clone = (int[, ])field.Clone(); float eval = NewEvaluation.Evaluate(field_clone, value.mino_positions, beforeEval, true); Search(field_clone, newmino, nexts_clone, ojama, eval, value.way); } } //ネクストなし else { TetrisEnvironment.Way bestkouho = new TetrisEnvironment.Way(); bool first = true; foreach (var value in ways.Values) { //TetrisEnvironment.Print(field, value.mino_positions, true); if (first) { bestkouho = value; first = false; } if (bestkouho.eval < value.eval) { bestkouho = value; } } if (_finalWays == null) { _finalWays = bestkouho; } else { if (_finalWays.Value.eval < bestkouho.eval) { _finalWays = bestkouho; } } } }
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(); } } } }