diff --git a/AboutDialog.Designer.cs b/AboutDialog.Designer.cs new file mode 100644 index 0000000..3e31fdf --- /dev/null +++ b/AboutDialog.Designer.cs @@ -0,0 +1,64 @@ +namespace TTGen +{ + partial class AboutDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.AboutTxt = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // AboutTxt + // + this.AboutTxt.AutoSize = true; + this.AboutTxt.Dock = System.Windows.Forms.DockStyle.Fill; + this.AboutTxt.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.AboutTxt.Location = new System.Drawing.Point(0, 0); + this.AboutTxt.Margin = new System.Windows.Forms.Padding(10); + this.AboutTxt.Name = "AboutTxt"; + this.AboutTxt.Padding = new System.Windows.Forms.Padding(15); + this.AboutTxt.Size = new System.Drawing.Size(232, 46); + this.AboutTxt.TabIndex = 0; + this.AboutTxt.Text = "About text (set programmicatally)"; + // + // AboutDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(284, 153); + this.Controls.Add(this.AboutTxt); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Name = "AboutDialog"; + this.Text = "About"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label AboutTxt; + } +} \ No newline at end of file diff --git a/AboutDialog.cs b/AboutDialog.cs new file mode 100644 index 0000000..7968c1a --- /dev/null +++ b/AboutDialog.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace TTGen +{ + public partial class AboutDialog : Form + { + public AboutDialog() + { + InitializeComponent(); + + AboutTxt.Text = + "Truth Table Generator v1.0 \n" + + "By Lee Zhen Yong AKA bruceoutdoors \n\n" + + "Built date: 30 Nov 2014 \n\n" + + "Uses Dijkstra's Shunting Yard algorithm \n" + + "and reverse polish notation. \n\n" + ; + } + } +} diff --git a/AboutDialog.resx b/AboutDialog.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/AboutDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/App.config b/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/BoolExpr.cs b/BoolExpr.cs new file mode 100644 index 0000000..bd328bb --- /dev/null +++ b/BoolExpr.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace TTGen +{ + class BoolExpr + { + private List Expression; + private const string mismatchParenErrorMsg = + "Error! Mismatched parenthesis in your expression!"; + + public BoolExpr(string input) + { + Expression = Token.Tokenize(input); + InsertANDs(); + + // convert to Reverse Polish Notation + Expression = ShuntingYard(Expression); + } + + public bool Solve() + { + Stack stack = new Stack(); + + foreach (Token t in Expression) { + if (t.Category == Token.TokenCategory.Bool) { + stack.Push(t.BoolVal); + } else if (t.Category == Token.TokenCategory.Op) { + if (t.ArgCount > stack.Count) { + throw new Exception("The user has not input sufficient values in the expression!"); + } + + // evaluate the operator: + switch (t.Symbol) { + case '+': + stack.Push(stack.Pop() | stack.Pop()); + break; + case '^': + stack.Push(stack.Pop() ^ stack.Pop()); + break; + case '*': + stack.Push(stack.Pop() & stack.Pop()); + break; + case '\'': + stack.Push(!stack.Pop()); + break; + default: + throw new Exception("Error: Invalid operation!!"); + } + } + } + + if (stack.Count > 1) throw new Exception("Error: The user input has too many values."); + + return stack.Pop(); + } + + // converts the token list to Reverse Polish Notation (RPN) + // using the Dijkstra's Shunting Yard algorithm + private List ShuntingYard(List list) + { + List outputQueue = new List(); + Stack operatorStack = new Stack(); + + foreach (Token t in list) { + if (t.Category == Token.TokenCategory.Bool) { + outputQueue.Add(t); + } else if (t.Category == Token.TokenCategory.Op) { + while ((operatorStack.Count > 0) && + (operatorStack.Peek().Category == Token.TokenCategory.Op) && + ( + (t.IsLeftAssoc && t.Precedence <= operatorStack.Peek().Precedence) || + (!t.IsLeftAssoc && t.Precedence < operatorStack.Peek().Precedence) + )) { + outputQueue.Add(operatorStack.Pop()); + } + operatorStack.Push(t); + } else if (t.Category == Token.TokenCategory.LeftParen) { + operatorStack.Push(t); + } else if (t.Category == Token.TokenCategory.RightParen) { + try { + while (operatorStack.Peek().Category != Token.TokenCategory.LeftParen) { + outputQueue.Add(operatorStack.Pop()); + } + // pop left parenthesis from the stack + operatorStack.Pop(); + } catch (InvalidOperationException) { + throw new Exception(mismatchParenErrorMsg); + } + } + } + + // pop remaining operators in the stack to the output queue: + while (operatorStack.Count > 0) { + // If the operator token on the top of the stack is a parenthesis + if (operatorStack.Peek().Category == Token.TokenCategory.LeftParen || + operatorStack.Peek().Category == Token.TokenCategory.RightParen) { + throw new Exception(mismatchParenErrorMsg); + } + outputQueue.Add(operatorStack.Pop()); + } + + return outputQueue; + } + + private void InsertANDs() + { + // compare 2 tokens at a time: + int a = 0; int b = 1; + while (b < Expression.Count) { + // iterates through every possible location + // where * should be inserted + if ((Expression[a].Category == Token.TokenCategory.Bool && + Expression[b].Category == Token.TokenCategory.LeftParen) + || + (Expression[a].Category == Token.TokenCategory.Bool && + Expression[b].Category == Token.TokenCategory.Bool) + || + (Expression[a].Category == Token.TokenCategory.RightParen && + Expression[b].Category == Token.TokenCategory.LeftParen) + || + (Expression[a].Category == Token.TokenCategory.RightParen && + Expression[b].Category == Token.TokenCategory.Bool) + || // conditions involving NOT (') + (Expression[a].Symbol == '\'' && + Expression[b].Category == Token.TokenCategory.Bool) + || + (Expression[a].Symbol == '\'' && + Expression[b].Category == Token.TokenCategory.LeftParen) + ) { + Expression.Insert(b, new Token('*', Token.TokenCategory.Op, 4)); + a++; b++; + } + a++; b++; + } + } + + public List GetBoolVars() + { + List boolVars = new List(); + foreach (var t in Expression) { + if (t.Category == Token.TokenCategory.Bool && t.isVariable) { + boolVars.Add(t.Symbol); + } + } + boolVars = boolVars.Distinct().ToList(); + boolVars.Sort(); + + return boolVars; + } + + // set variable value, returns true if successfully changed + public bool SetValue(char c, bool val) + { + bool success = false; + char ch = Char.ToUpper(c); + foreach (var t in Expression) { + if (t.Symbol == ch) { + t.BoolVal = val; + success = true; + } + } + + return success; + } + } +} diff --git a/MainWindow.Designer.cs b/MainWindow.Designer.cs new file mode 100644 index 0000000..6fd5e06 --- /dev/null +++ b/MainWindow.Designer.cs @@ -0,0 +1,253 @@ +namespace TTGen +{ + partial class MainWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.howArToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.EqualityLbl = new System.Windows.Forms.Label(); + this.mainLayout = new System.Windows.Forms.TableLayoutPanel(); + this.TruthTableView = new System.Windows.Forms.ListView(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.ErrorMsgLbl = new System.Windows.Forms.Label(); + this.Input1 = new System.Windows.Forms.TextBox(); + this.Input2 = new System.Windows.Forms.TextBox(); + this.GenBtn = new System.Windows.Forms.Button(); + this.menuStrip1.SuspendLayout(); + this.mainLayout.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // menuStrip1 + // + this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.howArToolStripMenuItem, + this.aboutToolStripMenuItem}); + this.menuStrip1.Location = new System.Drawing.Point(0, 0); + this.menuStrip1.Name = "menuStrip1"; + this.menuStrip1.Size = new System.Drawing.Size(384, 24); + this.menuStrip1.TabIndex = 0; + this.menuStrip1.Text = "menuStrip1"; + // + // howArToolStripMenuItem + // + this.howArToolStripMenuItem.Name = "howArToolStripMenuItem"; + this.howArToolStripMenuItem.Size = new System.Drawing.Size(64, 20); + this.howArToolStripMenuItem.Text = "How Ar?"; + this.howArToolStripMenuItem.Click += new System.EventHandler(this.howArToolStripMenuItem_Click); + // + // aboutToolStripMenuItem + // + this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; + this.aboutToolStripMenuItem.Size = new System.Drawing.Size(52, 20); + this.aboutToolStripMenuItem.Text = "About"; + this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click); + // + // EqualityLbl + // + this.EqualityLbl.AutoSize = true; + this.EqualityLbl.Dock = System.Windows.Forms.DockStyle.Fill; + this.EqualityLbl.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.EqualityLbl.ForeColor = System.Drawing.Color.Green; + this.EqualityLbl.Location = new System.Drawing.Point(3, 257); + this.EqualityLbl.Name = "EqualityLbl"; + this.EqualityLbl.Padding = new System.Windows.Forms.Padding(0, 3, 0, 5); + this.EqualityLbl.Size = new System.Drawing.Size(378, 30); + this.EqualityLbl.TabIndex = 7; + this.EqualityLbl.Text = "Equality Label"; + this.EqualityLbl.TextAlign = System.Drawing.ContentAlignment.TopCenter; + // + // mainLayout + // + this.mainLayout.ColumnCount = 1; + this.mainLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.mainLayout.Controls.Add(this.EqualityLbl, 0, 2); + this.mainLayout.Controls.Add(this.TruthTableView, 0, 1); + this.mainLayout.Controls.Add(this.tableLayoutPanel1, 0, 0); + this.mainLayout.Dock = System.Windows.Forms.DockStyle.Fill; + this.mainLayout.Location = new System.Drawing.Point(0, 24); + this.mainLayout.Name = "mainLayout"; + this.mainLayout.RowCount = 3; + this.mainLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 80F)); + this.mainLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.mainLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); + this.mainLayout.Size = new System.Drawing.Size(384, 287); + this.mainLayout.TabIndex = 9; + // + // TruthTableView + // + this.TruthTableView.Dock = System.Windows.Forms.DockStyle.Fill; + this.TruthTableView.FullRowSelect = true; + this.TruthTableView.GridLines = true; + this.TruthTableView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.TruthTableView.HoverSelection = true; + this.TruthTableView.Location = new System.Drawing.Point(10, 86); + this.TruthTableView.Margin = new System.Windows.Forms.Padding(10, 6, 10, 3); + this.TruthTableView.Name = "TruthTableView"; + this.TruthTableView.Size = new System.Drawing.Size(364, 168); + this.TruthTableView.TabIndex = 9; + this.TruthTableView.UseCompatibleStateImageBehavior = false; + this.TruthTableView.View = System.Windows.Forms.View.Details; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 3; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 30F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 85F)); + this.tableLayoutPanel1.Controls.Add(this.label1, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.label2, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.ErrorMsgLbl, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.Input1, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.Input2, 1, 2); + this.tableLayoutPanel1.Controls.Add(this.GenBtn, 2, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(6, 3); + this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(6, 3, 6, 3); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 3; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(372, 74); + this.tableLayoutPanel1.TabIndex = 10; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Dock = System.Windows.Forms.DockStyle.Fill; + this.label1.Location = new System.Drawing.Point(3, 20); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(24, 25); + this.label1.TabIndex = 0; + this.label1.Text = "#1"; + this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Fill; + this.label2.Location = new System.Drawing.Point(3, 45); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(24, 29); + this.label2.TabIndex = 1; + this.label2.Text = "#2"; + this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // ErrorMsgLbl + // + this.ErrorMsgLbl.AutoSize = true; + this.tableLayoutPanel1.SetColumnSpan(this.ErrorMsgLbl, 3); + this.ErrorMsgLbl.Dock = System.Windows.Forms.DockStyle.Left; + this.ErrorMsgLbl.ForeColor = System.Drawing.Color.Crimson; + this.ErrorMsgLbl.Location = new System.Drawing.Point(3, 0); + this.ErrorMsgLbl.Name = "ErrorMsgLbl"; + this.ErrorMsgLbl.Size = new System.Drawing.Size(99, 20); + this.ErrorMsgLbl.TabIndex = 2; + this.ErrorMsgLbl.Text = "Error Message Text"; + this.ErrorMsgLbl.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // Input1 + // + this.Input1.Dock = System.Windows.Forms.DockStyle.Fill; + this.Input1.Location = new System.Drawing.Point(33, 23); + this.Input1.Name = "Input1"; + this.Input1.Size = new System.Drawing.Size(251, 20); + this.Input1.TabIndex = 4; + this.Input1.TextChanged += new System.EventHandler(this.Input1_TextChanged); + // + // Input2 + // + this.Input2.Dock = System.Windows.Forms.DockStyle.Fill; + this.Input2.Enabled = false; + this.Input2.Location = new System.Drawing.Point(33, 48); + this.Input2.Name = "Input2"; + this.Input2.Size = new System.Drawing.Size(251, 20); + this.Input2.TabIndex = 5; + this.Input2.TextChanged += new System.EventHandler(this.Input2_TextChanged); + // + // GenBtn + // + this.GenBtn.Dock = System.Windows.Forms.DockStyle.Fill; + this.GenBtn.Location = new System.Drawing.Point(290, 23); + this.GenBtn.Name = "GenBtn"; + this.tableLayoutPanel1.SetRowSpan(this.GenBtn, 2); + this.GenBtn.Size = new System.Drawing.Size(79, 48); + this.GenBtn.TabIndex = 6; + this.GenBtn.Text = "Generate!"; + this.GenBtn.UseVisualStyleBackColor = true; + this.GenBtn.Click += new System.EventHandler(this.GenBtn_Click); + // + // MainWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(384, 311); + this.Controls.Add(this.mainLayout); + this.Controls.Add(this.menuStrip1); + this.MainMenuStrip = this.menuStrip1; + this.MinimumSize = new System.Drawing.Size(400, 350); + this.Name = "MainWindow"; + this.Text = "Truth Table Generator"; + this.menuStrip1.ResumeLayout(false); + this.menuStrip1.PerformLayout(); + this.mainLayout.ResumeLayout(false); + this.mainLayout.PerformLayout(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.ToolStripMenuItem howArToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem aboutToolStripMenuItem; + private System.Windows.Forms.Label EqualityLbl; + private System.Windows.Forms.TableLayoutPanel mainLayout; + private System.Windows.Forms.ListView TruthTableView; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label ErrorMsgLbl; + private System.Windows.Forms.TextBox Input1; + private System.Windows.Forms.TextBox Input2; + private System.Windows.Forms.Button GenBtn; + + + + + + } +} + diff --git a/MainWindow.cs b/MainWindow.cs new file mode 100644 index 0000000..f5e5ea8 --- /dev/null +++ b/MainWindow.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace TTGen +{ + public partial class MainWindow : Form + { + private BoolExpr expression1; + private BoolExpr expression2; + private bool error1 = false; + private bool error2 = false; + private bool errors = false; + + public MainWindow() + { + InitializeComponent(); + ErrorMsgLbl.Text = ""; + EqualityLbl.Text = ""; + } + + private void Input1_TextChanged(object sender, EventArgs e) + { + checkInputs(); + } + + private void Input2_TextChanged(object sender, EventArgs e) + { + checkInputs(); + } + + private void checkInputs() + { + if (Input1.Text != "") { + try { + expression1 = new BoolExpr(Input1.Text); + expression1.Solve(); + error1 = false; + Input2.Enabled = true; + } catch (Exception ex) { + ErrorMsgLbl.Text = "Error in #1: " + ex.Message; + error1 = true; + Input2.Enabled = false; + } + } else { + error1 = false; + Input2.Enabled = false; + } + + if (Input2.Enabled && Input2.Text != "") { + try { + expression2 = new BoolExpr(Input2.Text); + expression2.Solve(); + error2 = false; + } catch (Exception ex) { + ErrorMsgLbl.Text = "Error in #2: " + ex.Message; + error2 = true; + } + } else { + error2 = false; + } + + errors = (error1 || error2) ? true : false; + if (!errors) ErrorMsgLbl.Text = ""; + } + + private void GenBtn_Click(object sender, EventArgs e) + { + if (!validateInputs()) return; + + // clear the previous table: + TruthTableView.Columns.Clear(); + TruthTableView.Items.Clear(); + + List boolVars; + + if (isInput2Enabled()) { + // combine both variables from 2 equations: + boolVars = + expression1.GetBoolVars() + .Concat(expression2.GetBoolVars()) + .Distinct().ToList(); + } else { + boolVars = expression1.GetBoolVars(); + } + + bool[,] inputTable = GenInputTable(boolVars.Count); + + foreach (char c in boolVars) { + TruthTableView.Columns.Add(c.ToString()); + } + + // solve: + bool[] answer1 = new bool[inputTable.GetLength(0)]; + bool[] answer2 = new bool[inputTable.GetLength(0)]; ; + for (int i = 0; i < inputTable.GetLength(0); i++) { + for (int j = 0; j < inputTable.GetLength(1); j++) { + expression1.SetValue(boolVars[j], inputTable[i, j]); + if (isInput2Enabled()) expression2.SetValue(boolVars[j], inputTable[i, j]); + } + answer1[i] = expression1.Solve(); + if (isInput2Enabled()) answer2[i] = expression2.Solve(); + } + + bool equal = false; + if (isInput2Enabled()) equal = answer1.SequenceEqual(answer2); + + TruthTableView.Columns.Add("#1"); + if (isInput2Enabled() && !equal) TruthTableView.Columns.Add("#2"); + for (int i = 0; i < inputTable.GetLength(0); i++) { + ListViewItem L = TruthTableView.Items.Add(getBoolStr(inputTable[i, 0])); + for (int j = 1; j < inputTable.GetLength(1); j++) { + L.SubItems.Add(getBoolStr(inputTable[i, j])); + } + L.SubItems.Add(getBoolStr(answer1[i])); + if (isInput2Enabled() && !equal) L.SubItems.Add(getBoolStr(answer2[i])); ; + } + + if (isInput2Enabled()) { + if (equal) { + EqualityLbl.Text = "#1 and #2 are equivalent"; + EqualityLbl.ForeColor = Color.Green; + } else { + EqualityLbl.Text = "#1 and #2 are NOT equivalent"; + EqualityLbl.ForeColor = Color.Crimson; + } + } else { + EqualityLbl.Text = ""; + } + } + + private string getBoolStr(bool b) + { + return b ? "1" : "0"; + } + + private bool isInput2Enabled() + { + return Input2.Enabled && Input2.Text != ""; + } + + private void aboutToolStripMenuItem_Click(object sender, EventArgs e) + { + AboutDialog box = new AboutDialog(); + box.ShowDialog(); + } + + private bool validateInputs() + { + if (Input1.Text == "") { + MessageBox.Show("I can't generate a truth table without any input."); + return false; + } + + if (errors) { + MessageBox.Show("Please make sure there are no errors with your input before generate the truth table."); + return false; + } + + return true; + } + + private bool[,] GenInputTable(int col) + { + bool[,] table; + int row = (int)Math.Pow(2, col); + + table = new bool[row, col]; + + int divider = row; + + // iterate by column + for (int c = 0; c < col; c++) { + divider /= 2; + bool cell = false; + // iterate every row by this column's index: + for (int r = 0; r < row; r++) { + table[r, c] = cell; + if ((divider == 1) || ((r + 1) % divider == 0)) { + cell = !cell; + } + } + } + + return table; + } + + private void howArToolStripMenuItem_Click(object sender, EventArgs e) + { + string text = + "+ => OR gate\n" + + "* => AND gate\n" + + "^ => XOR gate\n" + + "' => NOT gate\n\n" + + "All letters are converted to upper case and\n" + + "interpreted as variables. All other inputs\n" + + "are invalid.\n\n" + + "Example: A(B^C')'+D\n\n" + + "#2 input allows you to compare 2 expressions."; + MessageBox.Show(text); + } + } +} diff --git a/MainWindow.resx b/MainWindow.resx new file mode 100644 index 0000000..d5494e3 --- /dev/null +++ b/MainWindow.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..be7e236 --- /dev/null +++ b/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace TTGen +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new MainWindow()); + } + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..5e0df04 --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BoolSolver")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BoolSolver")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c84daeb3-5aa2-4f53-a7de-48e652b9566e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs new file mode 100644 index 0000000..61c3bd1 --- /dev/null +++ b/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace TTGen.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TTGen.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Properties/Resources.resx b/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs new file mode 100644 index 0000000..3063c04 --- /dev/null +++ b/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace TTGen.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Properties/Settings.settings b/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/TTGenerator.csproj b/TTGenerator.csproj new file mode 100644 index 0000000..07ec520 --- /dev/null +++ b/TTGenerator.csproj @@ -0,0 +1,100 @@ + + + + + Debug + AnyCPU + {2B519794-B44B-4B19-B19F-1DF123540C1D} + WinExe + Properties + TTGen + TTGen + v4.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + Form + + + AboutDialog.cs + + + + Form + + + MainWindow.cs + + + + + + AboutDialog.cs + + + MainWindow.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + \ No newline at end of file diff --git a/TTGenerator.sln b/TTGenerator.sln new file mode 100644 index 0000000..8b726b1 --- /dev/null +++ b/TTGenerator.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TTGenerator", "TTGenerator.csproj", "{2B519794-B44B-4B19-B19F-1DF123540C1D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2B519794-B44B-4B19-B19F-1DF123540C1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2B519794-B44B-4B19-B19F-1DF123540C1D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B519794-B44B-4B19-B19F-1DF123540C1D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B519794-B44B-4B19-B19F-1DF123540C1D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Token.cs b/Token.cs new file mode 100644 index 0000000..e1bca4e --- /dev/null +++ b/Token.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace TTGen +{ + class Token + { + public enum TokenCategory + { + Undefined, + Bool, + Op, + LeftParen, + RightParen + }; + + // higher precendence gets executed first + public int Precedence { get; private set; } + public TokenCategory Category { get; private set; } + public char Symbol { get; private set; } // default value is 0 + // if it not left associative, it is right. + public bool IsLeftAssoc { get; private set; } + public bool BoolVal { get; set; } + public bool isVariable { get; private set; } + public int ArgCount { get; private set; } + + public Token(char symbol, + TokenCategory cat = TokenCategory.Undefined, + int precedence = -1, + int argCount = 0, + bool isLeftAssoc = true) + { + if (cat == TokenCategory.Bool) isVariable = true; + this.Category = cat; + this.Symbol = symbol; + this.Precedence = precedence; + this.IsLeftAssoc = isLeftAssoc; + this.ArgCount = argCount; + } + + // constructor for values + public Token(char symbol, bool boolVal) + { + this.Category = TokenCategory.Bool; + this.BoolVal = boolVal; + this.Symbol = symbol; + } + + public override string ToString() + { + return String.Format("Category: {0}\nValue: {1}\nPrecedence: {2}\nAssociativity: {3}\n", + Category.ToString(), + Symbol == 0 ? BoolVal.ToString() : Symbol.ToString(), + Precedence, + IsLeftAssoc ? "left" : "right"); + } + + public static List Tokenize(string input) + { + List result = new List(); + input = Regex.Replace(input, @"\s+", ""); + foreach (char c in input) { + if (Char.IsLetter(c)) { + // assume all variables are uppercase + result.Add(new Token(Char.ToUpper(c), TokenCategory.Bool)); + continue; + } + switch (c) { + case '0': + result.Add(new Token(c, false)); + break; + case '1': + result.Add(new Token(c, true)); + break; + case '(': + result.Add(new Token(c, TokenCategory.LeftParen)); + break; + case ')': + result.Add(new Token(c, TokenCategory.RightParen)); + break; + case '+': + result.Add(new Token(c, TokenCategory.Op, 2, 2)); + break; + case '^': + result.Add(new Token(c, TokenCategory.Op, 3, 2)); + break; + case '*': + result.Add(new Token(c, TokenCategory.Op, 4, 2)); + break; + case '\'': + result.Add(new Token(c, TokenCategory.Op, 5, 1, false)); + break; + default: + throw new Exception("Unable to tokenize. Make sure all characters are valid."); + } + } + return result; + } + } +}