Skip to content

Instantly share code, notes, and snippets.

@alpox
Created March 24, 2018 00:24
Show Gist options
  • Save alpox/ed336e415ff9cca4cb09a47ede99f9df to your computer and use it in GitHub Desktop.
Save alpox/ed336e415ff9cca4cb09a47ede99f9df to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Text.RegularExpressions;
namespace UNIMotor
{
public class MinePlugin : IPlugin
{
enum WaitFor
{
None,
Mine
}
private event EventHandler Walked;
private event EventHandler WayDone;
private event EventHandler WaysDone;
private WaitFor waitFor;
public Connection Connection { get; private set; }
private MineForm form;
bool started;
string mineRegex = "Umgebung.*?sich (.*?) Fall";
string walkRegex = "^(n|o|s|w|no|so|nw|sw|norden|sueden|westen|osten|suedwesten|suedosten|nordosten|nordwesten)$";
string failRegex = "Eine Falltuer oeffnet sich";
public int[] Position { get; set; }
private int[] newPosition;
public int[,] MineMap { get; set; }
private bool isWalking;
private List<int[]> NoMinePositions;
private List<int[]> FoundNoMinePositions;
public bool Input(InputType type, string str)
{
if (str.ToLower().Trim() == "start falltuer")
{
Start();
Connection.Writer.WriteLine("Aufzeichnung des Falltuerraetsel gestartet!");
return false;
}
if (!started) return true;
switch (type)
{
case InputType.Client:
return HandleClient(str);
case InputType.Unitopia:
return HandleUnitopia(str);
}
return true;
}
private bool HandleClient(string str)
{
if (!new Regex(walkRegex).Match(str).Success) return true;
var optionsMap = new Dictionary<string, Tuple<int, int>>()
{
{ "n", new Tuple<int, int>(-1, 0) },
{ "o", new Tuple<int, int>(1, 1) },
{ "w", new Tuple<int, int>(-1, 1) },
{ "s", new Tuple<int, int>(1, 0) },
{ "nord", new Tuple<int, int>(-1, 0) },
{ "ost", new Tuple<int, int>(1, 1) },
{ "west", new Tuple<int, int>(-1, 1) },
{ "sued", new Tuple<int, int>(1, 0) }
};
str = str.Trim().ToLower();
// Strip map - get all short written
if (str.Length <= 2)
{
var map = optionsMap.Where(pair => pair.Key.Length > 2);
foreach (var pair in map.ToList())
optionsMap.Remove(pair.Key);
}
// Change Position
if (optionsMap.Keys.Any(key => str.Contains(key)))
{
var tuples = optionsMap.Where(pair => str.Contains(pair.Key));
foreach (var tuple in tuples)
{
if (newPosition == null)
newPosition = new int[] { Position[0], Position[1] };
var tup = tuple.Value;
var newPos = newPosition[tup.Item2] + tup.Item1;
if (newPos >= 0 && newPos <= 19)
newPosition[tup.Item2] = newPos;
waitFor = WaitFor.Mine;
}
if (MineMap[newPosition[0], newPosition[1]] == -2)
{
newPosition = null;
Walked = null;
WayDone = null;
WaysDone = null;
waitFor = WaitFor.None;
Connection.Writer.WriteLine("UNIMotor hat verhindert dass du in diese Richtung geht. Du waerst geradewegs in eine Falltuer gelaufen!");
if(!Connection.Busy)
FindNulls();
return false;
}
}
return true;
}
int walkedCount;
private bool HandleUnitopia(string str)
{
if (new Regex(failRegex).Match(str).Success)
{
var bytes = TelnetHelper.SetLineColor(0x01 + 30, Encoding.ASCII.GetBytes("###############################################################\n" +
"## ##\n" +
"## ##\n" +
"## ########### ## ## ## ##\n" +
"## ## #### ## ## ##\n" +
"## ## ## ## ## ## ##\n" +
"## ## ## ## ## ## ##\n" +
"## ######## ## ## ## ## ##\n" +
"## ## ## #### ## ## ## ##\n" +
"## ## ## ## ## ## ##\n" +
"## ## ## ## ## ## ##\n" +
"## ## ## ## ## ########## ##\n" +
"## ##\n" +
"## ##\n" +
"###############################################################"), 0x07 + 30);
Connection.Writer.WriteLine(Encoding.ASCII.GetString(bytes));
form.InvokeMethod(() => form.Close());
return true;
}
if (!new Regex(mineRegex).Match(str).Success) return true;
if (waitFor == WaitFor.Mine && newPosition != null)
{
Position = newPosition;
newPosition = null;
var value = Util.RegexFirstGroup(str, mineRegex, System.Text.RegularExpressions.RegexOptions.Singleline);
int val = 0;//-1; // Not known
if (value != null)
switch (value)
{
case "keine": val = 0; break;
case "eine": val = 1; break;
default: val = Convert.ToInt32(value); break;
}
MineMap[Position[0], Position[1]] = val;
waitFor = WaitFor.None;
MarkMines();
if (form != null)
form.Update();
if ((val == 0 || TestIsNull(Position)) && !ListContainsPosition(NoMinePositions, Position) && !ListContainsPosition(FoundNoMinePositions, Position))
NoMinePositions.Insert(0, new int[] { Position[0], Position[1] });
Thread.Sleep(100);
if (Walked != null)
Walked(this, new EventArgs());
}
if (!Connection.Busy)
FindNulls();
return true;
}
private void MarkMine(int[] position)
{
var sur = GetSurroundingPositions(position);
var val = MineMap[position[0], position[1]];
var list = new List<int[]>();
foreach (var pos in sur)
if (MineMap[pos[0], pos[1]] == -1 || MineMap[pos[0], pos[1]] == -2)
list.Add(pos);
if (list.Count == val)
foreach (var pos in list)
MineMap[pos[0], pos[1]] = -2;
}
private void MarkMines()
{
ForAllInMap((i, p) =>
{
MarkMine(new int[] { i, p });
});
}
private bool ListContainsPosition(List<int[]> poses, int[] pos)
{
var inList = false;
foreach (var poss in poses)
if (poss[0] == pos[0] && poss[1] == pos[1])
{
inList = true;
break;
}
return inList;
}
private void Walk(string str)
{
HandleClient(str);
Connection.UNIClient.Send(str);
Connection.Writer.WriteLine("You are walking in direction: '" + str + "'!");
}
private void WalkWay(string[] str)
{
int count = 1;
if (str.Length > 0 && str.Length > count)
{
Walked += (s, e) =>
{
if (count < str.Length)
{
Walk(str[count++]);
}
else
{
Walked = null;
if (WayDone != null)
WayDone(this, new EventArgs());
}
};
}
if (str.Length > 0)
Walk(str[0]);
else
if (WayDone != null)
WayDone(this, new EventArgs());
if(str.Length <= count)
{
Walked += (s, e) =>
{
Walked = null;
if (WayDone != null)
WayDone(this, new EventArgs());
};
}
}
private void WalkWays(int[][] poses)
{
Connection.Busy = true;
WayDone = null;
int count = 1;
if (poses.Length > 0 && poses.Length > count)
{
WayDone += (s, e) =>
{
if (poses.Length > count)
{
WalkTo(poses[count++]);
}
else
{
WayDone = null;
if (WaysDone != null)
WaysDone(this, new EventArgs());
Connection.Busy = false;
FindNulls();
}
};
}
if (poses.Length > 0)
WalkTo(poses[0]);
else
{
if (WaysDone != null)
{
WaysDone(this, new EventArgs());
}
Connection.Busy = false;
FindNulls();
return;
}
if (poses.Length <= count)
{
WayDone += (s, e) =>
{
WayDone = null;
if (WaysDone != null)
WaysDone(this, new EventArgs());
Connection.Busy = false;
FindNulls();
};
}
}
private void TestAllOnNull()
{
ForAllInMap((i, p) =>
{
var mine = MineMap[i, p];
var pos = new int[] { i, p };
if (mine >= 0)
{
if (TestIsNull(pos) &&
!ListContainsPosition(NoMinePositions, pos) &&
!ListContainsPosition(FoundNoMinePositions, pos))
NoMinePositions.Insert(0, pos);
}
});
}
private bool TestIsNull(int[] position)
{
var surs = GetSurroundingPositions(position);
var countMines = 0;
foreach (var sur in surs)
{
if (MineMap[sur[0], sur[1]] == -2)
countMines++;
}
return countMines == MineMap[position[0], position[1]];
}
private void FindNulls()
{
if (!Connection.Busy)
{
TestAllOnNull();
if (NoMinePositions.Count == 0) return;
FoundNoMinePositions.Add(new int[] { NoMinePositions[0][0], NoMinePositions[0][1] });
var tempPos = NoMinePositions[0];
NoMinePositions.RemoveAt(0);
GetSurroundingValues(tempPos);
}
}
private void GetSurroundingValues(int[] pos)
{
var surrounds = new List<string>() {
"n", "w", "s", "o", "nw", "no", "sw", "so"
};
if (pos[0] == 0)
surrounds.RemoveAll(str => str.Contains("n"));
if (pos[0] == 19)
surrounds.RemoveAll(str => str.Contains("s"));
if (pos[1] == 0)
surrounds.RemoveAll(str => str.Contains("w"));
if (pos[1] == 19)
surrounds.RemoveAll(str => str.Contains("o"));
var posArr = new List<int[]>();
foreach (var sur in surrounds)
{
var surPos = GetPosition(pos, sur);
if (MineMap[surPos[0], surPos[1]] == -1)
posArr.Add(surPos);
}
WalkWays(posArr.ToArray());
}
public void WalkTo(int[] pos, bool streight = false)
{
WalkWay(GetWayTo(Position, pos, streight));
}
private string[] GetWayTo(int[] from, int[] pos, bool streight = false, List<int[]> lastPos = null, List<int[]> freeSpaces = null)
{
var way = new List<string>();
if(freeSpaces == null)
freeSpaces = new List<int[]>();
if (lastPos == null)
lastPos = new List<int[]>();
if (from == null)
from = Position;
var actWayPos = from;
var y = pos[0] - from[0];
var x = pos[1] - from[1];
var dX = x < 0 ? "w" : "o";
var dY = y < 0 ? "n" : "s";
y = y < 0 ? y * -1 : y;
x = x < 0 ? x * -1 : x;
while (!(x == 0 && y == 0))
{
var step = "";
if (y != 0)
{
step += dY;
y--;
}
if (x != 0)
{
step += dX;
x--;
}
int[][] tempLast = new int[lastPos.Count][];
lastPos.CopyTo(tempLast);
lastPos.Add(actWayPos);
freeSpaces.RemoveAll(item => Same(item, actWayPos));
if (IsMined(GetPosition(actWayPos, step), streight) || tempLast.Any(item => Same(item, actWayPos)))
{
var tempPos = actWayPos;
actWayPos = GetFirstNotMined(actWayPos, lastPos, freeSpaces, step, pos, streight);
if (actWayPos == null || GetWayTo(tempPos, actWayPos).Length == 0)
break;
way.AddRange(GetWayTo(tempPos, actWayPos, streight));
way.AddRange(GetWayTo(actWayPos, pos, streight, lastPos, freeSpaces));
break;
}
else
{
var poses = GetSurroundingList(actWayPos);
poses.ForEach(item =>
{
var position = GetPosition(actWayPos, item);
if (!IsMined(position, streight) &&
MineMap[position[0], position[1]] >= 0 &&
!lastPos.Any(lItem => Same(lItem, position)) &&
!freeSpaces.Any(fItem => Same(fItem, position)))
freeSpaces.Insert(0, position);
});
freeSpaces = OrderToPosition(freeSpaces, pos);
actWayPos = GetPosition(actWayPos, step);
way.Add(step);
}
}
return way.ToArray();
}
private bool Same(int[] arr1, int[] arr2)
{
return arr1[0] == arr2[0] && arr1[1] == arr2[1];
}
private bool IsMined(int[] pos, bool streight = false)
{
if (streight) return MineMap[pos[0], pos[1]] == -2;
var isNoFound = false;
foreach (var position in GetSurroundingPositions(pos))
if (TestIsNull(position))
isNoFound = true;
return MineMap[pos[0], pos[1]] == -2 || (MineMap[pos[0], pos[1]] == -1 && !isNoFound);
}
private int[] GetFirstNotMined(int[] pos, List<int[]> lastPos, List<int[]> freeSpaces, string step, int[] to, bool streight = false)
{
var poses = GetSurroundingList(pos);
if (lastPos != null)
poses.ForEach(pose => { if(lastPos.Any(lPos => Same(GetPosition(pos, pose), lPos))) poses.Remove(pose); });
poses.Remove(step);
poses.ForEach(item =>
{
var position = GetPosition(pos, item);
if (!IsMined(position, streight) &&
MineMap[position[0], position[1]] >= 0 &&
!lastPos.Any(lItem => Same(lItem, position)) &&
!freeSpaces.Any(fItem => Same(fItem, position)))
freeSpaces.Insert(0, position);
});
freeSpaces = OrderToPosition(freeSpaces, to);
foreach (var position in freeSpaces)
{
if (!IsMined(position, streight) && MineMap[position[0], position[1]] >= 0)
return position;
}
foreach (var position in freeSpaces)
{
if (!IsMined(position, streight))
return position;
}
return default(int[]);
}
private int ComparePositions(int[] pos1, int[] pos2)
{
var y = pos2[0] - pos1[0];
var x = pos2[1] - pos1[1];
y = y < 0 ? y * -1 : y;
x = x < 0 ? x * -1 : x;
return x + y;
}
private List<int[]> OrderToPosition(List<int[]> list, int[] position)
{
var newList = new List<int[]>();
var lCount = 0;
var nCount = 0;
while (newList.Count != list.Count)
{
var curPos = list[lCount];
nCount = newList.Count - 1;
if (newList.Count == 0)
{
newList.Add(curPos);
lCount++;
continue;
}
while (ComparePositions(newList[nCount], position) > ComparePositions(curPos, position))
{
nCount--;
if (nCount == -1)
break;
}
if (++nCount >= 0)
{
newList.Insert(nCount, curPos);
}
lCount++;
}
return newList;
}
private int[] GetPosition(int[] pos, string step)
{
switch (step)
{
case "n":
return new int[] { pos[0] - 1, pos[1] };
case "s":
return new int[] { pos[0] + 1, pos[1] };
case "w":
return new int[] { pos[0], pos[1] - 1 };
case "o":
return new int[] { pos[0], pos[1] + 1 };
case "nw":
return new int[] { pos[0] - 1, pos[1] - 1 };
case "no":
return new int[] { pos[0] - 1, pos[1] + 1 };
case "sw":
return new int[] { pos[0] + 1, pos[1] - 1 };
case "so":
return new int[] { pos[0] + 1, pos[1] + 1 };
}
return new int[] { 0, 0 };
}
public List<int[]> GetSurroundingPositions(int[] pos)
{
var list = new List<int[]>();
foreach (var direction in GetSurroundingList(pos))
list.Add(GetPosition(pos, direction));
return list;
}
public List<string> GetSurroundingList(int[] pos)
{
var surrounds = new List<string>() {
"n", "w", "s", "o", "nw", "no", "sw", "so"
};
if (pos[0] == 0)
surrounds.RemoveAll(str => str.Contains("n"));
if (pos[0] == 19)
surrounds.RemoveAll(str => str.Contains("s"));
if (pos[1] == 0)
surrounds.RemoveAll(str => str.Contains("w"));
if (pos[1] == 19)
surrounds.RemoveAll(str => str.Contains("o"));
return surrounds;
}
public void Start()
{
walkedCount = 0;
started = true;
Position = new [] { 0, 19 };
MineMap = new int[20, 20];
// Set all to -1 ( Not known )
ForAllInMap((i, p) =>
{
MineMap[i, p] = -1;
});
MineMap[0, 19] = 0;
waitFor = WaitFor.None;
Thread thread = new Thread(() => { Application.Run((form = new MineForm(this))); });
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start();
}
public void Stop()
{
waitFor = WaitFor.None;
Connection.Busy = false;
started = false;
newPosition = null;
Position = new int[] { 0, 19 };
NoMinePositions = new List<int[]>();
FoundNoMinePositions = new List<int[]>();
}
private void ForAllInMap(Action<int, int> action)
{
for (int i = 0; i < MineMap.GetLength(0); i++)
for (int p = 0; p < MineMap.GetLength(1); p++)
action(i, p);
}
public void Create(Connection con)
{
Connection = con;
NoMinePositions = new List<int[]>();
FoundNoMinePositions = new List<int[]>();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment