using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Remoting.Messaging; using System.Text; namespace HeuristicLab.Problems.GrammaticalOptimization { public class SantaFeAntProblem : IProblem { private const string grammarString = @" G(A): A -> l | r | m | ?(A)(A) | lA | rA | mA "; // original koza grammar // Ant -> left | right | move | if-food-ahead Ant Ant | Ant Ant | Ant Ant Ant // // here we use a modified grammar which has only one syntax tree for each sentence private readonly IGrammar grammar; public SantaFeAntProblem() { this.grammar = new Grammar(grammarString); } public double GetBestKnownQuality(int maxLen) { // for now only an upper bound is returned, ideally all food pellets are discovered return 89; } public IGrammar Grammar { get { return grammar; } } public double Evaluate(string sentence) { var ant = new Ant(); int p = 0; Run(ant, sentence, ref p); return ant.FoodEaten; } private void Run(Ant ant, string sentence, ref int p) { while (!ant.Done()) { if (p >= sentence.Length) p = 0; // restart switch (sentence[p]) { case 'r': { ant.TurnRight(); p++; break; } case 'l': { ant.TurnLeft(); p++; break; } case 'm': { ant.Move(); p++; break; } case '?': { p++; // skip p if (ant.IsFoodAhead()) { if (sentence[p] != '(') throw new ArgumentException(); p++; Run(ant, sentence, ref p); // it cannot happen that we run over the the end of the sentence here if (ant.Done()) return; if (sentence[p] != '(') throw new ArgumentException(); p++; Skip(sentence, ref p); } else { if (sentence[p] != '(') throw new ArgumentException(); p++; Skip(sentence, ref p); if (sentence[p] != '(') throw new ArgumentException(); p++; Run(ant, sentence, ref p); // it cannot happen that we run over the the end of the sentence here } break; } case ')': { p++; // skip return; // caller must continue processing } default: { throw new ArgumentException(); } } } } private void Skip(string sentence, ref int p) { int openCount = 1; while (openCount > 0) { if (sentence[p] == '(') openCount++; else if (sentence[p] == ')') openCount--; p++; } } public string Hash(string terminalPhrase) { return terminalPhrase.Replace("rl", "").Replace("lr", ""); } } public class Ant { private const int maxSteps = 600; public enum HeadingEnum { North, East, South, West }; public int FoodEaten { get; private set; } private readonly char[][] world = new char[32][]; private int posX; private int posY; private int steps; private HeadingEnum heading; public Ant() { world[00] = " ### ".ToCharArray(); world[01] = " # ".ToCharArray(); world[02] = " # .###.. ".ToCharArray(); world[03] = " # # # ".ToCharArray(); world[04] = " # # # ".ToCharArray(); world[05] = " ####.##### .##.. . ".ToCharArray(); world[06] = " # . # ".ToCharArray(); world[07] = " # # . ".ToCharArray(); world[08] = " # # . ".ToCharArray(); world[09] = " # # # ".ToCharArray(); world[10] = " . # . ".ToCharArray(); world[11] = " # . . ".ToCharArray(); world[12] = " # . # ".ToCharArray(); world[13] = " # # . ".ToCharArray(); world[14] = " # # ...###. ".ToCharArray(); world[15] = " . .#... # ".ToCharArray(); world[16] = " . . . ".ToCharArray(); world[17] = " # . . ".ToCharArray(); world[18] = " # # .#... ".ToCharArray(); world[19] = " # # # ".ToCharArray(); world[20] = " # # . ".ToCharArray(); world[21] = " # # . ".ToCharArray(); world[22] = " # . ...#. ".ToCharArray(); world[23] = " # . # ".ToCharArray(); world[24] = " ..##..#####. # ".ToCharArray(); world[25] = " # # ".ToCharArray(); world[26] = " # # ".ToCharArray(); world[27] = " # .#######.. ".ToCharArray(); world[28] = " # # ".ToCharArray(); world[29] = " . # ".ToCharArray(); world[30] = " .####.. ".ToCharArray(); world[31] = " ".ToCharArray(); posX = 0; posY = 0; heading = HeadingEnum.East; FoodEaten = 0; steps = 0; } public bool Done() { return steps > maxSteps; } public void TurnRight() { if (steps <= maxSteps) { steps++; if (heading == HeadingEnum.West) heading = HeadingEnum.North; else heading++; } } public void TurnLeft() { if (steps <= maxSteps) { steps++; if (heading == HeadingEnum.North) heading = HeadingEnum.West; else heading--; } } public void Move() { if (steps <= maxSteps) { steps++; MoveInternal(ref posX, ref posY); if (world[posY][posX] == '#') { FoodEaten++; world[posY][posX] = '.'; } } } private void MoveInternal(ref int posX, ref int posY) { switch (heading) { case HeadingEnum.North: posY = (posY + 31) % 32; break; case HeadingEnum.East: posX = (posX + 1) % 32; break; case HeadingEnum.South: posY = (posY + 1) % 32; break; case HeadingEnum.West: posX = (posX + 31) % 32; break; } } public bool IsFoodAhead() { int nextPosX = posX; int nextPosY = posY; MoveInternal(ref nextPosX, ref nextPosY); return world[nextPosY][nextPosX] == '#'; } } }