Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceReintegration/HeuristicLab.Problems.GeneticProgramming/3.3/LawnMower/Interpreter.cs @ 14929

Last change on this file since 14929 was 14929, checked in by gkronber, 7 years ago

#2520 fixed unit tests for new persistence: loading & storing all samples

File size: 7.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
26using HeuristicLab.Persistence;
27
28namespace HeuristicLab.Problems.GeneticProgramming.LawnMower {
29  public static class Interpreter {
30    [StorableType("40bffe1c-3629-42b9-9840-ed713ff5e95a")]
31    private enum Heading {
32      South,
33      East,
34      North,
35      West
36    };
37
38    private class MowerState {
39      public Heading Heading { get; set; }
40      public Tuple<uint, uint> Position { get; set; }
41      public int Energy { get; set; }
42      public MowerState() {
43        Heading = Heading.South;
44        Position = new Tuple<uint, uint>(0, 0);
45        Energy = 0;
46      }
47    }
48
49    public static bool[,] EvaluateLawnMowerProgram(int length, int width, ISymbolicExpressionTree tree) {
50      bool[,] lawn = new bool[length, width];
51      var mowerState = new MowerState();
52      mowerState.Heading = Heading.South;
53      mowerState.Energy = length * width * 2;
54      lawn[mowerState.Position.Item1, mowerState.Position.Item2] = true;
55      EvaluateLawnMowerProgram(tree.Root, mowerState, lawn, tree.Root.Subtrees.Skip(1).ToArray());
56      return lawn;
57    }
58
59    private static Tuple<int, int> EvaluateLawnMowerProgram(ISymbolicExpressionTreeNode node, MowerState mowerState, bool[,] lawn, IEnumerable<ISymbolicExpressionTreeNode> adfs) {
60      if (mowerState.Energy <= 0) return Tuple.Create(0, 0);
61
62      if (node.Symbol is ProgramRootSymbol) {
63        return EvaluateLawnMowerProgram(node.GetSubtree(0), mowerState, lawn, adfs);
64      } else if (node.Symbol is StartSymbol) {
65        return EvaluateLawnMowerProgram(node.GetSubtree(0), mowerState, lawn, adfs);
66      } else if (node.Symbol.Name == "Left") {
67        switch (mowerState.Heading) {
68          case Heading.East: mowerState.Heading = Heading.North;
69            break;
70          case Heading.North: mowerState.Heading = Heading.West;
71            break;
72          case Heading.West: mowerState.Heading = Heading.South;
73            break;
74          case Heading.South:
75            mowerState.Heading = Heading.East;
76            break;
77        }
78        return new Tuple<int, int>(0, 0);
79      } else if (node.Symbol.Name == "Forward") {
80        int dRow = 0;
81        int dCol = 0;
82        switch (mowerState.Heading) {
83          case Heading.East:
84            dCol++;
85            break;
86          case Heading.North:
87            dRow--;
88            break;
89          case Heading.West:
90            dCol--;
91            break;
92          case Heading.South:
93            dRow++;
94            break;
95        }
96        uint newRow = (uint)((mowerState.Position.Item1 + lawn.GetLength(0) + dRow) % lawn.GetLength(0));
97        uint newColumn = (uint)((mowerState.Position.Item2 + lawn.GetLength(1) + dCol) % lawn.GetLength(1));
98        mowerState.Position = Tuple.Create(newRow, newColumn);
99        mowerState.Energy = mowerState.Energy - 1;
100        lawn[newRow, newColumn] = true;
101        return Tuple.Create(0, 0);
102      } else if (node.Symbol.Name == "Sum") {
103        var p = EvaluateLawnMowerProgram(node.GetSubtree(0), mowerState, lawn, adfs);
104        var q = EvaluateLawnMowerProgram(node.GetSubtree(1), mowerState, lawn, adfs);
105        return Tuple.Create(p.Item1 + q.Item1, p.Item2 + q.Item2);
106      } else if (node.Symbol.Name == "Prog") {
107        EvaluateLawnMowerProgram(node.GetSubtree(0), mowerState, lawn, adfs);
108        return EvaluateLawnMowerProgram(node.GetSubtree(1), mowerState, lawn, adfs);
109      } else if (node.Symbol.Name == "Frog") {
110        var p = EvaluateLawnMowerProgram(node.GetSubtree(0), mowerState, lawn, adfs);
111        int x = p.Item1;
112        int y = p.Item2;
113        while (x < 0) x += lawn.GetLength(0);
114        while (y < 0) y += lawn.GetLength(1);
115        var newRow = (uint)((mowerState.Position.Item1 + x) % lawn.GetLength(0));
116        var newCol = (uint)((mowerState.Position.Item2 + y) % lawn.GetLength(1));
117        mowerState.Position = Tuple.Create(newRow, newCol);
118        mowerState.Energy = mowerState.Energy - 1;
119        lawn[newRow, newCol] = true;
120        return Tuple.Create(0, 0);
121      } else if (node.Symbol is InvokeFunction) {
122        var invokeNode = node as InvokeFunctionTreeNode;
123
124        // find the function definition for the invoke call
125        var functionDefinition = (from adf in adfs.Cast<DefunTreeNode>()
126                                  where adf.FunctionName == invokeNode.Symbol.FunctionName
127                                  select adf).Single();
128        // clone the function definition because we are replacing the argument nodes
129        functionDefinition = (DefunTreeNode)functionDefinition.Clone();
130        // find the argument tree nodes and their parents in the original function definition
131        // toList is necessary to prevent that newly inserted branches are iterated
132        var argumentCutPoints = (from parent in functionDefinition.IterateNodesPrefix()
133                                 from subtree in parent.Subtrees
134                                 where subtree is ArgumentTreeNode
135                                 select new { Parent = parent, Argument = subtree.Symbol as Argument, ChildIndex = parent.IndexOfSubtree(subtree) })
136                                 .ToList();
137        // replace all argument tree ndoes with the matching argument of the invoke node
138        foreach (var cutPoint in argumentCutPoints) {
139          cutPoint.Parent.RemoveSubtree(cutPoint.ChildIndex);
140          cutPoint.Parent.InsertSubtree(cutPoint.ChildIndex, (SymbolicExpressionTreeNode)invokeNode.GetSubtree(cutPoint.Argument.ArgumentIndex).Clone());
141        }
142        return EvaluateLawnMowerProgram(functionDefinition.GetSubtree(0), mowerState, lawn, adfs);
143      } else {
144        // try to parse as ephemeral random const with format: "x,y" (x, y in [0..32[)
145        int x, y;
146        var tokens = node.Symbol.Name.Split(',');
147        if (tokens.Length == 2 &&
148            int.TryParse(tokens[0], out x) &&
149            int.TryParse(tokens[1], out y)) {
150          return Tuple.Create(x, y);
151        } else {
152          throw new ArgumentException("Invalid symbol in the lawn mower program.");
153        }
154      }
155    }
156  }
157}
Note: See TracBrowser for help on using the repository browser.