using System;
using System.Collections.Generic;
using System.Text;
namespace RobotSolver
{
class Program
{
static void Main(string[] args)
{
new Solver().Go();
}
}
///
/// Solves the light-bot game
///
class Solver
{
// The commands the robot can do
enum Cmd { Nothing, Call1, Call2, Jump, Left, Right, Light, Forwards };
// ****** Level 11 \/ \/ \/
string[] grid =
{
// 01234567 <- x
"33333333", // y=0
"22222222", // 1
"11111111", // 2
" ", // 3
"11111111", // 4
" ", // 5
"11111111", // 6
" " // 7
};
int[] lx = {1,2,3,4,5,6,7,
1,2,3,4,5,6,7,8,
1,2,3,4,5,6,7,8,
1,2,3,4,5,6,7,8,
1,2,3,4,5,6,7,8,
1,2,3,4,5,6,7,8,
}; // light x locations
int[] ly = {7,7,7,7,7,7,7,
6,6,6,6,6,6,6,6,
5,5,5,5,5,5,5,5,
4,4,4,4,4,4,4,4,
3,3,3,3,3,3,3,3,
2,2,2,2,2,2,2,2,
}; // light y locations
int startrx = 0, startry = 6, startra = 1; // facing E on the grid
// ****** Level 10 /\ /\ /\
bool[] l = new bool[47]; // light lit status
int rx, ry, ra; // current robot x,y,angle
Int64 tries = 0; // tries counter
int best = 0; // number of lights turned on by the best
// solution seen so far
int newBest = 0;
string Directions(Cmd[] list)
{
string s = "";
for (int i = 0; i < 28; i++)
s += list[i].ToString() + (i==11 || i==19 || i==27 ? "\n" : ",");
return s;
}
void Reset()
{
for (int i = 0; i < l.Length; i++) {
l[i] = false;
}
rx = startrx;
ry = startry;
ra = startra;
}
int Height()
{
if (' ' == grid[ry][rx]) return 0;
return grid[ry][rx] - '0';
}
void Clip()
{
if (rx < 0) rx = 0;
if (rx > 7) rx = 7;
if (ry < 0) ry = 0;
if (ry > 7) ry = 7;
}
void Move()
{
if (ra == 0) ry--; // N
if (ra == 1) rx++; // E
if (ra == 2) ry++; // S
if (ra == 3) rx--; // W
}
void Exec(Cmd c)
{
int oldx = rx;
int oldy = ry;
int oldht = Height();
if (c == Cmd.Forwards)
{
Move();
Clip();
// can't climb/fall
if (oldht != Height())
{
rx = oldx;
ry = oldy;
}
}
if (c == Cmd.Jump)
{
Move();
Clip();
// must climb one level or fall any levels
int newht = Height();
if (!(newht == oldht + 1 || newht < oldht))
{
rx = oldx;
ry = oldy;
}
}
if (c == Cmd.Left)
{
ra--;
if (ra < 0) ra = 3;
}
if (c == Cmd.Right)
{
ra++;
if (ra > 3) ra = 0;
}
if (c == Cmd.Light)
{
for (int i = 0; i < l.Length; i++) {
if (rx == lx[i] && ry == ly[i]) {
l[i] = !l[i];
}
}
}
}
void TryPath(Cmd[] f)
{
tries++;
Reset();
int index = 0;
List stacki = new List();
bool done = false;
do
{
Cmd c = f[index];
// call other functions
if (c == Cmd.Call1)
{
stacki.Add(index);
index = 12;
}
if (c == Cmd.Call2)
{
stacki.Add(index);
index = 20;
}
if (c != Cmd.Call1 && c != Cmd.Call2)
{
// run it
Exec(c);
// move next
index++;
while (index == 20 || index == 28) // finished f1 or f2
{
// pop
index = stacki[stacki.Count - 1] + 1;
stacki.RemoveAt(stacki.Count - 1);
}
if (index == 12) done = true; // did it just end?
}
} while (!done && stacki.Count < 10);
if (stacki.Count >= 10) Reset(); // if it looped then
}
public int CountTrue(bool[] l) {
int count = 0;
for (int i = 0; i < l.Length; i++) {
if (l[i]) {
count += 1;
}
}
return count;
}
public void Go()
{
Console.WriteLine("Begin: " + DateTime.Now.ToString());
Random r = new Random();
int update_counter = 0;
bool done = false;
int i, j, morphs, successrate, morphcount, freshrate, morphrate, spreadrate;
Cmd[] morphgood = new Cmd[28];
Cmd[][] f;
f = new Cmd[1000][]; // 1000 members of this generation
for (j = 0; j < 1000; j++) f[j] = new Cmd[28];
// Start with a random generation
for (j = 0; j < 1000; j++)
{
for (i = 0; i < 27; i++)
{
f[j][i] = (Cmd)r.Next(8);
}
}
bool[] goodones = new bool[1000]; // which ones in that generation were any good
do
{ // Loop through a single generation
best = newBest;
// Go through all members of this generation
successrate = 0;
for (j = 0; j < 1000; j++)
{
// try it
TryPath(f[j]);
int count = CountTrue(l);
//Console.WriteLine(count);
goodones[j] = (count > best); // is this one any good?
if (count > best && count > newBest) {
newBest = count;
}
if (goodones[j]) // It's a half winner
{
successrate++;
}
if (count == l.Length) // Found a winner!
{
done = true;
Console.WriteLine("\nWINNER:\n{0}", Directions(f[j]));
}
}
// Randomise the generation
morphcount = 0;
freshrate = 0;
morphrate = 0;
spreadrate = 0;
for (j = 0; j < 1000; j++)
{
if (goodones[j])
{ // If it's half good, then morph it
// before i morph it, copy it for later morphing
Array.Copy(f[j], morphgood, 28);
morphs = r.Next(4); // how many fields to morph
for (i = 0; i < morphs; i++) // morph X entries
{
f[j][r.Next(28)] = (Cmd)r.Next(8);
}
morphrate++;
morphcount = 10; // morph this one over the next 10 crap ones
}
else // If its crap, then overwrite it
{
// Shall i spread and morph a previous half-good one into this slot?
if (morphcount > 0)
{
Array.Copy(morphgood, f[j], 28); // copy it into this slot
morphs = r.Next(4); // how many fields to morph
for (i = 0; i < morphs; i++) // morph X entries
{
f[j][r.Next(28)] = (Cmd)r.Next(8);
}
morphcount--;
spreadrate++;
}
else
{ // just totally regenerate it
for (i = 0; i < 27; i++)
{
f[j][i] = (Cmd)r.Next(8);
}
freshrate++;
}
}
}
// Update the user
update_counter++;
if (update_counter >= 100)
{
update_counter = 0;
Console.Write("\rTries: {0:#,0} Halfway: {1} Fresh: {2} Morphed: {3} Spread: {4} Best: {5}", tries, successrate, freshrate, morphrate, spreadrate, best);
}
} while (!done);
Console.WriteLine("End: " + DateTime.Now.ToString());
}
}
}