Files
inf3/src/Parser.cs

436 lines
11 KiB
C#

using System;
using System.Linq;
using System.Threading;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Frontend;
namespace WorldOfPeacecraft
{
public class Parser
{
public const string MessUpdate = "upd";
public const string MessDelete = "del";
public const string MessMap = "map";
public const string MessMessage = "mes";
public const string MessResult = "result";
public const string MessChallenge = "challenge";
public const string MessPlayer = "player";
public const string MessYourid = "yourid";
public const string MessTime = "time";
public const string MessOnline = "online";
public const string MessEntities = "ents";
public const string MessPlayers = "players";
public const string MessDragon = "dragon";
public const string MessMapcell = "cell";
private Queue<string> Buffer = new Queue<string> ();
private AutoResetEvent BufferFilledEvent = new AutoResetEvent (false);
private Thread ParserThread;
private LinkedList<string> Message;
private Regex LastLineRegex;
private Backend backend;
public Parser ()
{
ParserThread = new Thread (new ThreadStart (this.RunParser));
Message = new LinkedList<string> ();
LastLineRegex = new Regex ("^end:[0-9]+$");
}
private void RunParser ()
{
while (true) {
bool waitRequired = false;
lock (Buffer) {
if (Buffer.Count == 0) {
waitRequired = true;
BufferFilledEvent.Reset ();
}
}
if (waitRequired) {
BufferFilledEvent.WaitOne ();
}
lock (Buffer) {
Message.AddLast (Buffer.Dequeue ());
}
if (IsCompletePackage ()) {
Parse ();
}
// TODO Try-catch. IMPORTANT!
}
}
private void Parse ()
{
String[] aMessage = Enumerable.ToArray (Message);
Block mainBlock = new Block (aMessage, 0, aMessage.Length - 1);
ProcessData (mainBlock);
}
private void ProcessData (Block parentBlock)
{
if (parentBlock.GetStringValue ("ans") != null) {
ProcessAnswer (parentBlock);
return;
}
CheckBlocksSize (parentBlock, 1, 1);
Block block = parentBlock.GetBlocks ().First.Value;
switch (block.GetName ()) {
case MessUpdate:
ProcessUpdate (block);
break;
case MessDelete:
ProcessDelete (block);
break;
case MessMap:
ProcessMap (block);
break;
case MessMessage:
ProcessMessage (block);
break;
case MessResult:
ProcessResult (block);
break;
case MessChallenge:
ProcessChallenge (block);
break;
case MessPlayer:
ProcessPlayer (block);
break;
case MessYourid:
ProcessYourid (block);
break;
case MessTime:
ProcessTime (block);
break;
case MessOnline:
ProcessOnline (block);
break;
case MessEntities:
ProcessEntities (block);
break;
case MessPlayers:
ProcessEntities (block);
break;
default:
ThrowUnknownBlockException (parentBlock, block);
break;
}
}
private void ProcessUpdate (Block updateBlock)
{
CheckBlocksSize (updateBlock, 1, 1);
LinkedList<Block> blocks = updateBlock.GetBlocks ();
Block block = blocks.First.Value;
switch (block.GetName ()) {
case MessDragon:
ProcessDragon (block);
break;
case MessPlayer:
ProcessPlayer (block);
break;
case MessMapcell:
ProcessMapcell (block);
break;
default:
ThrowUnknownBlockException (updateBlock, block);
break;
}
}
private void ProcessDelete (Block deleteBlock)
{
CheckBlocksSize (deleteBlock, 1, 1);
LinkedList<Block> blocks = deleteBlock.GetBlocks ();
Block block = blocks.First.Value;
switch (block.GetName ()) {
case MessPlayer:
Player player = MapPlayer (block);
backend.removePlayer (player);
break;
case MessDragon:
Dragon dragon = MapDragon (block);
backend.removeDragon (dragon);
break;
}
}
private void ProcessMap (Block mapBlock)
{
CheckBlocksSize (mapBlock, 1, 1);
Block cellsBlock = mapBlock.GetBlocks ().First.Value;
int height = mapBlock.GetIntValue ("height");
int width = mapBlock.GetIntValue ("width");
try {
CheckBlocksSize (cellsBlock, width * height, width * height);
} catch (ParsingException e) {
throw new ParsingException ("The received map is " + width + "x" + height + "=" + (width * height) + " cells large, but the received cellblock contained " + cellsBlock.GetBlocks ().Count, e);
}
Map map = new Map(height, width);
foreach (Block cell in cellsBlock.GetBlocks()) {
map.SetTile(MapMapcell(cell));
}
backend.SetMap(map);
}
private void ProcessMessage (Block mesBlock)
{
int srcid = mesBlock.GetIntValue ("srcid");
string src = mesBlock.GetStringValue ("src");
string txt = mesBlock.GetStringValue ("txt");
//Message m = new Message (srcid, src, txt);
//TODO Herausfinden wie wir das oben lösen
}
private void ProcessAnswer (Block block)
{
}
private void ProcessResult (Block procBlock)
{
CheckBlocksSize (procBlock, 1, 1);
int round = procBlock.GetIntValue ("round");
bool running = procBlock.GetBoolValue ("running");
int delay = procBlock.GetIntValue ("delay");
//ProcessOpponent (procBlock.GetBlocks ());
//Result r = new Result(round, running, delay);
//TODO Herausfinden wie wir das oben lösen
}
private void ProcessOpponent(Block block)
{
//TODO -> Wafa
}
private void ProcessDecision(Block block)
{
//TODO -> Wafa
}
private void ProcessChallenge (Block block)
{
//TODO -> Samed
}
private void ProcessPlayer (Block playerBlock)
{
int points = playerBlock.GetIntValue ("points");
int id = playerBlock.GetIntValue ("id");
bool busy = playerBlock.GetBoolValue ("busy");
string desc = playerBlock.GetStringValue ("desc");
int x = playerBlock.GetIntValue ("x");
int y = playerBlock.GetIntValue ("y");
//Player p = new Player(points, id, busy, desc, x, y,);
}
private void ProcessYourid (Block yourIdBlock)
{
LinkedList <string> unnamedValues = yourIdBlock.GetUnnamedValues ();
string stringValue = unnamedValues.First.Value;
int intValue = int.Parse (stringValue);
//YourID id = new YourID (intValue);
//TODO Herausfinden wie wir das oben lösen
}
private void ProcessTime (Block block)
{
//TODO -> Wafa
}
private void ProcessOnline (Block block)
{
//TODO -> Wafa
}
private void ProcessEntities (Block block)
{
// TODO -> Manu
}
private void ProcessPlayers (Block block)
{
// TODO -> Manu
}
private void ProcessDragon (Block block)
{
//TODO -> Samed
}
private Dragon MapDragon (Block dragonBlock)
{
int id = dragonBlock.GetIntValue ("id");
bool busy = dragonBlock.GetBoolValue ("busy");
string desc = dragonBlock.GetStringValue ("desc");
int x = dragonBlock.GetIntValue ("x");
int y = dragonBlock.GetIntValue ("y");
return new Dragon (id, x, y, desc, busy);
}
private Player MapPlayer (Block playerBlock)
{
int id = playerBlock.GetIntValue ("id");
int score = playerBlock.GetIntValue ("points");
bool busy = playerBlock.GetBoolValue ("busy");
string desc = playerBlock.GetStringValue ("desc");
int x = playerBlock.GetIntValue ("x");
int y = playerBlock.GetIntValue ("y");
return new Player (id, x, y, desc, busy, score);
}
private Tile MapMapcell (Block cellBlock)
{
CheckBlocksSize (cellBlock, 1, 1);
int x = cellBlock.GetIntValue ("col");
int y = cellBlock.GetIntValue ("row");
Block propsBlock = cellBlock.GetBlocks ().First.Value;
bool walkable = false;
bool wall = false;
bool forest = false;
bool water = false;
bool huntable = false;
foreach (string prop in propsBlock.GetUnnamedValues()) {
switch (prop) {
case "WALKABLE":
walkable = true;
break;
case "WALL":
wall = true;
break;
case "FOREST":
forest = true;
break;
case "WATER":
water = true;
break;
case "HUNTABLE":
huntable = true;
break;
default:
throw new ParsingException("Unknown mapcell-property '" + prop + "'");
}
}
return new Tile(x,y,walkable, wall, forest, huntable, water);
}
private void ThrowUnknownBlockException (Block parentBlock, Block childBlock)
{
throw new ParsingException ("Unknown Block: '" + childBlock.GetName () + "' (as subblock of '" + parentBlock.GetName () + "')");
}
private void CheckBlocksSize (Block parentBlock, int min, int max)
{
LinkedList<Block> blocks = parentBlock.GetBlocks ();
if (blocks.Count < min || (max >= 0 && blocks.Count > max)) {
if (min == max) {
throw new ParsingException ("The block '" + parentBlock.GetName () + "' has to contain exactly '" + min + "' Block, but contained '" + blocks.Count + "'");
} else if (max < 0) {
throw new ParsingException ("The block '" + parentBlock.GetName () + "' has to contain at least '" + min + "' Blocks, but contained '" + blocks.Count + "'");
} else {
throw new ParsingException ("The block '" + parentBlock.GetName () + "' has to contain between '" + min + "' and '" + max + "' Blocks, but contained '" + blocks.Count + "'");
}
}
}
private bool IsCompletePackage ()
{
string lastLine = Message.Last.Value;
return LastLineRegex.IsMatch (lastLine);
}
public void Stop ()
{
ParserThread.Abort ();
}
public void AddToBuffer (string s)
{
lock (Buffer) {
Buffer.Enqueue (s);
BufferFilledEvent.Set ();
}
}
private class Block
{
private string Name;
private LinkedList<Block> Blocks = new LinkedList<Block> ();
private Dictionary<String, String> Values = new Dictionary<String, String> ();
private LinkedList<String> UnnamedValues;
public Block (String[] message, int start, int end)
{
int pos = start;
Name = StringUtils.SubstringAfter (message [pos], ":");
pos++;
while (pos < end) {
// Is the next element a block or a value?
if (message [pos].StartsWith ("begin:")) {
// It's a block
int blockstart = pos;
int begins = 1;
while (begins > 0) {
pos++;
if (pos >= end)
throw new ParsingException ("The message is missing end:-lines");
if (message [pos].StartsWith ("end:"))
begins--;
else if (message [pos].StartsWith ("begin:"))
begins++;
}
Blocks.AddLast (new Block (message, blockstart, pos));
} else if (message[pos].Contains(":")) {
// It's a value
string name = StringUtils.SubstringBefore (message [pos], ":");
string val = StringUtils.SubstringAfter (message [pos], ":");
Values [name] = val;
pos++;
}
else {
UnnamedValues.AddLast(message[pos]);
pos++;
}
}
}
public string GetName ()
{
return Name;
}
public LinkedList<string> GetUnnamedValues()
{
return UnnamedValues;
}
public LinkedList<Block> GetBlocks ()
{
return Blocks;
}
public string GetStringValue (string name)
{
return Values [name];
}
public int GetIntValue (string name)
{
return int.Parse (Values [name]);
}
public long GetLongValue (string name)
{
return long.Parse (Values [name]);
}
public bool GetBoolValue (string name)
{
return bool.Parse (Values [name]);
}
}
}
}