Created
March 24, 2018 00:24
-
-
Save alpox/ed336e415ff9cca4cb09a47ede99f9df to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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