From d76442512fd4314fcedbdc28a611f676ab70ce2b Mon Sep 17 00:00:00 2001 From: emkael Date: Wed, 25 May 2016 13:28:25 +0200 Subject: * project directory structure --- src/PBNBoard.cs | 364 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 364 insertions(+) create mode 100644 src/PBNBoard.cs (limited to 'src/PBNBoard.cs') diff --git a/src/PBNBoard.cs b/src/PBNBoard.cs new file mode 100644 index 0000000..72f87a4 --- /dev/null +++ b/src/PBNBoard.cs @@ -0,0 +1,364 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace BCDD +{ + class PBNField + { + public String Key; + public String Value; + public String RawField; + + public PBNField() { } + + public PBNField(String key, String value) + { + this.Key = key; + this.Value = value; + this.RawField = String.Format("[{0} \"{1}\"]", this.Key, this.Value); + } + + public PBNField(String rawData) + { + this.RawField = rawData; + } + } + + class FieldNotFoundException : Exception + { + public FieldNotFoundException() : base() { } + public FieldNotFoundException(String msg) : base(msg) { } + } + + class PBNBoard + { + public List Fields; + + private bool? hasOptimumResultTable = null; + private bool? hasAbility = null; + + private static Regex linePattern = new Regex(@"\[(.*) ""(.*)""\]"); + private static Regex abilityPattern = new Regex(@"\b([NESW]):([0-9A-D]{5})\b"); + private static Regex optimumResultTablePattern = new Regex(@"^([NESW])\s+([CDHSN])T?\s+(\d+)$"); + + public PBNBoard(List lines) + { + this.Fields = new List(); + foreach (String line in lines) + { + PBNField field = new PBNField(); + field.RawField = line; + Match lineParse = PBNBoard.linePattern.Match(line); + if (lineParse.Success) + { + field.Key = lineParse.Groups[1].Value; + field.Value = lineParse.Groups[2].Value; + } + this.Fields.Add(field); + } + } + + public bool HasField(String key) + { + foreach (PBNField field in this.Fields) + { + if (key.Equals(field.Key)) + { + return true; + } + } + return false; + } + + public String GetField(String key) + { + foreach (PBNField field in this.Fields) + { + if (key.Equals(field.Key)) + { + return field.Value; + } + } + throw new FieldNotFoundException(key + " field not found"); + } + + public void DeleteField(String key) + { + List toRemove = new List(); + foreach (PBNField field in this.Fields) + { + if (key.Equals(field.Key)) + { + toRemove.Add(field); + } + } + foreach (PBNField remove in toRemove) + { + this.Fields.Remove(remove); + } + } + + public String GetLayout() + { + return this.GetField("Deal"); + } + + public String GetNumber() + { + return this.GetField("Board"); + } + + public String GetVulnerable() + { + return this.GetField("Vulnerable"); + } + + public String GetDealer() + { + return this.GetField("Dealer"); + } + + public MatchCollection ValidateAbility(String ability) + { + MatchCollection matches = PBNBoard.abilityPattern.Matches(ability); + if (matches.Count != 4) + { + this.hasAbility = false; + throw new DDTableInvalidException("Invalid Ability line: " + ability); + } + List players = new List(); + foreach (Match match in matches) + { + if (players.Contains(match.Groups[1].Value)) + { + this.hasAbility = false; + throw new DDTableInvalidException("Duplicate entry in Ability: " + match.Groups[0].Value); + } + else + { + players.Add(match.Groups[1].Value); + } + } + this.hasAbility = true; + return matches; + } + + public String GetAbility() + { + return this.GetField("Ability"); + } + + public void DeleteAbility() + { + this.DeleteField("Ability"); + } + + public void WriteAbility(int[,] ddTable) + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 4; i++) + { + sb.Append(BCalcWrapper.PLAYERS[i]); + sb.Append(':'); + for (int j = 4; j >= 0; j--) + { + sb.Append((char)(ddTable[i, j] > 9 ? 'A' + ddTable[i, j] - 10 : ddTable[i, j] + '0')); + } + if (i < 3) + { + sb.Append(' '); + } + } + String abilityStr = sb.ToString(); + this.Fields.Add(new PBNField("Ability", abilityStr)); + } + + public String GetMinimax() + { + return this.GetField("Minimax"); + } + + public void DeleteMinimax() + { + this.DeleteField("Minimax"); + } + + public void WriteMinimax(ParContract contract) + { + this.Fields.Add(new PBNField("Minimax", String.Format("{0}{1}{2}{3}{4}", contract.Level, contract.Denomination, contract.Doubled ? "D" : "", contract.Declarer, contract.Score))); + } + + public String GetOptimumScore() + { + return this.GetField("OptimumScore"); + } + + public void DeleteOptimumScore() + { + this.DeleteField("OptimumScore"); + } + + public void WriteOptimumScore(ParContract contract) + { + this.Fields.Add(new PBNField("OptimumScore", String.Format("NS {0}", contract.Score))); + } + + public String GetOptimumResult() + { + return this.GetField("OptimumResult"); + } + + public List ValidateOptimumResultTable(List table) + { + List matches = new List(); + List duplicates = new List(); + foreach (String line in table) + { + Match match = PBNBoard.optimumResultTablePattern.Match(line); + if (!match.Success) + { + this.hasOptimumResultTable = false; + throw new DDTableInvalidException("Invalid OptimumResultTable line: " + line); + } + String position = match.Groups[1].Value + " - " + match.Groups[2].Value; + if (duplicates.Contains(position)) + { + this.hasOptimumResultTable = false; + throw new DDTableInvalidException("Duplicate OptimumResultTable line: " + line); + } + else + { + duplicates.Add(position); + } + matches.Add(match); + } + this.hasOptimumResultTable = true; + return matches; + } + + public List GetOptimumResultTable() + { + bool fieldFound = false; + List result = new List(); + foreach (PBNField field in this.Fields) + { + if ("OptimumResultTable".Equals(field.Key)) + { + fieldFound = true; + } + else + { + if (fieldFound) + { + if (field.Key == null) + { + result.Add(field.RawField); + } + else + { + break; + } + } + } + } + if (!fieldFound) + { + this.hasOptimumResultTable = false; + throw new FieldNotFoundException("OptimumResultTable field not found"); + } + return result; + } + + public void DeleteOptimumResultTable() + { + bool fieldFound = false; + List toRemove = new List(); + foreach (PBNField field in this.Fields) + { + if ("OptimumResultTable".Equals(field.Key)) + { + fieldFound = true; + toRemove.Add(field); + } + else + { + if (fieldFound) + { + if (field.Key == null) + { + toRemove.Add(field); + } + else + { + break; + } + } + } + } + foreach (PBNField remove in toRemove) + { + this.Fields.Remove(remove); + } + } + + public void WriteOptimumResultTable(int[,] ddTable) + { + this.Fields.Add(new PBNField("OptimumResultTable", @"Declarer;Denomination\2R;Result\2R")); + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 5; j++) + { + this.Fields.Add(new PBNField(String.Format("{0} {1}{2} {3}", BCalcWrapper.PLAYERS[i], BCalcWrapper.DENOMINATIONS[j], (BCalcWrapper.DENOMINATIONS[j] == 'N') ? "T" : "", ddTable[i, j]))); + } + } + } + + public void SaveParContract(ParContract contract) + { + this.DeleteOptimumScore(); + this.WriteOptimumScore(contract); // we're not writing DDS custom fields, just parse them + this.DeleteMinimax(); + this.WriteMinimax(contract); + } + + public void SaveDDTable(int[,] ddTable) + { + if (this.hasOptimumResultTable == null) + { + try + { + List optimumResultTable = this.ValidateOptimumResultTable(this.GetOptimumResultTable()); + this.hasOptimumResultTable = true; + } + catch (FieldNotFoundException) + { + this.hasOptimumResultTable = false; + } + } + if (this.hasOptimumResultTable == false) + { + this.DeleteOptimumResultTable(); + this.WriteOptimumResultTable(ddTable); + } + if (this.hasAbility == null) + { + try + { + MatchCollection ability = this.ValidateAbility(this.GetAbility()); + this.hasAbility = true; + } + catch (FieldNotFoundException) + { + this.hasAbility = false; + } + } + if (this.hasAbility == false) + { + this.DeleteAbility(); + this.WriteAbility(ddTable); + } + } + } +} -- cgit v1.2.3