using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using System.Resources;
namespace Analizator9000
{
///
/// Main application window control.
///
public partial class Form1 : Form
{
///
/// Dealer input scripts parser instance.
///
private DealerParser parser;
///
/// Constructs the main window.
///
public Form1()
{
InitializeComponent();
this.parser = new DealerParser();
}
///
/// Public getter for localization resource manager
///
/// Component resource manager for Form1
public static ResourceManager GetResourceManager() {
if (resManager == null)
{
resManager = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
}
return resManager;
}
///
/// "Select file" button click, opens file selection dialog for input script.
///
///
///
private void button1_Click(object sender, EventArgs e)
{
generateFileDialog.ShowDialog();
}
///
/// Input script file selection event. Initiates input script parsing.
///
///
///
private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
{
try
{
this.parser = new DealerParser();
parser.loadFile(generateFileDialog.FileName);
if (parser.produce > 0) produceBox.Text = parser.produce.ToString();
if (parser.generate > 0) generateBox.Text = parser.generate.ToString();
conditionBox.Text = parser.condition;
if (parser.predeal.ContainsKey("east"))
{
predealEastSpadesBox.Text = parser.predeal["east"][0];
predealEastHeartsBox.Text = parser.predeal["east"][1];
predealEastDiamondsBox.Text = parser.predeal["east"][2];
predealEastClubsBox.Text = parser.predeal["east"][3];
}
if (parser.predeal.ContainsKey("west"))
{
predealWestSpadesBox.Text = parser.predeal["west"][0];
predealWestHeartsBox.Text = parser.predeal["west"][1];
predealWestDiamondsBox.Text = parser.predeal["west"][2];
predealWestClubsBox.Text = parser.predeal["west"][3];
}
if (parser.predeal.ContainsKey("north"))
{
predealNorthSpadesBox.Text = parser.predeal["north"][0];
predealNorthHeartsBox.Text = parser.predeal["north"][1];
predealNorthDiamondsBox.Text = parser.predeal["north"][2];
predealNorthClubsBox.Text = parser.predeal["north"][3];
}
if (parser.predeal.ContainsKey("south"))
{
predealSouthSpadesBox.Text = parser.predeal["south"][0];
predealSouthHeartsBox.Text = parser.predeal["south"][1];
predealSouthDiamondsBox.Text = parser.predeal["south"][2];
predealSouthClubsBox.Text = parser.predeal["south"][3];
}
foreach (String action in parser.actions)
{
actionsBox.Text += action.Substring("average".Length) + "\n";
}
generateFileNameTextBox.Text = generateFileDialog.FileName;
}
catch (Exception ex)
{
MessageBox.Show(
GetResourceManager().GetString("Form1_fileOpenError") + ": " + ex.Message,
GetResourceManager().GetString("Form1_fileOpenError"), MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
///
/// "Generate" button click. Saves the input script file and runs deals generating.
///
///
///
private void generateButton_Click(object sender, EventArgs e)
{
generateGroup.Enabled = false;
analyzeGroup.Enabled = false;
statusListBox.Items.Clear();
progressBar.Value = 0;
resultTextBox.Text = "";
try
{
this.parser.generate = Convert.ToInt64(generateBox.Text);
this.parser.produce = Convert.ToInt64(produceBox.Text);
parser.condition = conditionBox.Text;
parser.predeal["north"] = new String[] { predealNorthSpadesBox.Text, predealNorthHeartsBox.Text, predealNorthDiamondsBox.Text, predealNorthClubsBox.Text };
parser.predeal["south"] = new String[] { predealSouthSpadesBox.Text, predealSouthHeartsBox.Text, predealSouthDiamondsBox.Text, predealSouthClubsBox.Text };
parser.predeal["west"] = new String[] { predealWestSpadesBox.Text, predealWestHeartsBox.Text, predealWestDiamondsBox.Text, predealWestClubsBox.Text };
parser.predeal["east"] = new String[] { predealEastSpadesBox.Text, predealEastHeartsBox.Text, predealEastDiamondsBox.Text, predealEastClubsBox.Text };
foreach (KeyValuePair predeal in parser.predeal)
{
for (int i = 0; i < predeal.Value.Length; i++)
{
predeal.Value[i] = new String(predeal.Value[i].ToUpper().Replace('D', 'Q').Replace('W', 'J').Replace("10", "T").OrderBy(c => "AKQJT98765432".IndexOf(c)).ToArray());
}
}
parser.actions = actionsBox.Text.Split('\n').ToList();
}
catch (Exception ex)
{
MessageBox.Show(GetResourceManager().GetString("Form1_generateInputError") + ": " + ex.Message, GetResourceManager().GetString("Form1_generateInputError"), MessageBoxButtons.OK, MessageBoxIcon.Error);
generateGroup.Enabled = true;
analyzeGroup.Enabled = true;
}
try
{
String outputFileName = parser.saveFile();
DealerWrapper dealer = new DealerWrapper("files/" + outputFileName, this, this.parser.produce);
dealer.run(this.generateEnd);
}
catch (FileNotFoundException)
{
MessageBox.Show(GetResourceManager().GetString("Form1_generateFileNotFoundError"), GetResourceManager().GetString("Form1_error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
generateGroup.Enabled = true;
analyzeGroup.Enabled = true;
}
catch (Exception ex)
{
MessageBox.Show(GetResourceManager().GetString("Form1_generateGeneratorError") + ": " + ex.Message, GetResourceManager().GetString("Form1_generateGeneratorError"), MessageBoxButtons.OK, MessageBoxIcon.Error);
generateGroup.Enabled = true;
analyzeGroup.Enabled = true;
}
}
///
/// Delegate for generating end method callback.
///
///
private delegate void endDelegate(String filename);
///
/// Generating end callback method. Prints out deal generating summary.
///
/// Output (generated deals) file name.
private void generateEnd(String filename)
{
if (this.InvokeRequired)
{
this.Invoke(new endDelegate(generateEnd), new object[] { filename });
}
else
{
progressBar.Value = 100;
if (filename != null)
{
this.addStatusLine(GetResourceManager().GetString("Form1_generateFileSaved") + ": " + filename);
}
analyzeFileNameTextBox.Text = Path.GetFullPath(@"files\" + filename);
generateGroup.Enabled = true;
analyzeGroup.Enabled = true;
}
}
///
/// Delegate for debug line addition method.
///
///
private delegate void AddStatusDelegate(String line);
///
/// Debug line addition method (thread-safe).
///
/// String to be appended to the debug output.
public void addStatusLine(String line)
{
if (line != null)
{
if (statusListBox.InvokeRequired)
{
this.Invoke(new AddStatusDelegate(addStatusLine), new object[] { line });
}
else
{
statusListBox.Items.Add(line);
statusListBox.SelectedIndex = statusListBox.Items.Count - 1;
}
}
}
///
/// Delegate for progress bar update method.
///
/// Percentage of progress to set (0-100)
private delegate void SetProgressDelegate(int progress);
///
/// Progress bar update method (thread-safe).
///
/// Percentage of progress to set (0-100)
public void setProgress(int progress)
{
if (progressBar.InvokeRequired)
{
this.Invoke(new SetProgressDelegate(setProgress), new object[]{ progress });
}
else
{
progressBar.Value = progress;
}
}
///
/// Deals file selection event. Sets the deals file path in the text field.
///
///
///
private void analyzeFileDialog_FileOk(object sender, CancelEventArgs e)
{
analyzeFileNameTextBox.Text = analyzeFileDialog.FileName;
}
///
/// "Select file" button click for deals file selection.
///
///
///
private void button2_Click(object sender, EventArgs e)
{
analyzeFileDialog.ShowDialog();
}
///
/// Instance of analysis summary class.
///
private Accumulator ac;
///
/// "Analyze" button click. Runs the analysis.
///
///
///
private void analyzeButton_Click(object sender, EventArgs e)
{
this.contractCancelButton.Enabled = true;
this.contractAnalyzeButton.Enabled = false;
this.analyzeButton.Enabled = false;
this.abortButton.Enabled = true;
this.fullContractTable.Enabled = false;
statusListBox.Items.Clear();
this.addStatusLine(GetResourceManager().GetString("Form1_analyzeOpenFile") + ": " + analyzeFileNameTextBox.Text);
try
{
String[] deals = File.ReadAllLines(analyzeFileNameTextBox.Text);
if (deals.Length == 0)
{
throw new Exception(GetResourceManager().GetString("Form1_analyzeNoDealsError"));
}
List cons = new List();
foreach (int i in Enumerable.Range(1, 5))
{
foreach (int j in Enumerable.Range(1, 4))
{
if (((CheckBox)contractTable.GetControlFromPosition(i, j)).Checked)
{
cons.Add(new Contract(5 - i, j - 1));
}
}
}
if (cons.Count == 0)
{
throw new Exception(GetResourceManager().GetString("Form1_analyzeNoContractsError"));
}
// we run either "old" Accumulator or contract analysis with ScoreAccumulator,
// depending on the button of event origin
this.ac = sender.GetHashCode().Equals(this.analyzeButton.GetHashCode())
? new Accumulator(deals, cons, this)
: new ScoreAccumulator(deals, cons, this.contractsToScore, vulnerabilityBox.SelectedIndex, this);
this.ac.run(10);
}
catch (Exception ex)
{
MessageBox.Show(GetResourceManager().GetString("Form1_analyzeError") + ": " + ex.Message, GetResourceManager().GetString("Form1_analyzeError"), MessageBoxButtons.OK, MessageBoxIcon.Error);
this.setProgress(0);
analyzeButton.Enabled = true;
abortButton.Enabled = false;
analyzeGroup.Enabled = true;
generateGroup.Enabled = true;
contractAnalyzeButton.Enabled = true;
contractCancelButton.Enabled = false;
fullContractTable.Enabled = true;
}
}
///
/// Delegate for analysis end callback method.
///
private delegate void EndAnalysisDelegate();
///
/// Analysis end callback method. Cleans up visually after the analysis.
///
public void endAnalysis()
{
if (this.InvokeRequired)
{
this.Invoke(new EndAnalysisDelegate(endAnalysis));
}
else
{
this.setProgress(100);
abortButton.Enabled = false;
analyzeGroup.Enabled = true;
generateGroup.Enabled = true;
contractAnalyzeButton.Enabled = true;
contractCancelButton.Enabled = false;
fullContractTable.Enabled = true;
statusListBox.Focus();
this.ac = null;
}
}
///
/// Delegate for result summary display method.
///
/// Result summary string.
private delegate void SetResultDelegate(String res);
///
/// Displays analysis results summary.
///
/// Result summary string.
public void setResult(String res)
{
if (this.InvokeRequired)
{
this.Invoke(new SetResultDelegate(setResult), new object[] { res });
}
else
{
resultTextBox.Text = res;
}
}
///
/// Delegate for contract analysis output
///
/// Dictionary of trick sums for analyzed contracts
/// Dictionary of score sums for analyzed contracts
/// Dictionary of success rate for analyzed contracts
/// Dictionary of matchpoint sums for analyzed contracts
/// Dictionary of IMP sums for analyzed contracts
/// Number of deals already scored
private delegate void UpdateContractTableDelegate(Dictionary trickSum, Dictionary scoreSum, Dictionary successSum, Dictionary maxSum, Dictionary impSum, long dealCount);
///
/// Updates GUI output for contract analysis
///
/// Dictionary of trick sums for analyzed contracts
/// Dictionary of score sums for analyzed contracts
/// Dictionary of success rate for analyzed contracts
/// Dictionary of matchpoint sums for analyzed contracts
/// Dictionary of IMP sums for analyzed contracts
/// Number of deals already scored
public void updateContractTable(Dictionary trickSum, Dictionary scoreSum, Dictionary successSum, Dictionary maxSum, Dictionary impSum, long dealCount)
{
if (this.InvokeRequired)
{
this.Invoke(new UpdateContractTableDelegate(updateContractTable), new object[] { trickSum, scoreSum, successSum, maxSum, impSum, dealCount });
}
else
{
foreach (int row in Enumerable.Range(1, fullContractTable.RowCount - 1))
{
Contract rowContract = this.getContractFromTableRow(row);
if (rowContract != null && rowContract.Frequency > 0)
{
((TextBox)fullContractTable.GetControlFromPosition(5, row)).Text = ((double)trickSum[rowContract] / dealCount).ToString("0.##");
((TextBox)fullContractTable.GetControlFromPosition(6, row)).Text = ((double)scoreSum[rowContract] / dealCount).ToString("0.##");
((TextBox)fullContractTable.GetControlFromPosition(7, row)).Text = ((double)successSum[rowContract] / dealCount).ToString("0.##");
((TextBox)fullContractTable.GetControlFromPosition(8, row)).Text = (maxSum[rowContract] / dealCount).ToString("0.##");
((TextBox)fullContractTable.GetControlFromPosition(9, row)).Text = (impSum[rowContract] / dealCount).ToString("0.##");
}
}
}
}
///
/// "Abort" button click event.
///
///
///
private void abortButton_Click(object sender, EventArgs e)
{
if (this.ac != null)
{
this.ac.abortAnalysis();
}
}
///
/// Mass checkboxes within contract table layout toggle method.
///
/// Set of x-coordinates for checkboxes to toggle.
/// Set of y-coordinates for checkboxes to toggle.
/// Indicates whether box range should be toggled (true) or just checked (false)
private void toggleBoxes(IEnumerable xRange, IEnumerable yRange, bool toggle = true)
{
foreach (int x in xRange)
{
foreach (int y in yRange)
{
CheckBox cb = ((CheckBox)contractTable.GetControlFromPosition(x, y));
cb.Checked = !(toggle && cb.Checked);
}
}
}
///
/// Toggles all contract chackboxes.
///
///
///
private void button3_Click(object sender, EventArgs e)
{
this.toggleBoxes(Enumerable.Range(1, 5), Enumerable.Range(1, 4));
}
///
/// Toggles the first column of checkboxes ("NT").
///
///
///
private void label18_Click(object sender, EventArgs e)
{
this.toggleBoxes(Enumerable.Range(1, 1), Enumerable.Range(1, 4), false);
}
///
/// Toggles the second column of checkboxes (spades).
///
///
///
private void label14_Click(object sender, EventArgs e)
{
this.toggleBoxes(Enumerable.Range(2, 1), Enumerable.Range(1, 4), false);
}
///
/// Toggles the third column of checkboxes (hearts).
///
///
///
private void label15_Click(object sender, EventArgs e)
{
this.toggleBoxes(Enumerable.Range(3, 1), Enumerable.Range(1, 4), false);
}
///
/// Toggles the fourth column of checkboxes (diamonds).
///
///
///
private void label16_Click(object sender, EventArgs e)
{
this.toggleBoxes(Enumerable.Range(4, 1), Enumerable.Range(1, 4), false);
}
///
/// Toggles the fifth column of checkboxes (clubs).
///
///
///
private void label17_Click(object sender, EventArgs e)
{
this.toggleBoxes(Enumerable.Range(5, 1), Enumerable.Range(1, 4), false);
}
///
/// Toggles the first row of checkboxes (North).
///
///
///
private void label19_Click(object sender, EventArgs e)
{
this.toggleBoxes(Enumerable.Range(1, 5), Enumerable.Range(1, 1), false);
}
///
/// Toggles the second row of checkboxes (East).
///
///
///
private void label20_Click(object sender, EventArgs e)
{
this.toggleBoxes(Enumerable.Range(1, 5), Enumerable.Range(2, 1), false);
}
///
/// Toggles the third row of checkboxes (South).
///
///
///
private void label21_Click(object sender, EventArgs e)
{
this.toggleBoxes(Enumerable.Range(1, 5), Enumerable.Range(3, 1), false);
}
///
/// Toggles the fourth row of checkboxes (West).
///
///
///
private void label22_Click(object sender, EventArgs e)
{
this.toggleBoxes(Enumerable.Range(1, 5), Enumerable.Range(4, 1), false);
}
///
/// List of contracts to score by ScoreAccumulator
///
private List contractsToScore = new List();
///
/// Starts contract analysis
///
///
///
private void button4_Click(object sender, EventArgs e)
{
this.contractsToScore.Clear();
this.toggleBoxes(Enumerable.Range(1, 5), Enumerable.Range(1, 4), false);
this.toggleBoxes(Enumerable.Range(1, 5), Enumerable.Range(1, 4));
foreach (int row in Enumerable.Range(1, fullContractTable.RowCount - 1)) {
Contract rowContract = this.getContractFromTableRow(row);
if (rowContract != null)
{
if (rowContract.Level > 0)
{
this.toggleBoxes(Enumerable.Range(5 - rowContract.Denomination, 1), Enumerable.Range(rowContract.Declarer + 1, 1), false); // forcing analysis of certain denomination-declarer combinations
}
if (rowContract.Frequency > 0)
{
this.contractsToScore.Add(rowContract);
}
}
foreach (int column in Enumerable.Range(5, 4)) {
((TextBox)this.fullContractTable.GetControlFromPosition(column, row)).Text = "";
}
}
this.analyzeButton_Click(sender, e);
}
///
/// Enables contract table fields accordingly to selected combo boxes.
///
///
///
private void tableCombo_Change(object sender, EventArgs e)
{
TableLayoutPanelCellPosition position = fullContractTable.GetPositionFromControl((Control)sender);
NumericUpDown frequencyBox = (NumericUpDown)fullContractTable.GetControlFromPosition(4, position.Row);
Contract rowContract = this.getContractFromTableRow(position.Row);
if (rowContract != null)
{
frequencyBox.Enabled = true;
if (frequencyBox.Value < 1)
{
frequencyBox.Value = 1;
}
if (rowContract.Level == 0)
{
((ComboBox)fullContractTable.GetControlFromPosition(1, position.Row)).SelectedIndex = 0;
((ComboBox)fullContractTable.GetControlFromPosition(2, position.Row)).SelectedIndex = 0;
((ComboBox)fullContractTable.GetControlFromPosition(3, position.Row)).SelectedIndex = 0;
}
}
else
{
frequencyBox.Enabled = false;
frequencyBox.Value = 0;
}
}
///
/// Retrieves contract based on a row of GUI table
///
/// Index of the row for the contract
/// Contract object representing user's choice or NULL when the choice is invalid/incomplete
private Contract getContractFromTableRow(int rowIndex)
{
ComboBox levelBox = (ComboBox)fullContractTable.GetControlFromPosition(0, rowIndex);
ComboBox denominationBox = (ComboBox)fullContractTable.GetControlFromPosition(1, rowIndex);
ComboBox modifiersBox = (ComboBox)fullContractTable.GetControlFromPosition(2, rowIndex);
ComboBox declarerBox = (ComboBox)fullContractTable.GetControlFromPosition(3, rowIndex);
NumericUpDown frequencyBox = (NumericUpDown)fullContractTable.GetControlFromPosition(4, rowIndex);
if (levelBox.SelectedIndex < 1 || (denominationBox.SelectedIndex < 1 && levelBox.SelectedIndex != 1) || (declarerBox.SelectedIndex < 1 && levelBox.SelectedIndex != 1))
{
return null;
}
return new Contract(levelBox.SelectedIndex - 1, denominationBox.SelectedIndex - 1, (declarerBox.SelectedIndex + 2) % 4, Math.Max(0, modifiersBox.SelectedIndex), (int)frequencyBox.Value, rowIndex);
}
private void Form1_Load(object sender, EventArgs e)
{
vulnerabilityBox.SelectedIndex = 0; // set default vulnerability for contracts analysis
}
///
/// Cancels contract analysis
///
///
///
private void button5_Click(object sender, EventArgs e)
{
this.contractCancelButton.Enabled = false;
this.contractAnalyzeButton.Enabled = true;
this.abortButton_Click(sender, e);
}
private static ResourceManager resManager;
}
}