软工5--结对2--四则运算生成器
四则运算生成器
发布版,扫描二维码下载
题目
- 我们在刚开始上课的时候介绍过一个小学四则运算自动生成程序的例子,请实现它,要求:
- 能够自动生成四则运算练习题
- 可以定制题目数量
- 用户可以选择运算符
- 用户设置最大数(如十以内、百以内等)
- 用户选择是否有括号、是否有小数
- 用户选择输出方式(如输出到文件、打印机等)
- 最好能提供图形用户界面(根据自己能力选做,以完成上述功能为主)
职位
担任驾驶员。
计划制定
软件需求
- 本软件属于教学辅助类软件。
- 软件计划面向小学生的家长、教师出题使用。致力于为他们提供简洁快速的操作体验,由于教师的工作重心应该在批改与备课上,所以本软件不应该占用他们过多的时间去摸索与设置。
- 用户实际调研暂无。
- 竞争性分析:市场中此类软件数不胜数,所以我们决定在简洁与高效两方面做出特色。
- 最主要的功能定位于定制多种题目类型。
计划与估计
- 计划于1小时内完成生成公式的算法。
- 计划1天内完成界面搭建工作。
- 计划再用一天来进行前端与后台的关联与DEBUG工作。
项目地址
https://github.com/947104238/FourAOBuild
项目结构
1. 主工程界面
2. 启动页
3. 设置数据类实例
public SettingsData(String textnums, String maxnum, Set<String> symbol, boolean parentheses, boolean smallnum, boolean printlocal) {
this.textnums = textnums;
this.maxnum = maxnum;
this.symbol = symbol;
this.parentheses = parentheses;
this.smallnum = smallnum;
this.printlocal = printlocal;
}
Getter&Setter方法在此省略。
4. 设置
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
SettingsData data = new SettingsData();
data.setMaxnum(sp.getString("set_maxnum","10"));
data.setParentheses(sp.getBoolean("set_parentheses",false));
data.setPrintlocal(sp.getBoolean("set_printlocal",false));
data.setSmallnum(sp.getBoolean("set_smallnum",false));
data.setTextnums(sp.getString("set_textnums","10"));
data.setSymbol(sp.getStringSet("set_symbol",null));
Intent intent = new Intent(SettingActivity.this,TestActivity.class);
intent.putExtra("data",data);
数据传输实例。
5. 功能生成接口
public class BuildTest {
private StringBuffer test = null;
// 最大值
private int max;
// 符号范围
private String[] sym ;
// 是否有括号
private boolean hasPt = false;
// 未匹配的左括号数量
private int leftPt = 0;
// 是否有小数
private boolean hasSml = false;
public BuildTest() {
test = new StringBuffer();
test.append("");
}
public void setSymbol(String []sym){
this.sym = sym;
}
//接口 设置最大值
public void setMax(int max) {
this.max = max;
}
//接口 设置是否有括号
public void setHasParenthese(boolean hasPt) {
this.hasPt = hasPt;
}
//接口 设置是否有小数
public void setHasSmallNum(boolean hasSml) {
this.hasSml = hasSml;
}
// 接口 生成公式
public StringBuffer buildTest() {
setOrigin();
Random random = new Random();
int times = 5;
for (int i = 1; i < random.nextInt(times); i++) {
buildPt("left");
buildElement();
buildPt("right");
buildConnect();
buildPt("left");
}
buildElement();
for (int i = 0; i < leftPt; i++) {
test.append(")");
}
test.append("=");
return test;
}
// 生成算式
private void buildElement() {
Random random = new Random();
int a, b, symbol;
double as,bs;
a = random.nextInt(max);
b = random.nextInt(max);
symbol = random.nextInt(sym.length);
if (hasSml) {
DecimalFormat df = new DecimalFormat("0.00");
as = a+random.nextDouble();
bs = b+random.nextDouble();
test.append(df.format(as) + sym[symbol] + df.format(bs) + "");
} else {
test.append(a + sym[symbol] + b + "");
}
}
// 生成连接符
private void buildConnect() {
Random random = new Random();
int symbol;
symbol = random.nextInt(sym.length);
test.append(sym[symbol]);
}
// 生成括号
private void buildPt(String lor) {
String[] ptLeft = { "", "(" };
String[] ptRight = { "", ")" };
Random random = new Random();
// 当前是否是括号
int prePt = 0;
if (hasPt) {
if (lor.equals("left")) {
prePt = random.nextInt(2);
test.append(ptLeft[prePt]);
leftPt += prePt;
} else {
if (leftPt > 0) {
prePt = random.nextInt(2);
test.append(ptRight[prePt]);
leftPt -= prePt;
}
}
}
}
// 得到公式
private void setOrigin() {
test.delete(0, test.length());
leftPt = 0;
}
}
子方法迭代生成法。
6. 试题列表类
public class Tests {
private StringBuffer test;
public Tests() {
}
public Tests(StringBuffer test) {
this.test = test;
}
public StringBuffer getTest() {
return test;
}
public void setTest(StringBuffer test) {
this.test = test;
}
}
7. 试题列表适配器
其中对getView方法进行优化,在大量生成列表时保证性能。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null){
convertView = LayoutInflater.from(context).inflate(R.layout.list_test,parent,false);
holder = new ViewHolder();
holder.tv_item = convertView.findViewById(R.id.tv_item);
convertView.setTag(holder);
}else {
holder = (ViewHolder)convertView.getTag();
}
holder.tv_item.setText(mData.get(position).getTest());
return convertView;
}
static class ViewHolder{
TextView tv_item;
}
8. 试题列表生成
mData = new LinkedList<>();
BuildTest buildTest = new BuildTest();
buildTest.setHasParenthese(parentheses);
buildTest.setHasSmallNum(smallnum);
buildTest.setMax(max);
buildTest.setSymbol(preSymbol);
num = 50;
for (int i=1;i<=num;i++) {
s = new StringBuffer();
s.append(i+"、 ");
s.append(buildTest.buildTest());
mData.add(new Tests(s));
}
testsAdapter = new TestsAdapter(mData,context);
lv_test.setAdapter(testsAdapter);
列表的生成与适配器的使用。
9. 设置界面
本次设置界面尝试使用了Android提供的Preferences方法。用简单的布局实现了逻辑严谨的偏好设置选项。
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/app_name">
<PreferenceCategory
android:title="@string/settings" >
<EditTextPreference
android:title="@string/text_nums"
android:summary="@string/text_numssummary"
android:key="set_testnums"
android:defaultValue="20" />
</PreferenceCategory>
<PreferenceCategory
android:title="@string/set_calcu">
<MultiSelectListPreference
android:key="set_symbol"
android:title="@string/set_symbol"
android:summary="@string/set_symbol_summary"
android:entries="@array/arr_symbol"
android:entryValues="@array/value_symbol"/>
<ListPreference
android:key="set_maxnum"
android:entries="@array/arr_max"
android:entryValues="@array/value_max"
android:title="设置最大数"
android:summary="设置运算题的数值范围"/>
<SwitchPreference
android:key="set_parentheses"
android:title="是否有括号"
android:summaryOn="包含括号"
android:summaryOff="不包含括号"
android:persistent="true"
android:defaultValue="false"/>
<SwitchPreference
android:key="set_smallnum"
android:title="是否有小数"
android:summary="无小数"
android:summaryOn="包含小数"
android:summaryOff="不包含小数"
android:persistent="true"
android:defaultValue="false"/>
</PreferenceCategory>
<PreferenceCategory
android:title="功能设置">
<SwitchPreference
android:key="set_printlocal"
android:title="输出到本地文件"
android:summaryOff="不保存到本地"
android:summaryOn="保存到本地"
android:defaultValue="false"/>
<ListPreference
android:key="set_printer"
android:title="连接到打印机"
android:summary="选择打印机类型"
android:entries="@array/arr_printer"
android:entryValues="@array/value_printer"/>
</PreferenceCategory>
<PreferenceCategory
android:title="执行功能">
<Preference
android:key="build"
android:title="生成练习题"/>
<Preference
android:key="saveToLocal"
android:title="保存到本地"/>
<Preference
android:key="printer"
android:title="打印"/>
</PreferenceCategory>
</PreferenceScreen>
程序展示
1. 主设置界面
2. 设置题目数量
3. 设置运算符
4. 设置最大值
5. 设置打印机
功能测试
Test 1
四则混合运算
Test 2
单一运算符(乘法)
Test 3
双运算符(加&除法)
Test 4
包含括号
Test 5
包含小数
Test 6
包含小数及括号
对领航员的评价
在此次的结对编程中,我做为驾驶员(码农),离不开领航员在大方向上的指引。领航员方式一座灯塔,让我在沉迷于某项无关主要代码的工作时能突然惊醒。同时我体会到了两人结对编程时的思维碰撞,当一个方法、一段代码产生错误时,两人既可以分身工作,一人去审查代码,另一人去查阅参考资料;同时又能合二为一,一起讨论分析出现问题的原因,调试代码,修改BUG。老话众人拾柴火焰高或许说的就是这个道理。在结对编程中,两个人的互相讨论又能保证避免双方的分神,大大提高了工作效率。
同时互相的激励作用也是很重要的,当重复编码或者遇到很隐蔽或者很明显但毫无解决办法的问题时,程序员容易出现焦躁或者厌烦情绪,这时候能有一个引导员是由为重要的。
当然,我这次对这么一个小程序并没有出现负面情绪(滑稽)。
总结
这次的项目说大不大,说小也不小。说不大是因为主要功能生成多项式的代码很少,说不小是因为大多数工作都花在了界面设计布局上,同时由于正赶上了AndroidStudio大更新,很多Github上老前辈的
开源设计库都用不了了,致使我临时去学习了Android提供的Preferences设置页,走了不少弯路,也遇到并解决了不少困难。
在代码写到一半的时候突然发现PreferencesActivity被AS标为了过时的方法,此时也只能顶着头皮继续用了,因为要改的话重构代码工作量不小。之后有时间的话我可能会填补一下这个坑,或者在
开新项目时直接启用新方法。