From 74ced229ca6bf25d3d8cb8cdb82bdeca34856604 Mon Sep 17 00:00:00 2001 From: emkael Date: Mon, 23 May 2016 15:58:18 +0200 Subject: * parsing and printing double-dummy trick table --- BCDD.csproj | 1 + DDTable.cs | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ PBNBoard.cs | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Program.cs | 31 +++++++++++++ 4 files changed, 329 insertions(+) create mode 100644 DDTable.cs diff --git a/BCDD.csproj b/BCDD.csproj index 915d67c..50be342 100644 --- a/BCDD.csproj +++ b/BCDD.csproj @@ -48,6 +48,7 @@ + diff --git a/DDTable.cs b/DDTable.cs new file mode 100644 index 0000000..78d58b9 --- /dev/null +++ b/DDTable.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; + +namespace BCDD +{ + class DDTableInvalidException : FieldNotFoundException + { + public DDTableInvalidException() : base() { } + public DDTableInvalidException(String msg) : base(msg) { } + } + + class DDTable + { + private PBNBoard board; + + private int[,] getEmptyTable() + { + int[,] result = new int[4, 5]; + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 5; j++) + { + result[i, j] = -1; + } + } + return result; + } + + private int[,] validateTable(int[,] table) + { + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 5; j++) + { + if (table[i, j] > 13 || table[i, j] < 0) + { + throw new DDTableInvalidException("Invalid number of tricks: " + table[i, j].ToString()); + } + } + } + return table; + } + + public DDTable(PBNBoard board) + { + this.board = board; + } + + public int[,] GetBCalcTable() + { + int[,] result = this.getEmptyTable(); + String deal = this.board.GetLayout(); + IntPtr solver = BCalcWrapper.bcalcDDS_new(Marshal.StringToHGlobalAnsi("PBN"), Marshal.StringToHGlobalAnsi(deal), 0, 0); + for (int denom = 0; denom < 5; denom++) + { + BCalcWrapper.bcalcDDS_setTrumpAndReset(solver, denom); + for (int player = 0; player < 4; player++) + { + BCalcWrapper.bcalcDDS_setPlayerOnLeadAndReset(solver, BCalcWrapper.bcalc_declarerToLeader(player)); + result[player, denom] = 13 - BCalcWrapper.bcalcDDS_getTricksToTake(solver); + } + } + return this.validateTable(result); + } + + public int[,] GetJFRTable() + { + int[,] result = this.getEmptyTable(); + String ability = this.board.GetAbility(); + MatchCollection abilities = this.board.ValidateAbility(ability); + foreach (Match playerAbility in abilities) + { + char player = playerAbility.Groups[1].Value[0]; + int playerID = Array.IndexOf(BCalcWrapper.PLAYERS, player); + int denomID = 4; + foreach (char tricks in playerAbility.Groups[2].Value.ToCharArray()) + { + result[playerID, denomID] = (tricks > '9') ? (tricks - 'A' + 10) : (tricks - '0'); + denomID--; + } + } + return this.validateTable(result); + } + + public int[,] GetPBNTable() + { + List table = this.board.GetOptimumResultTable(); + List parsedTable = this.board.ValidateOptimumResultTable(table); + int[,] result = this.getEmptyTable(); + foreach (Match lineMatch in parsedTable) + { + char player = lineMatch.Groups[1].Value[0]; + char denom = lineMatch.Groups[2].Value[0]; + int tricks = Int16.Parse(lineMatch.Groups[3].Value); + int playerID = Array.IndexOf(BCalcWrapper.PLAYERS, player); + int denomID = Array.IndexOf(BCalcWrapper.DENOMINATIONS, denom); + result[playerID, denomID] = tricks; + } + return this.validateTable(result); + } + + public int[,] GetDDTable() + { + try + { + return this.GetJFRTable(); + } + catch (FieldNotFoundException) + { + try + { + return this.GetPBNTable(); + } + catch (FieldNotFoundException) + { + return this.GetBCalcTable(); + } + } + } + + public static void PrintTable(int[,] ddTable) + { + foreach (char header in BCalcWrapper.DENOMINATIONS) + { + Console.Write('\t'); + Console.Write(header); + } + Console.WriteLine(); + for (int i = 0; i < 4; i++) + { + Console.Write(BCalcWrapper.PLAYERS[i]); + for (int j = 0; j < 5; j++) + { + Console.Write('\t'); + Console.Write(ddTable[i, j].ToString()); + } + Console.WriteLine(); + } + } + } +} diff --git a/PBNBoard.cs b/PBNBoard.cs index f03b809..c9ae180 100644 --- a/PBNBoard.cs +++ b/PBNBoard.cs @@ -36,6 +36,9 @@ namespace BCDD { public List Fields; + private bool? hasOptimumResultTable = null; + private bool? hasAbility = null; + public PBNBoard(List lines) { this.Fields = new List(); @@ -114,5 +117,154 @@ namespace BCDD return this.GetField("Dealer"); } + public MatchCollection ValidateAbility(String ability) + { + Regex abilityMatch = new Regex(@"\b([NESW]):([0-9A-D]{5})\b"); + MatchCollection matches = abilityMatch.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 List ValidateOptimumResultTable(List table) + { + Regex linePattern = new Regex(@"^([NESW])\s+([CDHSN])T?\s+(\d+)$"); + List matches = new List(); + List duplicates = new List(); + foreach (String line in table) + { + Match match = linePattern.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); + } + } + } } diff --git a/Program.cs b/Program.cs index e0a7149..814edce 100644 --- a/Program.cs +++ b/Program.cs @@ -18,6 +18,37 @@ namespace BCDD { Console.WriteLine("Analyzing " + filename); PBNFile file = new PBNFile(filename); + foreach (PBNBoard board in file.Boards) + { + DDTable table = new DDTable(board); + String boardNo; + try + { + boardNo = board.GetNumber(); + } + catch (FieldNotFoundException) + { + boardNo = "?"; + } + try + { + int[,] ddTable = table.GetDDTable(); + if (ddTable != null) + { + Console.WriteLine("Board " + boardNo); + DDTable.PrintTable(ddTable); + } + else + { + Console.WriteLine("ERROR: unable to determine DD table for board " + boardNo); + } + } + catch (Exception e) + { + Console.WriteLine(e.Message); + Console.WriteLine(e.StackTrace); + } + } } Console.WriteLine("Press any key to continue..."); Console.ReadLine(); -- cgit v1.2.3