public void advance(char dir, apple apl, snake[] snakes, bool printapl) { if (l > 2) { if (Save == 'w' && dir == 's') { dir = Save; } if (Save == 's' && dir == 'w') { dir = Save; } if (Save == 'a' && dir == 'd') { dir = Save; } if (Save == 'd' && dir == 'a') { dir = Save; } } ttl--; num++; if (!alive) { if (l > 0) { l--; } else { delete(); Xsnake[0] = -1; Ysnake[0] = -1; delete(); } } else { runTime++; for (int i = l; i > 0; i--) { Xsnake[i] = Xsnake[i - 1]; Ysnake[i] = Ysnake[i - 1]; } if (dir == 's') { Ysnake[0]++; } if (dir == 'w') { Ysnake[0]--; } if (dir == 'd') { Xsnake[0]++; } if (dir == 'a') { Xsnake[0]--; } if ((apl.appleX() == Xsnake[0]) && (apl.appleY() == Ysnake[0])) { l++; num = 0; apl.newCord(snakes, s); if (printapl) { apl.print(); } //ttl = ((ttl + ttlConst) * 6) / 10; ttl = ttl + ttlConst; } } Save = dir; }
// the evolution function for the machine learning. // gets the number of snakes that plays simultaneously (Competing with each other). static snake Evolution(int snknum) { snake[] snakes = new snake[snknum]; for (int i = 0; i < snakes.Length; i++) { snakes[i] = new snake(i, s); } for (int i = 0; i < snakes.Length; i++) { snakes[i].newCord(snakes, s); } bool erase = false; char dir = ' '; //snake diraction by the neural network results. bool life = true; bool othersLife = true; snakes1 = new snake[60]; // the number of snakes in every generation int numOfGeneration = 100000000; int evr = 1; // the num of iterations each snake do in one generation int a = 40; // snakes1.length - a = the num of new random snakes. int b = 5; // the num of parents snakes int c = 10; // the num of snakes that survives to the next generation (includes b) // a - (b + c) = the number of childrens. char pressedKey = ' '; // changes to the key pressed by the user for (int i = 0; i < snakes1.Length; i++) { snakes1[i] = new snake(0, s); snakes1[i].AIPrep(snakes); } Console.WriteLine("if you already have a saved version and want to keep training it, please write the version num. Otherwise write anything else."); int ErlySnk = int.Parse(Console.ReadLine()); Console.Beep(261, 50); Console.Clear(); PrintBoard(); //loading the save version to all the snakes. Also adding mutations. snakes1[0].Load(ErlySnk); snakes1[0].snksScore = 10000; for (int i = 1; i < snakes1.Length; i++) { snakes1[i].Load(ErlySnk); snakes1[i].Change(10); } for (int t = 0; t < numOfGeneration; t++) { Console.SetCursorPosition(0, s); Console.WriteLine("Press '*' to stop the learning and save the neural network to file."); Console.WriteLine("Press 'w' to watch the current snake."); Console.WriteLine((t / (numOfGeneration + 0.0)) * 100 + "% (epoch " + t + " ) "); for (int x = 0; x < snakes1.Length; x++) { if ((x / (snakes1.Length + 0.0)) * 100 % 10 == 0) { Console.SetCursorPosition(0, s + 3); Console.WriteLine((x / (snakes1.Length + 0.0)) * 100 + "% "); } //initialization of variables before the game begins for (int i = 0; i < snakes.Length; i++) { snakes[i] = new snake(i, s); snakes[i].newCord(snakes, s); snakes[i].l = 1; } life = true; apple apl = new apple(snakes, s); snakes[0] = snakes1[x]; snakes[0].newCord(snakes, s); double score = 0; for (int m = 0; m < evr; m++) { apl.newCord(snakes, s); // print the current game state to the screan if ((Console.KeyAvailable || pressedKey == 'w') && x > snakes1.Length - a) { if (Console.KeyAvailable) { pressedKey = Console.ReadKey().KeyChar; } Console.Clear(); PrintBoard(); Console.Write(x + " / " + snakes1.Length); apl.print(); } while (Console.KeyAvailable) { pressedKey = Console.ReadKey().KeyChar; } snakes[0].l = 1; //initial snake length //one game while (life) { if (erase && (pressedKey != 'w')) { Console.Clear(); PrintBoard(); erase = false; } for (int i = 0; i < snakes.Length; i++) { if (i == 0) { // one move of the tested snake, according to the neural network. dir = snakes[0].AIsnkalg(snakes, apl); snakes[i].advance(dir, apl, snakes, (Console.KeyAvailable || pressedKey == 'w') && x > snakes1.Length - a); life = snakes[0].isAlive(snakes); snakes[0].Save = dir; } else { //one move of snakes[i], according to the fixed algorithm dir = snakes[i].snkalg(snakes, apl); snakes[i].Save = dir; snakes[i].advance(dir, apl, snakes, (Console.KeyAvailable || pressedKey == 'w') && x > snakes1.Length - a); othersLife = snakes[i].isAlive(snakes); if (!othersLife) { snakes[i] = new snake(i, s); snakes[i].newCord(snakes, s); } } // print the current game state to the screan if ((Console.KeyAvailable || pressedKey == 'w') && x > snakes1.Length - a) { erase = true; if (Console.KeyAvailable) { pressedKey = Console.ReadKey().KeyChar; } snakes[i].delete(); Console.SetCursorPosition(0, 0); snakes[i].write(arrows); Console.SetCursorPosition(2 * s + 1, 0); Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("score: " + snakes1[x].score()); if (i == 0) { Thread.Sleep(50); } apl.print(); } } } snakes[0].ttl = snakes[0].ttlConst; life = true; snakes[0].alive = true; snakes[0].runTime = 0; snakes[0].l = 1; snakes[0].bonus = 0; snakes[0].newCord(snakes, s); score += snakes[0].snksScore; snakes[0].snksScore = 0; } score = score / (evr * 1.0); double temp = -0.5; if (snakes1[x].Right) { temp += 0.5; } if (snakes1[x].Left) { temp += 0.5; } if (snakes1[x].Straight) { temp += 0.5; } score *= temp; snakes1[x].Right = false; snakes1[x].Left = false; snakes1[x].Straight = false; snakes1[x] = snakes[0]; snakes1[x].snksScore = score; } Console.WriteLine("last epoch's first place score in this epoch: " + snakes1[snakes1.Length - 1].snksScore + " "); Sort(0, snakes1.Length - 1); // sort snakes1 by score if (pressedKey == '*') { return(snakes1[snakes1.Length - 1]); // returning the snake with the best score } Console.SetCursorPosition(0, s + 5); Console.ForegroundColor = ConsoleColor.White; for (int i = 0; i < 10; i++) { Console.WriteLine((i + 1) + ": " + snakes1[snakes1.Length - i - 1].snksScore + " "); } Console.SetCursorPosition(0, s + 3); for (int x = 0; x < snakes1.Length; x++) { if (x < snakes1.Length - a)// create new random snakes { snakes1[x] = new snake(0, s); snakes1[x].AIPrep(snakes); } else if (x < (snakes1.Length) - c) // create snakes childs { snakes1[x] = new snake(0, s); snakes1[x].AIPrep(snakes); snakes1[x].Load(snakes1[snakes1.Length - x % b - 1].nn); // duplicating a snake into this snake snakes1[x].Change(rnd.NextDouble() * 8 + 4); // add mutations } snakes1[x].l = 1; snakes1[x].alive = true; snakes1[x].runTime = 0; snakes1[0].newCord(snakes, s); snakes1[x].snksScore = 0; } } return(snakes1[snakes1.Length - 1]); // returning the snake with the best score }