#region License Information
/* HeuristicLab
* Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using HeuristicLab.Data;
using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
namespace HeuristicLab.Problems.GeneticProgramming.ArtificialAnt {
public class Interpreter {
public int MaxTimeSteps { get; private set; }
public int FoodEaten { get; private set; }
public BoolMatrix World { get; private set; }
public ISymbolicExpressionTree Expression { get; private set; }
public int ElapsedTime { get; set; }
private int currentDirection;
private int currentAntLocationRow;
private int currentAntLocationColumn;
private int nFoodItems;
private Stack nodeStack = new Stack();
public Interpreter(ISymbolicExpressionTree tree, BoolMatrix world, int maxTimeSteps) {
this.Expression = tree;
this.MaxTimeSteps = maxTimeSteps;
// create a clone of the world because the ant will remove the food items it can find.
World = (BoolMatrix)world.Clone();
CountFoodItems();
}
private void CountFoodItems() {
nFoodItems = 0;
for (int i = 0; i < World.Rows; i++) {
for (int j = 0; j < World.Columns; j++) {
if (World[i, j]) nFoodItems++;
}
}
}
public void AntLocation(out int row, out int column) {
row = currentAntLocationRow;
column = currentAntLocationColumn;
}
public int AntDirection {
get { return currentDirection; }
}
public void Run() {
while (ElapsedTime < MaxTimeSteps && FoodEaten < nFoodItems) {
Step();
}
}
public void Step() {
// expression evaluated completly => start at root again
if (nodeStack.Count == 0) {
nodeStack.Push(Expression.Root.GetSubtree(0).GetSubtree(0));
}
var currentNode = nodeStack.Pop();
if (currentNode.Symbol.Name == "Left") {
currentDirection = (currentDirection + 3) % 4;
ElapsedTime++;
} else if (currentNode.Symbol.Name == "Right") {
currentDirection = (currentDirection + 1) % 4;
ElapsedTime++;
} else if (currentNode.Symbol.Name == "Move") {
MoveAntForward();
if (World[currentAntLocationRow, currentAntLocationColumn]) {
FoodEaten++;
World[currentAntLocationRow, currentAntLocationColumn] = false;
}
ElapsedTime++;
} else if (currentNode.Symbol.Name == "IfFoodAhead") {
int nextAntLocationRow;
int nextAntLocationColumn;
NextField(out nextAntLocationRow, out nextAntLocationColumn);
if (World[nextAntLocationRow, nextAntLocationColumn]) {
nodeStack.Push(currentNode.GetSubtree(0));
} else {
nodeStack.Push(currentNode.GetSubtree(1));
}
} else if (currentNode.Symbol.Name == "Prog2") {
nodeStack.Push(currentNode.GetSubtree(1));
nodeStack.Push(currentNode.GetSubtree(0));
} else if (currentNode.Symbol.Name == "Prog3") {
nodeStack.Push(currentNode.GetSubtree(2));
nodeStack.Push(currentNode.GetSubtree(1));
nodeStack.Push(currentNode.GetSubtree(0));
} else if (currentNode.Symbol is InvokeFunction) {
var invokeNode = currentNode as InvokeFunctionTreeNode;
var functionDefinition = (SymbolicExpressionTreeNode)FindMatchingFunction(invokeNode.Symbol.FunctionName).Clone();
var argumentCutPoints = (from node in functionDefinition.IterateNodesPrefix()
where node.Subtrees.Count() > 0
from subtree in node.Subtrees
where subtree is ArgumentTreeNode
select new { Parent = node, Argument = subtree.Symbol as Argument, ChildIndex = node.IndexOfSubtree(subtree) }).ToList();
foreach (var cutPoint in argumentCutPoints) {
cutPoint.Parent.RemoveSubtree(cutPoint.ChildIndex);
cutPoint.Parent.InsertSubtree(cutPoint.ChildIndex, (SymbolicExpressionTreeNode)invokeNode.GetSubtree(cutPoint.Argument.ArgumentIndex).Clone());
}
nodeStack.Push(functionDefinition.GetSubtree(0));
} else {
throw new InvalidOperationException(currentNode.Symbol.ToString());
}
}
private void MoveAntForward() {
NextField(out currentAntLocationRow, out currentAntLocationColumn);
}
private void NextField(out int nextAntLocationRow, out int nextAntLocationColumn) {
switch (currentDirection) {
case 0:
nextAntLocationColumn = (currentAntLocationColumn + 1) % World.Columns; // EAST
nextAntLocationRow = currentAntLocationRow;
break;
case 1:
nextAntLocationRow = (currentAntLocationRow + 1) % World.Rows; // SOUTH
nextAntLocationColumn = currentAntLocationColumn;
break;
case 2:
nextAntLocationColumn = (currentAntLocationColumn + World.Columns - 1) % World.Columns; // WEST
nextAntLocationRow = currentAntLocationRow;
break;
case 3:
nextAntLocationRow = (currentAntLocationRow + World.Rows - 1) % World.Rows; // NORTH
nextAntLocationColumn = currentAntLocationColumn;
break;
default:
throw new InvalidOperationException();
}
}
private SymbolicExpressionTreeNode FindMatchingFunction(string name) {
foreach (var defunBranch in Expression.Root.Subtrees.OfType()) {
if (defunBranch.FunctionName == name) return defunBranch;
}
throw new ArgumentException("Function definition for " + name + " not found.");
}
}
}