用户需求:
程序能接收用户输入的整数答案,并判断对错
程序结束时,统计出答对、答错的题目数量。
补充说明:0——10的整数是随机生成的
用户可以选择四则运算中的一种
用户可以结束程序的运行,并显示统计结果。
在此基础上,做增量开发。
增量内容: 1)处理用户的错误输入,比如输入字母或符号等,处理除法运算中分母为0的情况,处理结果为负数的情况,保证是小学水平不出现负数,比如不能出现5-8=-3这种情况;
2)用户可以设定倒计时;
3)用户可以设定随机整数的范围和题目数量;
4)用户可以选择哪种计算类型,比如加减乘除,或可选择软件随机生成四则运算中的一种;
5)用户可以选择随机生成的题目中是否带有小括号,比如(2+3)*5,如果是gui程序,添加这个功能可以用复选框实现。
6)保证生成过的题目不再重复出现。
设计思路:
因为是做增量啊,所以呢,我在看了5和6这两个增量之后,第一感觉是有点难度。这次和之前的运算不同的地方是:
对于5):加了小括号,这就要考虑优先级了,并且不能再用两个文本框来生成两个数字进行运算了。所以我考虑,把两个文本框合成一个文本框,这样的话就让它来存生成的一个式子,最后只对这个式子进行运算就OK了,这不但可以生成两个数的运算表达式,还可以生成三个数的运算表达式,就看你怎么定义出题方法了。当然了,想的是很简单,毕竟生成的是一个式子而并非两个数进行计算那么简单了。所以我继续分析,就对后面的这个式子进行研究啊。首先它是一个字符串表达式,而进行计算的话肯定不能用string类型的来进行计算。所以用队列把表达式里的每一个数取出来,并定义一个栈,让取出的元素放到栈里,这样的话只对栈里元素用逆波兰式进行计算就可以了。
1.对于实现 出题为一个字符串表达式,我用了如下这种方法:
n1 = ran.Next(int.Parse(textBox4.Text), int.Parse(textBox5.Text)); n2 = ran.Next(int.Parse(textBox4.Text), int.Parse(textBox5.Text)); , int.Parse(textBox5.Text)); textBox1.Text += "("; ) textBox1.Text += "(" + n1 + ")"; else textBox1.Text += n1; , ) == ) textBox1.Text += "+"; else textBox1.Text += "-"; ) textBox1.Text += "(" + n2 + ")"; else textBox1.Text += n2 + ")"; , ) == ) textBox1.Text += "*"+n3; else textBox1.Text += "/" + n3; break;
2.对于让它连续出一种运算的表达式,根据最小取值范围的字符长度,也就是截取第一个运算数后面的运算符来进行判断。如下:
) == "+") { RandomNumjia(); }
3.在准备工作做好之后就是进行计算了:
代码实现:
Form1.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace _Random { public partial class Form1 : Form { public Form1() { InitializeComponent(); } ; ; ; ; private void button1_Click(object sender, EventArgs e) { label2.Text = t.ToString(); timer1.Enabled = true; timer1.Interval = ; timer1.Start(); } private void RDN() { Random ran=new Random(); int n1,n2; if (textBox4.Text==""&&textBox5.Text=="") { MessageBox.Show("请输入取值范围!"); return; } if (checkBox1.Checked == true) ; ; i < int.Parse(textBox6.Text); i++) { textBox1.Clear(); switch (select) { : { n1 = ran.Next(int.Parse(textBox4.Text), int.Parse(textBox5.Text)); n2 = ran.Next(int.Parse(textBox4.Text), int.Parse(textBox5.Text)); , int.Parse(textBox5.Text)); textBox1.Text += "("; ) textBox1.Text += "(" + n1 + ")"; else textBox1.Text += n1; , ) == ) textBox1.Text += "+"; else textBox1.Text += "-"; ) textBox1.Text += "(" + n2 + ")"; else textBox1.Text += n2 + ")"; , ) == ) textBox1.Text += "*"+n3; else textBox1.Text += "/" + n3; break; } } textBox3.Text = ""; } } private void RandomNumjia() { textBox1.Clear(); textBox3.Clear(); if (textBox4.Text == "" && textBox5.Text == "") { MessageBox.Show("请输入取值范围!"); return; } Random ran = new Random(); int n1 = ran.Next(int.Parse(textBox4.Text), int.Parse(textBox5.Text)); int n2 = ran.Next(int.Parse(textBox4.Text), int.Parse(textBox5.Text)); ) textBox1.Text += "(" + n1 + ")"; else textBox1.Text += n1; textBox1.Text += "+"; ) textBox1.Text += "(" + n2 + ")"; else textBox1.Text += n2; } private void RandomNumjian() { textBox1.Clear(); textBox3.Clear(); if (textBox4.Text == "" && textBox5.Text == "") { MessageBox.Show("请输入取值范围!"); return; } Random ran = new Random(); int n1 = ran.Next(int.Parse(textBox4.Text), int.Parse(textBox5.Text)); int n2 = ran.Next(int.Parse(textBox4.Text), int.Parse(textBox5.Text)); ) textBox1.Text += "(" + n1 + ")"; else textBox1.Text += n1; textBox1.Text += "-"; ) textBox1.Text += "(" + n2 + ")"; else textBox1.Text += n2; } private void RandomNumcheng() { textBox1.Clear(); textBox3.Clear(); if (textBox4.Text == "" && textBox5.Text == "") { MessageBox.Show("请输入取值范围!"); return; } Random ran = new Random(); int n1 = ran.Next(int.Parse(textBox4.Text), int.Parse(textBox5.Text)); int n2 = ran.Next(int.Parse(textBox4.Text), int.Parse(textBox5.Text)); ) textBox1.Text += "(" + n1 + ")"; else textBox1.Text += n1; textBox1.Text += "*"; ) textBox1.Text += "(" + n2 + ")"; else textBox1.Text += n2; } private void RandomNumchu() { textBox1.Clear(); textBox3.Clear(); if (textBox4.Text == "" && textBox5.Text == "") { MessageBox.Show("请输入取值范围!"); return; } Random ran = new Random(); int n1 = ran.Next(int.Parse(textBox4.Text), int.Parse(textBox5.Text)); int n2 = ran.Next(int.Parse(textBox4.Text), int.Parse(textBox5.Text)); ) textBox1.Text += "(" + n1 + ")"; else textBox1.Text += n1; textBox1.Text += "/"; ) textBox1.Text += "(" + n2 + ")"; else textBox1.Text += n2; } private void timer1_Tick(object sender, EventArgs e) { ) { timer1.Enabled = false; textBox3.Enabled = false; MessageBox.Show("时间到!"); textBox3.Enabled = false; Form2 frm2 = new Form2(); frm2.ShowDialog(); } t = t - ; label2.Text = t.ToString(); } private void button2_Click(object sender, EventArgs e) { timer1.Stop(); Form2 frm2 = new Form2(); frm2.ShowDialog(); } private void button3_Click(object sender, EventArgs e) { RandomNumjia(); } private void button4_Click(object sender, EventArgs e) { RandomNumjian(); } private void button5_Click(object sender, EventArgs e) { RandomNumcheng(); } private void button6_Click(object sender, EventArgs e) { RandomNumchu(); } private void button7_Click(object sender, EventArgs e) { if (textBox4.Text == "" && textBox5.Text == "") { MessageBox.Show("请输入取值范围!"); return; } else { ; i < int.Parse(textBox6.Text);i++) { RDN(); } } } private void textBox3_KeyDown(object sender, KeyEventArgs e) { string result = textBox1.Text; if (Count == int.Parse(textBox6.Text)) { Form2 frm2 = new Form2(); frm2.ShowDialog(); } if (e.KeyCode == Keys.Enter) { if (textBox3.Text == Calucate(result).ToString()) //直接调用Calucate这个方法计算result的值并与输入的值进行比较 { right++; Count++; MessageBox.Show("回答正确!"); } else { MessageBox.Show("答题错误!"); Count++; string s = textBox1.Text; ) == "+") { RandomNumjia(); } ) == "-") { RandomNumjian(); } ) == "*") { RandomNumcheng(); } ) == "/") { RandomNumchu(); } ) { RDN(); } } string m = textBox1.Text; ) == "+") { RandomNumjia(); } , ) == "-") { RandomNumjian(); } , ) == "*") { RandomNumcheng(); } , ) == "/") { RandomNumchu(); } ) { RDN(); } } } const string operators = "+-*/"; //运算符 static Dictionary<char, int> priorities = null; //优先级 static void Calculator() //添加了四种运算符以及四种运算符的优先级 { priorities = new Dictionary<char, int>(); priorities.Add(); priorities.Add(); priorities.Add(); priorities.Add(); priorities.Add(); } static int Compute(int leftNum, int rightNum, char op) //这是一种方法,用来计算左右两个数的静态方法! { switch (op) { case '+': return leftNum + rightNum; case '-': return leftNum - rightNum; case '*': return leftNum * rightNum; case '/': return leftNum / rightNum; ; } } static bool IsOperator(char op) //每次判断这个字符是否是运算符? { ; } static bool IsAssoc(char op) //返回一个关联符号 { return op == '+' || op == '-' || op == '*' || op == '/'; } static Queue<object> QueueSort (string expression) // 队列排序 { Queue<object> result = new Queue<object>(); Stack<char> operatorStack = new Stack<char>(); //运算符栈 operatorStack.Push('#'); char top, cur, tempChar; //top栈顶,current最近的; string tempNum; , j; i < expression.Length; ) //取出表达式 { cur = expression[i++]; //取出表达式的每个字符赋给cur top = operatorStack.Peek(); //栈顶元素赋给top此时为"#" if (cur == '(') //将左括号压栈,此时栈顶元素为"(" { operatorStack.Push(cur); } else { if (IsOperator(cur)) //如果是运算符的话 { while (IsOperator(top) && ((IsAssoc(cur) && priorities[cur] <= priorities[top])) || (!IsAssoc(cur) && priorities[cur] < priorities[top])) { result.Enqueue(operatorStack.Pop()); //如果元素为运算符并且优先级小于栈顶元素优先级,出栈 top = operatorStack.Peek(); //继续把栈顶元素赋给top } operatorStack.Push(cur); //把数字压栈 } else if (cur == ')') //将右括号添加到结尾 { && (tempChar = operatorStack.Pop()) != '(') { result.Enqueue(tempChar); } } else { tempNum = "" + cur; j = i; '))) { tempNum += expression[j++]; } i = j; result.Enqueue(tempNum); } } } ) { cur = operatorStack.Pop(); if (cur == '#') continue; ) { top = operatorStack.Peek(); } result.Enqueue(cur); } return result; } static int Calucate(string expression) { try { var rpn = QueueSort(expression); //rpn逆波兰表达式reverse polish notation Stack<int> operandStack = new Stack<int>(); int left, right; object cur; ) { cur = rpn.Dequeue(); //出列 if (cur is char) //如果cur为字符的话 { right = operandStack.Pop(); //右边的数字出栈 left = operandStack.Pop(); //左边的数字出栈 operandStack.Push(Compute(left, right, (char)cur)); //此时调用compute方法 } else { operandStack.Push(int.Parse(cur.ToString())); //是数字就压栈 } } return operandStack.Pop(); } catch { throw new Exception("表达式格式不正确!"); } } } }
代码编写过程:
Form2.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace _Random { public partial class Form2 : Form { public Form2() { InitializeComponent(); } private void Form2_Load(object sender, EventArgs e) { textBox1.Text = Form1.Count.ToString(); textBox2.Text = Form1.right.ToString(); textBox3.Text = (Form1.Count - Form1.right).ToString(); } } }
运行过程:
答题的时候给出取值范围,和预想答题数目,然后点击随机,这时程序就会生成一个式子。
当我在输入答案并回车的时候会对生成的式子进行计算,并与输入的答案进行比较。
当时间用完,或者点击结束运算的时候,会弹出测试结果并提示时间到。
PSP耗时分析:
结对编程总结:
说明:我们一起做了1个增量