summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Zimniewicz <mzimniew@man.poznan.pl>2016-11-19 17:59:10 +0100
committerMichal Zimniewicz <mzimniew@man.poznan.pl>2016-11-19 17:59:10 +0100
commitcd8f6bf8c23f9a63669d7489dd9d49525c9df6e4 (patch)
treef274fec74eaa624cc86f1b50514d6bddcefd7b20
parent531b20117552e9a7a78bce3a70ad71acff2de340 (diff)
parent211efd174ac0333cdf9f40695ea5673e5bfb7b95 (diff)
Merge branch 'hand-evaluation' into validate-lead-card
-rw-r--r--Aktywator/Aktywator.csproj3
-rw-r--r--Aktywator/Bws.cs68
-rw-r--r--Aktywator/DDTable.cs110
-rw-r--r--Aktywator/HandRecord.cs31
-rw-r--r--Aktywator/MainForm.Designer.cs26
-rw-r--r--Aktywator/PBN.cs36
-rw-r--r--Aktywator/PBNBoard.cs206
-rw-r--r--Aktywator/PBNFile.cs46
-rw-r--r--README.md4
9 files changed, 508 insertions, 22 deletions
diff --git a/Aktywator/Aktywator.csproj b/Aktywator/Aktywator.csproj
index b153254..14bb190 100644
--- a/Aktywator/Aktywator.csproj
+++ b/Aktywator/Aktywator.csproj
@@ -81,6 +81,7 @@
<DependentUpon>ChooseTournament.cs</DependentUpon>
</Compile>
<Compile Include="Common.cs" />
+ <Compile Include="DDTable.cs" />
<Compile Include="HandRecord.cs" />
<Compile Include="MainForm.cs">
<SubType>Form</SubType>
@@ -96,6 +97,8 @@
<DependentUpon>MysqlSettings.cs</DependentUpon>
</Compile>
<Compile Include="PBN.cs" />
+ <Compile Include="PBNBoard.cs" />
+ <Compile Include="PBNFile.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Setting.cs" />
diff --git a/Aktywator/Bws.cs b/Aktywator/Bws.cs
index c4d6962..9533c7e 100644
--- a/Aktywator/Bws.cs
+++ b/Aktywator/Bws.cs
@@ -54,6 +54,8 @@ namespace Aktywator
settings.Add(new Setting("BM2AutoBoardNumber", main.xAutoBoardNumber, this));
settings.Add(new Setting("BM2ResetFunctionKey", main.xResetFunctionKey, this));
settings.Add(new Setting("BM2ViewHandrecord", main.xViewHandrecord, this));
+ settings.Add(new Setting("BM2RecordBidding", main.xCollectBidding, this));
+ settings.Add(new Setting("BM2RecordPlay", main.xCollectPlay, this));
settings.Add(new Setting("BM2ValidateLeadCard", main.xCheckLeadCard, this));
}
@@ -105,6 +107,8 @@ namespace Aktywator
return false;
if (!sql.checkTableExists("HandRecord"))
return false;
+ if (!sql.checkTableExists("HandEvaluation"))
+ return false;
return true;
}
@@ -132,6 +136,8 @@ namespace Aktywator
settings.Add(new Setting("BM2NameSource", "integer", "2"));
settings.Add(new Setting("BM2ViewHandrecord", "bit", "false"));
settings.Add(new Setting("BM2EnterHandrecord", "bit", "false"));
+ settings.Add(new Setting("BM2RecordBidding", "bit", "false"));
+ settings.Add(new Setting("BM2RecordPlay", "bit", "false"));
settings.Add(new Setting("BM2ValidateLeadCard", "bit", "false"));
settings.Add(new Setting("Name", "text(18)", "''", "PlayerNumbers"));
@@ -169,6 +175,41 @@ namespace Aktywator
catch (OleDbException)
{
}
+ try
+ {
+ sql.query("CREATE TABLE HandEvaluation (`Section` integer, `Board` integer, "
+ + "NorthSpades integer,NorthHearts integer,NorthDiamonds integer,NorthClubs integer,NorthNotrump integer,"
+ + "EastSpades integer,EastHearts integer,EastDiamonds integer,EastClubs integer,EastNotrump integer,"
+ + "SouthSpades integer,SouthHearts integer,SouthDiamonds integer,SouthClubs integer,SouthNotrump integer,"
+ + "WestSpades integer,WestHearts integer,WestDiamonds integer,WestClubs integer,WestNotrump integer,"
+ + "NorthHcp integer,EastHcp integer,SouthHcp integer,WestHcp integer"
+ + ");");
+ }
+ catch (OleDbException)
+ {
+ }
+ try
+ {
+ sql.query("CREATE TABLE PlayData ("
+ + "`ID` autoincrement, `Section` integer, `Table` integer, `Round` integer, `Board` integer,"
+ + "`Counter` integer, `Direction` text(2), `Card` text(10), `DateLog` datetime,"
+ + "`TimeLog` datetime, `Erased` bit"
+ + ");");
+ }
+ catch (OleDbException)
+ {
+ }
+ try
+ {
+ sql.query("CREATE TABLE BiddingData ("
+ + "`ID` autoincrement, `Section` integer, `Table` integer, `Round` integer, `Board` integer,"
+ + "`Counter` integer, `Direction` text(2), `Bid` text(10), `DateLog` datetime,"
+ + "`TimeLog` datetime, `Erased` bit"
+ + ");");
+ }
+ catch (OleDbException)
+ {
+ }
}
public void updateSettings()
@@ -379,6 +420,7 @@ namespace Aktywator
public void loadHandRecords(PBN pbn)
{
sql.query("DELETE FROM HandRecord");
+ sql.query("DELETE FROM HandEvaluation");
for (int i = 0; i < pbn.handRecords.Length; i++)
if (pbn.handRecords[i] != null)
for (int section = 1; section <= highSection(); section++)
@@ -405,6 +447,32 @@ namespace Aktywator
str.Append(b.west[2]); str.Append("','");
str.Append(b.west[3]); str.Append("')");
sql.query(str.ToString());
+ int[,] ddTable = pbn.ddTables[i].GetDDTable();
+ if (ddTable != null)
+ {
+ StringBuilder ddStr = new StringBuilder();
+ ddStr.Append("INSERT INTO HandEvaluation VALUES(");
+ ddStr.Append(section); ddStr.Append(",");
+ ddStr.Append(i); ddStr.Append(",");
+ for (int player = 0; player < 4; player++)
+ {
+ for (int denom = 0; denom < 5; denom++)
+ {
+ ddStr.Append(ddTable[player, denom]);
+ ddStr.Append(",");
+ }
+ }
+ for (int j = 0; j < 4; j++)
+ {
+ ddStr.Append(b.hpcs[j]);
+ if (j < 3)
+ {
+ ddStr.Append(",");
+ }
+ }
+ ddStr.Append(")");
+ sql.query(ddStr.ToString());
+ }
}
}
}
diff --git a/Aktywator/DDTable.cs b/Aktywator/DDTable.cs
new file mode 100644
index 0000000..5de9c3b
--- /dev/null
+++ b/Aktywator/DDTable.cs
@@ -0,0 +1,110 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
+
+namespace Aktywator
+{
+ class DDTableInvalidException : FieldNotFoundException
+ {
+ public DDTableInvalidException() : base() { }
+ public DDTableInvalidException(String msg) : base(msg) { }
+ }
+
+ class DDTable
+ {
+ public static char[] DENOMINATIONS = { 'S', 'H', 'D', 'C', 'N' };
+ private static char[] JFR_DENOMS = {'N', 'S', 'H', 'D', 'C'};
+ public static char[] PLAYERS = { 'N', 'E', 'S', 'W' };
+
+ 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)
+ {
+ foreach (int t in table)
+ {
+ if (t > 13 || t < 0)
+ {
+ throw new DDTableInvalidException("Invalid number of tricks: " + t.ToString());
+ }
+ }
+ return table;
+ }
+
+ public DDTable(PBNBoard board)
+ {
+ this.board = board;
+ }
+
+ 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(PLAYERS, player);
+ int denomID;
+ int denom = 0;
+ foreach (char tricks in playerAbility.Groups[2].Value.ToCharArray())
+ {
+ denomID = Array.IndexOf(DENOMINATIONS, JFR_DENOMS[denom]);
+ result[playerID, denomID] = (tricks > '9') ? (tricks - 'A' + 10) : (tricks - '0');
+ denom++;
+ }
+ }
+ return this.validateTable(result);
+ }
+
+ public int[,] GetPBNTable()
+ {
+ List<String> table = this.board.GetOptimumResultTable();
+ List<Match> 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(PLAYERS, player);
+ int denomID = Array.IndexOf(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 null;
+ }
+ }
+ }
+ }
+}
diff --git a/Aktywator/HandRecord.cs b/Aktywator/HandRecord.cs
index bd0e9f9..199e94f 100644
--- a/Aktywator/HandRecord.cs
+++ b/Aktywator/HandRecord.cs
@@ -10,6 +10,7 @@ namespace Aktywator
public string[] east;
public string[] south;
public string[] west;
+ public int[] hpcs;
public HandRecord()
{
@@ -19,6 +20,31 @@ namespace Aktywator
west = new string[4];
}
+ private int _hpcFromHand(string hand)
+ {
+ int hpc = 0;
+ foreach (char c in hand)
+ {
+ if (c == 'a' || c == 'A')
+ {
+ hpc += 4;
+ }
+ if (c == 'k' || c == 'K')
+ {
+ hpc += 3;
+ }
+ if (c == 'q' || c == 'Q')
+ {
+ hpc += 2;
+ }
+ if (c == 'j' || c == 'J')
+ {
+ hpc += 1;
+ }
+ }
+ return hpc;
+ }
+
public HandRecord(string pbnString)
{
string[] hand = pbnString.Split(' ');
@@ -26,6 +52,11 @@ namespace Aktywator
east = hand[1].Split('.');
south = hand[2].Split('.');
west = hand[3].Split('.');
+ hpcs = new int[4];
+ for (int i = 0; i < 4; i++)
+ {
+ hpcs[i] = this._hpcFromHand(hand[i]);
+ }
}
}
}
diff --git a/Aktywator/MainForm.Designer.cs b/Aktywator/MainForm.Designer.cs
index c6df9e2..c28159e 100644
--- a/Aktywator/MainForm.Designer.cs
+++ b/Aktywator/MainForm.Designer.cs
@@ -106,6 +106,8 @@
this.bLoadHands = new System.Windows.Forms.Button();
this.timer = new System.Windows.Forms.Timer(this.components);
this.openPBN = new System.Windows.Forms.OpenFileDialog();
+ this.xCollectBidding = new System.Windows.Forms.CheckBox();
+ this.xCollectPlay = new System.Windows.Forms.CheckBox();
this.groupBoxTop.SuspendLayout();
this.menu.SuspendLayout();
this.statusStrip1.SuspendLayout();
@@ -241,6 +243,8 @@
//
// tabPage1
//
+ this.tabPage1.Controls.Add(this.xCollectPlay);
+ this.tabPage1.Controls.Add(this.xCollectBidding);
this.tabPage1.Controls.Add(this.xCheckLeadCard);
this.tabPage1.Controls.Add(this.xViewHandrecord);
this.tabPage1.Controls.Add(this.xResultsOverview);
@@ -906,6 +910,26 @@
//
this.openPBN.Filter = "PBN|*.pbn";
//
+ // xCollectBidding
+ //
+ this.xCollectBidding.AutoSize = true;
+ this.xCollectBidding.Location = new System.Drawing.Point(339, 115);
+ this.xCollectBidding.Name = "xCollectBidding";
+ this.xCollectBidding.Size = new System.Drawing.Size(97, 17);
+ this.xCollectBidding.TabIndex = 30;
+ this.xCollectBidding.Text = "zbieraj licytację";
+ this.xCollectBidding.UseVisualStyleBackColor = true;
+ //
+ // xCollectPlay
+ //
+ this.xCollectPlay.AutoSize = true;
+ this.xCollectPlay.Location = new System.Drawing.Point(339, 138);
+ this.xCollectPlay.Name = "xCollectPlay";
+ this.xCollectPlay.Size = new System.Drawing.Size(146, 17);
+ this.xCollectPlay.TabIndex = 31;
+ this.xCollectPlay.Text = "zbieraj przebieg rozgrywki";
+ this.xCollectPlay.UseVisualStyleBackColor = true;
+ //
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -1020,6 +1044,8 @@
private System.Windows.Forms.Label label13;
private System.Windows.Forms.Label label9;
private System.Windows.Forms.TextBox eOomRounds;
+ public System.Windows.Forms.CheckBox xCollectPlay;
+ public System.Windows.Forms.CheckBox xCollectBidding;
public System.Windows.Forms.CheckBox xCheckLeadCard;
}
}
diff --git a/Aktywator/PBN.cs b/Aktywator/PBN.cs
index ad7ac99..f6d5393 100644
--- a/Aktywator/PBN.cs
+++ b/Aktywator/PBN.cs
@@ -2,12 +2,14 @@
using System.Collections.Generic;
using System.Text;
using System.IO;
+using System.Windows.Forms;
namespace Aktywator
{
class PBN
{
public HandRecord[] handRecords;
+ public DDTable[] ddTables;
protected int lowBoard;
protected int highBoard;
private int _count;
@@ -19,33 +21,23 @@ namespace Aktywator
public PBN(string filename, int lowBoard, int highBoard)
{
this.handRecords = new HandRecord[highBoard + 1];
+ this.ddTables = new DDTable[highBoard + 1];
- StreamReader f = new StreamReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read));
- try
+ this.lowBoard = lowBoard;
+ this.highBoard = highBoard;
+
+ this._count = 0;
+ PBNFile pbn = new PBNFile(filename);
+ foreach (PBNBoard board in pbn.Boards)
{
- int board = lowBoard;
- bool canBeRead = false;
- _count = 0;
- while (!f.EndOfStream && (board <= highBoard))
+ int boardNo = Int32.Parse(board.GetNumber());
+ if (lowBoard <= boardNo && boardNo <= highBoard)
{
- string line = f.ReadLine();
- if (line.Trim() == "[Board \"" + board + "\"]")
- canBeRead = true;
- else if (canBeRead && (line.Substring(0, 6) == "[Deal "))
- {
- line = line.Substring(line.IndexOf(':') + 1);
- line = line.Substring(0, line.IndexOf('"'));
- handRecords[board] = new HandRecord(line);
- canBeRead = false;
- _count++;
- board++;
- }
+ this.handRecords[boardNo] = new HandRecord(board.GetLayout());
+ this.ddTables[boardNo] = new DDTable(board);
+ this._count++;
}
}
- finally
- {
- f.Close();
- }
}
}
diff --git a/Aktywator/PBNBoard.cs b/Aktywator/PBNBoard.cs
new file mode 100644
index 0000000..fadfd22
--- /dev/null
+++ b/Aktywator/PBNBoard.cs
@@ -0,0 +1,206 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Aktywator
+{
+
+ 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<PBNField> 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<string> lines)
+ {
+ this.Fields = new List<PBNField>();
+ 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 String GetLayout()
+ {
+ string[] dealParts = this.GetField("Deal").Split(':');
+ return dealParts[dealParts.Length - 1];
+ }
+
+ 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<String> players = new List<String>();
+ 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 String GetOptimumResult()
+ {
+ return this.GetField("OptimumResult");
+ }
+
+ public List<Match> ValidateOptimumResultTable(List<String> table)
+ {
+ List<Match> matches = new List<Match>();
+ List<String> duplicates = new List<String>();
+ 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<String> GetOptimumResultTable()
+ {
+ bool fieldFound = false;
+ List<String> result = new List<String>();
+ 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;
+ }
+
+ }
+}
diff --git a/Aktywator/PBNFile.cs b/Aktywator/PBNFile.cs
new file mode 100644
index 0000000..044630a
--- /dev/null
+++ b/Aktywator/PBNFile.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace Aktywator
+{
+ class PBNFile
+ {
+ public List<PBNBoard> Boards;
+
+ private String filename;
+
+ public PBNFile(String filename)
+ {
+ this.filename = filename;
+ this.Boards = new List<PBNBoard>();
+ String[] fileContents = File.ReadAllLines(this.filename);
+ List<String> contents = new List<String>();
+ foreach (String line in fileContents) {
+ contents.Add(line.Trim());
+ }
+ List<String> lines = new List<String>();
+ foreach (String line in contents)
+ {
+ if (line.Length == 0)
+ {
+ if (lines.Count > 0)
+ {
+ this.Boards.Add(new PBNBoard(lines));
+ lines = new List<String>();
+ }
+ }
+ else
+ {
+ lines.Add(line);
+ }
+ }
+ if (lines.Count > 0)
+ {
+ this.Boards.Add(new PBNBoard(lines));
+ }
+ }
+
+ }
+}
diff --git a/README.md b/README.md
index b801265..034b115 100644
--- a/README.md
+++ b/README.md
@@ -3,3 +3,7 @@
Więcej info: http://michzimny.pl/aktywator
Nie jestem dumny z tego kodu, ale działa i dostałem prośby o udostępnienie źródeł, więc udostępniam.
+
+Program zawiera część kodu źródłowego projektu BCDD: http://github.com/emkael/bcdd
+Ta część źródeł udpostępniana jest w uproszczonej licencji BSD: https://opensource.org/licenses/BSD-2-Clause, kompatybilnej z licencją GPL reszty programu.
+