source: branches/HeuristicLab.Problems.GrammaticalOptimization/HeuristicLab.Problems.GrammaticalOptimization/SantaFeAntProblem.cs @ 11732

Last change on this file since 11732 was 11732, checked in by gkronber, 5 years ago

#2283: refactoring and bug fixes

File size: 7.0 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Runtime.Remoting.Messaging;
5using System.Text;
6
7namespace HeuristicLab.Problems.GrammaticalOptimization {
8  public class SantaFeAntProblem : IProblem {
9    private const string grammarString = @"
10G(A):
11A -> l | r | m | ?(A)(A) | lA | rA | mA
12";
13    // original koza grammar
14    // Ant -> left | right | move | if-food-ahead Ant Ant | Ant Ant | Ant Ant Ant
15    //
16    // here we use a modified grammar which has only one syntax tree for each sentence
17
18
19    private readonly IGrammar grammar;
20
21    public SantaFeAntProblem() {
22      this.grammar = new Grammar(grammarString);
23    }
24
25    public double BestKnownQuality(int maxLen) {
26      // for now only an upper bound is returned, ideally all food pellets are discovered
27      return 89;
28    }
29
30    public IGrammar Grammar {
31      get { return grammar; }
32    }
33
34    public double Evaluate(string sentence) {
35      var ant = new Ant();
36      int p = 0;
37      Run(ant, sentence, ref p);
38      return ant.FoodEaten;
39    }
40
41    private void Run(Ant ant, string sentence, ref int p) {
42      while (!ant.Done()) {
43        if (p >= sentence.Length) p = 0; // restart
44        switch (sentence[p]) {
45          case 'r': {
46              ant.TurnRight();
47              p++;
48              break;
49            }
50          case 'l': {
51              ant.TurnLeft();
52              p++;
53              break;
54            }
55          case 'm': {
56              ant.Move();
57              p++;
58              break;
59            }
60          case '?': {
61              p++; // skip p
62              if (ant.IsFoodAhead()) {
63                if (sentence[p] != '(') throw new ArgumentException();
64                p++;
65                Run(ant, sentence, ref p);      // it cannot happen that we run over the the end of the sentence here
66                if (ant.Done()) return;
67                if (sentence[p] != '(') throw new ArgumentException();
68                p++;
69                Skip(sentence, ref p);
70              } else {
71                if (sentence[p] != '(') throw new ArgumentException();
72                p++;
73                Skip(sentence, ref p);
74                if (sentence[p] != '(') throw new ArgumentException();
75                p++;
76                Run(ant, sentence, ref p);    // it cannot happen that we run over the the end of the sentence here
77              }
78              break;
79            }
80          case ')': {
81              p++; // skip
82              return;     // caller must continue processing
83            }
84          default: {
85              throw new ArgumentException();
86            }
87        }
88      }
89    }
90
91    private void Skip(string sentence, ref int p) {
92      int openCount = 1;
93      while (openCount > 0) {
94        if (sentence[p] == '(') openCount++;
95        else if (sentence[p] == ')') openCount--;
96        p++;
97      }
98    }
99
100    public string Hash(string terminalPhrase) {
101      return terminalPhrase.Replace("rl", "").Replace("lr", "");
102    }
103  }
104
105  public class Ant {
106    private const int maxSteps = 600;
107    public enum HeadingEnum { North, East, South, West };
108    public int FoodEaten { get; private set; }
109    private readonly char[][] world = new char[32][];
110    private int posX;
111    private int posY;
112    private int steps;
113    private HeadingEnum heading;
114
115
116
117    public Ant() {
118      world[00] = " ###                            ".ToCharArray();
119      world[01] = "   #                            ".ToCharArray();
120      world[02] = "   #                    .###..  ".ToCharArray();
121      world[03] = "   #                    #    #  ".ToCharArray();
122      world[04] = "   #                    #    #  ".ToCharArray();
123      world[05] = "   ####.#####       .##..    .  ".ToCharArray();
124      world[06] = "            #       .        #  ".ToCharArray();
125      world[07] = "            #       #        .  ".ToCharArray();
126      world[08] = "            #       #        .  ".ToCharArray();
127      world[09] = "            #       #        #  ".ToCharArray();
128      world[10] = "            .       #        .  ".ToCharArray();
129      world[11] = "            #       .        .  ".ToCharArray();
130      world[12] = "            #       .        #  ".ToCharArray();
131      world[13] = "            #       #        .  ".ToCharArray();
132      world[14] = "            #       #  ...###.  ".ToCharArray();
133      world[15] = "            .   .#...  #        ".ToCharArray();
134      world[16] = "            .   .      .        ".ToCharArray();
135      world[17] = "            #   .      .        ".ToCharArray();
136      world[18] = "            #   #      .#...    ".ToCharArray();
137      world[19] = "            #   #          #    ".ToCharArray();
138      world[20] = "            #   #          .    ".ToCharArray();
139      world[21] = "            #   #          .    ".ToCharArray();
140      world[22] = "            #   .      ...#.    ".ToCharArray();
141      world[23] = "            #   .      #        ".ToCharArray();
142      world[24] = " ..##..#####.   #               ".ToCharArray();
143      world[25] = " #              #               ".ToCharArray();
144      world[26] = " #              #               ".ToCharArray();
145      world[27] = " #     .#######..               ".ToCharArray();
146      world[28] = " #     #                        ".ToCharArray();
147      world[29] = " .     #                        ".ToCharArray();
148      world[30] = " .####..                        ".ToCharArray();
149      world[31] = "                                ".ToCharArray();
150
151      posX = 0;
152      posY = 0;
153      heading = HeadingEnum.East;
154      FoodEaten = 0;
155      steps = 0;
156    }
157
158    public bool Done() {
159      return steps > maxSteps;
160    }
161
162    public void TurnRight() {
163      if (steps <= maxSteps) {
164        steps++;
165        if (heading == HeadingEnum.West) heading = HeadingEnum.North;
166        else heading++;
167      }
168    }
169
170    public void TurnLeft() {
171      if (steps <= maxSteps) {
172        steps++;
173        if (heading == HeadingEnum.North) heading = HeadingEnum.West;
174        else heading--;
175      }
176    }
177
178    public void Move() {
179      if (steps <= maxSteps) {
180        steps++;
181        MoveInternal(ref posX, ref posY);
182        if (world[posY][posX] == '#') {
183          FoodEaten++;
184          world[posY][posX] = '.';
185        }
186      }
187    }
188
189    private void MoveInternal(ref int posX, ref int posY) {
190      switch (heading) {
191        case HeadingEnum.North:
192          posY = (posY + 31) % 32;
193          break;
194        case HeadingEnum.East:
195          posX = (posX + 1) % 32;
196          break;
197        case HeadingEnum.South:
198          posY = (posY + 1) % 32;
199          break;
200        case HeadingEnum.West:
201          posX = (posX + 31) % 32;
202          break;
203      }
204    }
205
206    public bool IsFoodAhead() {
207      int nextPosX = posX;
208      int nextPosY = posY;
209      MoveInternal(ref nextPosX, ref nextPosY);
210      return world[nextPosY][nextPosX] == '#';
211    }
212  }
213}
Note: See TracBrowser for help on using the repository browser.