一.实现目标
二.软件假设的一些条件
三.设计思路
总体流程是用户先给定需求,之后程序判断需求的合法性,对于合法需求,先生成操作数,再生成运算符,判重之后合并为一个字符串输出。先对于每一项需求分类进行讨论:
四.界面设计
个人喜欢简单明了的风格,故界面仅仅只两个个五毛钱特效的窗口。初始界面具体如下图:

算式选择界面:

当然,上图是VS中的编辑界面,真正的界面在没有选定小数时其右边两个空间是visable=false的,分数同理。

五.结果测试
对于每种不同情况生成30个不同的算式,这里只截取前十个。
1.整数[-5,9]。

2.假分数[1,6]+乘除

3.真分数[-0.6,0.5]+括号

4.小数[-23,26.4]+小数点后两位+乘除+括号

六.实现代码
1.用户选择界面的代码,主要包含判断需求合法性和各种需求的标记处理等。
public double MIN, MAX;
public bool mulandde, bracket, fraction,decimals;
public int frac,dec;
public Form2()
{
InitializeComponent();
groupBox1.Visible = false;
label3.Visible = false;
textBox3.Visible = false;
mulandde = bracket = fraction = decimals = false;
frac = 0;
dec = -1;
}
private void checkBox4_CheckedChanged(object sender, EventArgs e)
{
if (checkBox4.Checked)
{
groupBox1.Visible = true;
fraction = true;
}
else
{
groupBox1.Visible = false;
fraction = false;
}
}
private void checkBox5_CheckedChanged(object sender, EventArgs e)
{
if (checkBox5.Checked)
{
label3.Visible = true;
textBox3.Visible = true;
decimals = true;
}
else {
label3.Visible = false;
textBox3.Visible = false ;
decimals = false;
}
}
private void button1_Click(object sender, EventArgs e)
{
//MIN MAX
string s = textBox1.Text;
if (s.Length == 0)
{
MessageBox.Show("填写有误,请重新填写", null, MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
MIN = Double.Parse(s);
s = textBox2.Text;
if (s.Length == 0)
{
MessageBox.Show("填写有误,请重新填写", null, MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
MAX = Double.Parse(s);
//fraction
if (fraction && frac == 0)
{
MessageBox.Show("填写有误,请重新填写", null, MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
//decimals
if (decimals) {
s = textBox3.Text;
if (s.Length == 0)
{
MessageBox.Show("填写有误,请重新填写", null, MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
for (int i = 0; i < s.Length; i++) if (s[i] < ‘0‘ || s[i] > ‘9‘){
MessageBox.Show("填写有误,请重新填写", null, MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
dec = int.Parse(s);
}
this.Close();
}
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
if(radioButton1.Checked) frac = 1;
}
private void radioButton2_CheckedChanged(object sender, EventArgs e)
{
if (radioButton2.Checked) frac = 2;
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
mulandde = !mulandde;
}
private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
bracket = !bracket;
}
2.主界面的代码,主要是操作数和运算符的生成以及打印。
const int Maxn=30;
Form2 form;
string[] equation;
double[][] num;
string[][] cnum;
char[][] op;
public Form1()
{
InitializeComponent();
equation = new string[Maxn];
num = new double[Maxn][];
for (int i = 0; i < Maxn; i++)
num[i] = new double[3];
op = new char[Maxn][];
for (int i = 0; i < Maxn; i++)
op[i] = new char[2];
cnum=new string[Maxn][];
for (int i = 0; i < Maxn; i++)
cnum[i] = new string[3];
}
private void _sort(int ith)
{
if (num[ith][0] < num[ith][1]) {
double t = num[ith][0];
num[ith][0] = num[ith][1]; num[ith][1] = t;
}
if (num[ith][2] != 0 && num[ith][1] < num[ith][2]) {
double t = num[ith][1];
num[ith][1] = num[ith][2]; num[ith][2] = t;
}
if (num[ith][0] < num[ith][1])
{
double t = num[ith][0];
num[ith][0] = num[ith][1]; num[ith][1] = t;
}
}
//生成题目
private void button1_Click(object sender, EventArgs e)
{
while (listBox1.Items.Count != 0)
listBox1.Items.Remove(listBox1.Items[0]);
//模式窗体
Random R=new Random();
form = new Form2();
form.ShowDialog();
int top = 2;
if (form.mulandde) top = 4;
for (int i = 0; i < Maxn; i++) {
//构造不同的操作数
while (true)
{
build_equ(i);
_sort(i);
bool flag=true;
for (int j = 0; j < i; j++) if (num[i][0] == num[j][0] && num[i][1] == num[j][1] && num[i][2] == num[j][2]){
flag = false; break;
}
if (flag) break;
}
//构造运算符
int tt = R.Next(top);
switch (tt) {
case 0: op[i][0] = ‘+‘; break;
case 1: op[i][0] = ‘-‘; break;
case 2: op[i][0] = ‘*‘; break;
case 3: op[i][0] = ‘/‘; break;
}
if (num[i][2] != 0)
{
tt = R.Next(top);
switch (tt)
{
case 0: op[i][1] = ‘+‘; break;
case 1: op[i][1] = ‘-‘; break;
case 2: op[i][1] = ‘*‘; break;
case 3: op[i][1] = ‘/‘; break;
}
}
else {
op[i][1] = ‘ ‘;
}
if (form.bracket&&num[i][2]!=0&&R.Next(3)==1)
{
char a = op[i][0], b = op[i][1];
if (((a == ‘+‘ || a == ‘-‘) && (b == ‘+‘ || b == ‘-‘)) || ((a == ‘*‘ || a == ‘/‘) && (b == ‘*‘ || b == ‘/‘)))
{
equation[i] = "" + cnum[i][0] + " " + op[i][0] + " ( " + cnum[i][1];
equation[i] += " " + op[i][1] + " " + cnum[i][2];
equation[i] += " ) = ";
}
else {
if (a == ‘+‘ || a == ‘-‘)
{
equation[i] = "( " + cnum[i][0] + " " + op[i][0] + " " + cnum[i][1];
equation[i] += " ) " + op[i][1] + " " + cnum[i][2];
equation[i] += " = ";
}
else {
equation[i] = "" + cnum[i][0] + " " + op[i][0] + " ( " + cnum[i][1];
equation[i] += " " + op[i][1] + " " + cnum[i][2];
equation[i] += " ) = ";
}
}
}
else
{
equation[i] = "" + cnum[i][0] + " " + op[i][0] + " " + cnum[i][1];
if (cnum[i][2] != "")
{
equation[i] += " " + op[i][1] + " " + cnum[i][2];
}
equation[i] += " = ";
}
}
}
private void button2_Click(object sender, EventArgs e)
{
for (int i = 0; i < Maxn; i++)
listBox1.Items.Add(equation[i]);
}
//构造第pos个算式操作数的函数
private void build_equ(int pos)
{
//test
Random R = new Random();
double l=form.MIN,r=form.MAX;
if (form.fraction) {
if (form.frac == 1)
{
//真分数
int fz1, fz2, fm1, fm2;
double t;
fm1 = R.Next(29) + 2;
fm2 = R.Next(29) + 2;
t = R.NextDouble()*(r - l) + l;
num[pos][0] = t;
fz1 = (int)(fm1 * t);
t = R.NextDouble() * (r - l) + l;
fz2 = (int)(fm2 * t);
int _gcd = gcd(fz1, fm1);
fz1 /= _gcd;
fm1 /= _gcd;
_gcd = gcd(fz2, fm2);
fz2 /= _gcd;
fm2 /= _gcd;
num[pos][1] = t;
if(fm1<0)
cnum[pos][0] = "-" + fz1 + ‘/‘ + (-fm1);
else
cnum[pos][0] = "" + fz1 + ‘/‘ + fm1;
if(fm2<0)
cnum[pos][1] = "" + fz2 + ‘/‘ + (-fm2);
else
cnum[pos][1] = "" + fz2 + ‘/‘ + fm2;
if (R.Next(2) == 1)
{
fm1 = R.Next(19) + 2;
t = R.NextDouble() * (r - l) + l;
num[pos][2] = t;
fz1 = (int)(fm1 * t);
_gcd = gcd(fz1, fm1);
fz1 /= _gcd;
fm1 /= _gcd;
cnum[pos][2] = "" + fz1 + ‘/‘ + fm1;
}
else
{
num[pos][2] = 0;
cnum[pos][2] = "";
}
}
else {
//假分数
int fz1, fz2, fm1, fm2;
double t;
fm1 = R.Next(19) + 2;
fm2 = R.Next(19) + 2;
t = R.NextDouble() * (r - l) + l;
num[pos][0] = t;
fz1 = (int)(fm1 * t);
t = R.NextDouble() * (r - l) + l;
fz2 = (int)(fm2 * t);
num[pos][1] = t;
int _gcd = gcd(fz1, fm1);
fz1 /= _gcd;
fm1 /= _gcd;
_gcd = gcd(fz2, fm2);
fz2 /= _gcd;
fm2 /= _gcd;
if (fm1 < 0)
cnum[pos][0] = "-" + fz1 + ‘/‘ + (-fm1);
else
cnum[pos][0] = "" + fz1 + ‘/‘ + fm1;
if (fm2 < 0)
cnum[pos][1] = "" + fz2 + ‘/‘ + (-fm2);
else
cnum[pos][1] = "" + fz2 + ‘/‘ + fm2;
if (R.Next(2) == 1)
{
fm1 = R.Next(19) + 2;
t = R.NextDouble() * (r - l) + l;
num[pos][2] = t;
fz1 = (int)(fm1 * t);
_gcd = gcd(fz1, fm1);
fz1 /= _gcd;
fm1 /= _gcd;
cnum[pos][2] = "" + fz1 + ‘/‘ + fm1;
}
else
{
num[pos][2] = 0;
cnum[pos][2] = "";
}
}
}
else if (form.decimals)
{
//小数
double a, b;
int d = 1;
for (int i = 1; i <= form.dec; i++) d *= 10;
a = R.NextDouble() * (r - l) + l;
b = R.NextDouble() * (r - l) + l;
num[pos][0] = a;
num[pos][1] = b;
a = (int)(a * d);
b = (int)(b * d);
cnum[pos][0] = "" + (a/d);
cnum[pos][1] = "" + (b/d);
if (R.Next(2) == 1)
{
a = R.NextDouble() * (r - l) + l;
num[pos][2] = a;
a = (int)(a * d);
cnum[pos][2] = "" + (a/d);
}
else
{
num[pos][2] = 0;
cnum[pos][2] = "";
}
}
else {
//整数
int a, b;
a = (int)(R.Next((int)(r - l)) + l);
b = (int)(R.Next((int)(r - l)) + l);
num[pos][0] = a;
num[pos][1] = b;
cnum[pos][0] = "" + a;
cnum[pos][1] = "" + b;
if (R.Next(2) == 1)
{
a = (int)(R.Next((int)(r - l)) + l); ;
num[pos][2] = a;
cnum[pos][2] = "" + a;
}
else {
num[pos][2] = 0;
cnum[pos][2] = "";
}
}
}
private int gcd(int a, int b)
{
//求a和b最大公约数
int r = 1;
while (r!=0) {
r = a % b;
a = b; b = r;
}
return a;
}
七.项目后的一些感想
之前在学校的学习都是写一些具体的题目,其目的性和范围性都非常的强,且问题单一,而这个项目虽然仅仅是一个四则运算,但当许多小而简单的问题联系在一起的时候就会变得复杂,对问题的分析也会变得困难,其中各种制约关系在一开始对问题进行抽象时给自己带来了不小的麻烦,这些麻烦并非想不到办法,而是不知道该怎么将某些办法结合起来。也正因此,对于软件工程这一科目有了更深一层的了解,目前的认知是软件工程的核心不是解决某个具体的技术性问题,而是合理协调用户所提需求,建立便于分析维护的问题模型。有不对指出还请老师指正~~
原文:http://www.cnblogs.com/jin-test/p/5272544.html