160 lines
6.2 KiB
C#
160 lines
6.2 KiB
C#
using Bobo.System.Maze.Bot.Interface;
|
|
using HightechICT.Amazeing.Client.Rest;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Bobo.System.Maze.Bot
|
|
{
|
|
public class SimpleBot : BaseBot
|
|
{
|
|
private Stack<Direction> Directions { get; set; } = new Stack<Direction>();
|
|
private List<List<Direction>> ExitDirections { get; set; } = new List<List<Direction>>();
|
|
private List<List<Direction>> CollectionPointDirections { get; set; } = new List<List<Direction>>();
|
|
|
|
public SimpleBot(AmazeingClient mazeClient, ILogger logger) : base(mazeClient, logger)
|
|
{ }
|
|
|
|
public override async Task<int> Run(MazeInfo maze)
|
|
{
|
|
if (MazeClient == null)
|
|
throw new ArgumentException(nameof(MazeClient));
|
|
|
|
if (string.IsNullOrWhiteSpace(maze.Name))
|
|
throw new ArgumentException(nameof(maze.Name));
|
|
|
|
Random random = new Random();
|
|
Logger.Log(LogLevel.Information, "Entering maze '{MazeName}'", maze.Name);
|
|
PossibleActionsAndCurrentScore result = await MazeClient.EnterMaze(maze.Name);
|
|
int collected = 0;
|
|
|
|
do
|
|
{
|
|
if (result.PossibleMoveActions.All(m => m.HasBeenVisited))
|
|
{
|
|
Logger.Log(LogLevel.Debug, "All adjacent tiles have been visited! Going back.");
|
|
result = await MoveBackOne();
|
|
}
|
|
else
|
|
{
|
|
MoveAction[] notVisited = result.PossibleMoveActions.Where(m => !m.HasBeenVisited).ToArray();
|
|
Logger.Log(LogLevel.Debug, $"{string.Join(", ", notVisited.Select(m => m.Direction.ToString()))} have not been visited, selecting next move.");
|
|
int selected = random.Next(notVisited.Length - 1);
|
|
MoveAction moveAction = notVisited[selected];
|
|
|
|
Logger.Log(LogLevel.Debug, $"Moving {moveAction.Direction}, I have {(!moveAction.HasBeenVisited ? "not" : string.Empty)} been here.");
|
|
|
|
result = await MazeClient.Move(moveAction.Direction);
|
|
|
|
Directions.Push(moveAction.Direction);
|
|
}
|
|
|
|
|
|
// if this is an exit, copy the path so we know how to get there
|
|
if (result.CanExitMazeHere)
|
|
{
|
|
ExitDirections.Add(new List<Direction>(Directions));
|
|
}
|
|
|
|
// if this is a collection point, copy the path so we know how to get there
|
|
if (result.CanCollectScoreHere)
|
|
{
|
|
CollectionPointDirections.Add(new List<Direction>(Directions));
|
|
|
|
List<Direction> list = new List<Direction>(Directions);
|
|
}
|
|
|
|
Logger.Log(LogLevel.Debug, $"New tile has {(!result.CanExitMazeHere ? "no" : string.Empty)} exit.");
|
|
|
|
} while (maze.PotentialReward != result.CurrentScoreInHand
|
|
&& CollectionPointDirections.Any()
|
|
&& ExitDirections.Any());
|
|
|
|
|
|
|
|
do
|
|
{
|
|
// create a list of the directions to the current point
|
|
List<Direction> fromStart = new List<Direction>(Directions);
|
|
|
|
// see what collection point is closest (if multiple)
|
|
List<Direction> collectionPointDirections = CollectionPointDirections.First();
|
|
int collectionCommonPointFromStart = int.MaxValue;
|
|
foreach(List<Direction> cdp in CollectionPointDirections)
|
|
{
|
|
int lowest = fromStart.Count() < cdp.Count() ? fromStart.Count() : cdp.Count();
|
|
int lastCommonIndex = 0;
|
|
|
|
// start from index 0 and work up to the lowest size
|
|
for (lastCommonIndex = 0; lastCommonIndex < lowest; lastCommonIndex++)
|
|
{
|
|
if (fromStart[lastCommonIndex] != cdp[lastCommonIndex])
|
|
{
|
|
// not common, break loop
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (lastCommonIndex < collectionCommonPointFromStart)
|
|
{
|
|
collectionPointDirections = cdp;
|
|
collectionCommonPointFromStart = lastCommonIndex;
|
|
}
|
|
}
|
|
|
|
// first go back to the common index
|
|
for (int returnMoves = 0; returnMoves < fromStart.Count - collectionCommonPointFromStart; returnMoves ++)
|
|
{
|
|
await MoveBackOne();
|
|
}
|
|
|
|
for (int toCollectionIndex = collectionCommonPointFromStart + 1; toCollectionIndex < collectionPointDirections.Count(); toCollectionIndex++)
|
|
{
|
|
result = await MazeClient.Move(collectionPointDirections[toCollectionIndex]);
|
|
}
|
|
|
|
// go to collection
|
|
if (result.CanCollectScoreHere)
|
|
{
|
|
collected += result.CurrentScoreInHand;
|
|
await MazeClient.CollectScore();
|
|
}
|
|
|
|
// go to exit
|
|
}
|
|
while (!result.CanExitMazeHere);
|
|
|
|
await MazeClient.ExitMaze();
|
|
|
|
Logger.Log(LogLevel.Information, "Collected {Collected}!", collected);
|
|
Logger.Log(LogLevel.Information, "Exited maze {MazeName}!", maze.Name);
|
|
|
|
return collected;
|
|
}
|
|
|
|
private Task<PossibleActionsAndCurrentScore> MoveBackOne()
|
|
{
|
|
Direction direction = Directions.Pop();
|
|
|
|
switch (direction)
|
|
{
|
|
case Direction.Left:
|
|
direction = Direction.Right;
|
|
break;
|
|
case Direction.Right:
|
|
direction = Direction.Left;
|
|
break;
|
|
case Direction.Up:
|
|
direction = Direction.Down;
|
|
break;
|
|
case Direction.Down:
|
|
direction = Direction.Up;
|
|
break;
|
|
|
|
}
|
|
|
|
Logger.Log(LogLevel.Debug, "Moving {Direction}, I have been here.", direction);
|
|
|
|
return MazeClient.Move(direction);
|
|
}
|
|
}
|
|
}
|