Skip to content

Commit

Permalink
added the A* and Greedy Best First Search with Manhattan and Manhatta…
Browse files Browse the repository at this point in the history
…n/Linear Conflict Heuristics
  • Loading branch information
Siddharth committed Jul 18, 2017
1 parent 285c731 commit 0c3c32c
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 18 deletions.
100 changes: 97 additions & 3 deletions FifteenPuzzle/Heuristics.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Search;

namespace FifteenPuzzle
{
class Heuristics
public class ManhattanDistanceHeuristic : HeuristicBase<PuzzleState>
{
public override string Name { get { return "Manhattan"; } }

public override int Evaluate(PuzzleState state, PuzzleState goalState)
{
var manhattanDistanceOff = 0;

for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
int val = state.Board[i, j];

if (val == 0)
{
continue;
}

var correctPlace = goalState.GetSpace(val);
manhattanDistanceOff += ManhattanDistance(i, j, correctPlace.Row, correctPlace.Col);
}
}

return manhattanDistanceOff;
}

public static int ManhattanDistance(int fromRow, int fromCol, int toRow, int toCol)
{
return Math.Abs(fromRow - toRow) + Math.Abs(fromCol - toCol);
}
}

public class ManhanttanDistanceWithLinearConflictHeuristic: HeuristicBase<PuzzleState>
{
public override string Name { get { return "Manhattan + Linear Conflict"; }}

public override int Evaluate(PuzzleState state, PuzzleState goalState)
{
int manhanttanDist = 0;

var possibleRowConflicts = new Dictionary<int, List<Tuple<int, int>>>();
var possibleColConflicts = new Dictionary<int, List<Tuple<int, int>>>();

for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
int val = state.Board[i, j];
if (val == 0)
{
continue;
}

var correctPos = goalState.GetSpace(val);
manhanttanDist += ManhattanDistanceHeuristic.ManhattanDistance(i, j, correctPos.Row, correctPos.Col);

// check for linear conflicts in the horizontal + vertical direction

if (i == correctPos.Row && j != correctPos.Col)
{
if (!possibleRowConflicts.ContainsKey(i))
{
possibleRowConflicts[i] = new List<Tuple<int, int>>();
}

possibleRowConflicts[i].Add(Tuple.Create(j, correctPos.Col));
}

if (j == correctPos.Col && i != correctPos.Row)
{
if (!possibleColConflicts.ContainsKey(j))
{
possibleColConflicts[j] = new List<Tuple<int, int>>();
}

possibleColConflicts[j].Add(Tuple.Create(i, correctPos.Row));
}

}
}

// Calculate the # of linear conflicts

int linearConflicts = 0;

foreach (List<Tuple<int, int>> possibleConflicts in possibleRowConflicts.Values.Concat(possibleColConflicts.Values))
{
Tuple<int, int> conflict = possibleConflicts.First();

linearConflicts += possibleConflicts.Skip(1).Count(x => (x.Item1 > conflict.Item1 && x.Item2 < conflict.Item2) ||
(x.Item1 < conflict.Item1 && x.Item2 > conflict.Item2));
}

return manhanttanDist + 2 * linearConflicts;

}
}
}
48 changes: 33 additions & 15 deletions FifteenPuzzle/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,38 @@ private static void RunAllTestCases()
Console.WriteLine("**********************");

const string goalState1 = "((0 1 2 3) (4 5 6 7) (8 9 10 11) (12 13 14 15) (0 0))";
const string easyInitState = "((1 2 3 0) (4 5 6 7) (8 9 10 11) (12 13 14 15) (0 3))";
const string medInitState = "((1 2 6 3) (4 5 10 7) (0 9 14 11) (8 12 13 15) (2 0))";
const string hardInitState = "((1 2 3 7) (4 5 6 15) (8 9 11 0) (12 13 14 10) (2 3))";
const string easyInitState1 = "((1 2 3 0) (4 5 6 7) (8 9 10 11) (12 13 14 15) (0 3))";
const string medInitState1 = "((1 2 6 3) (4 5 10 7) (0 9 14 11) (8 12 13 15) (2 0))";
const string hardInitState1 = "((1 2 3 7) (4 5 6 15) (8 9 11 0) (12 13 14 10) (2 3))";

Console.WriteLine("\nGoal State 1: " + goalState1);
Console.WriteLine("EASY Init State: " + easyInitState + "\n");
RunSingleSearch(easyInitState, goalState1);
Console.WriteLine("EASY Init State: " + easyInitState1 + "\n");
RunSingleSearch(easyInitState1, goalState1);

Console.WriteLine("\nGoal State 1: " + goalState1);
Console.WriteLine("MED Init State: " + medInitState + "\n");
RunSingleSearch(medInitState, goalState1);
Console.WriteLine("MED Init State: " + medInitState1 + "\n");
RunSingleSearch(medInitState1, goalState1);

Console.WriteLine("\nGoal State 1: " + goalState1);
Console.WriteLine("HARD Init State: " + hardInitState + "\n");
RunSingleSearch(hardInitState, goalState1);
Console.WriteLine("HARD Init State: " + hardInitState1 + "\n");
RunSingleSearch(hardInitState1, goalState1);

const string goalState2 = "((1 2 3 4) (8 7 6 5) (9 10 11 12) (0 15 14 13) (3 0))";
const string easyInitState2 = "((0 2 3 4) (1 7 6 5) (8 10 11 12) (9 15 14 13) (0 0))";
const string medInitState2 = "((2 3 4 0) (1 8 6 5) (10 7 11 12) (9 15 14 13) (0 3))";
const string hardInitState2 = "((7 1 2 3) (8 6 5 4) (0 9 10 11) (15 14 13 12) (2 0))";

Console.WriteLine("\nGoal State 2: " + goalState2);
Console.WriteLine("EASY Init State: " + easyInitState2 + "\n");
RunSingleSearch(easyInitState2, goalState2);

Console.WriteLine("\nGoal State 2: " + goalState2);
Console.WriteLine("MED Init State: " + medInitState2 + "\n");
RunSingleSearch(medInitState2, goalState2);

Console.WriteLine("\nGoal State 2: " + goalState2);
Console.WriteLine("HARD Init State: " + hardInitState2 + "\n");
RunSingleSearch(hardInitState2, goalState2);
}

private static void RunSingleSearch(string initStateString, string goalStateString)
Expand All @@ -75,17 +92,18 @@ private static void RunSingleSearch(PuzzleState initState, PuzzleState goalState
new Thread(() => Console.WriteLine(searcher.DFS(6).ToString())),
new Thread(() => Console.WriteLine(searcher.DFS(12).ToString())),
new Thread(() => Console.WriteLine(searcher.DFS(18).ToString())),
new Thread(() => Console.WriteLine(searcher.UCS().ToString()))
new Thread(() => Console.WriteLine(searcher.UCS().ToString())),
new Thread(() => Console.WriteLine(searcher.GreedyBestFirstSearch( new ManhattanDistanceHeuristic()).ToString())),
new Thread(() => Console.WriteLine(searcher.AStarSearch(new ManhattanDistanceHeuristic()).ToString())),
new Thread(() =>
Console.WriteLine(searcher.GreedyBestFirstSearch( new ManhanttanDistanceWithLinearConflictHeuristic()).ToString())),
new Thread(() =>
Console.WriteLine(searcher.AStarSearch(new ManhanttanDistanceWithLinearConflictHeuristic()).ToString()))
};

searchThreads.ForEach(x => x.Start());

searchThreads.ForEach(x => x.Join());
}

private static void AskForInput()
{

}
}
}
15 changes: 15 additions & 0 deletions Search/HeuristicBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace Search
{
public abstract class HeuristicBase<T>: IHeuristic where T: StateBase
{
public abstract string Name { get; }
public abstract int Evaluate(T state, T goalState);

public int Evaluate(StateBase state, StateBase goalState)
{
return Evaluate(state as T, goalState as T);
}
}
}
1 change: 1 addition & 0 deletions Search/Search.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
<Compile Include="Searcher.cs" />
<Compile Include="IHeuristic.cs" />
<Compile Include="HeuristicCache.cs" />
<Compile Include="HeuristicBase.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Expand Down
14 changes: 14 additions & 0 deletions Search/Searcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ public SearchResult UCS()
NodeComparator comparator = (node1, node2) => node1.GHat.CompareTo(node2.GHat);
CostFunc cost = (state1, state2) => 1;
return GenericSearch(_initialState, _goalState, "UCS", comparator, cost, null);
}

public SearchResult GreedyBestFirstSearch(IHeuristic heuristic)
{
NodeComparator comparator = (node1, node2) => node1.HHat.CompareTo(node2.HHat);
return GenericSearch(_initialState, _goalState, "Greedy Best First Search",
comparator, (state1, state2) => 1, heuristic);
}

public SearchResult AStarSearch(IHeuristic heuristic)
{
NodeComparator comparator = (node1, node2) => node1.FHat.CompareTo(node2.FHat);
return GenericSearch(_initialState, _goalState, "AStar",
comparator, (state1, state2) => 1, heuristic);
}

public SearchResult GenericSearch(StateBase initialState,
Expand Down

0 comments on commit 0c3c32c

Please sign in to comment.