对于答题判断程序-4以及家居强电电路模拟程序1-2的总结性Blog
一、前言
相关知识点:
1、答题判断程序-4在前面答题判断程序-3的基础上增加了更多的输入格式判断以及对于边界条件情况的处理,对于面对对象编程的概念进一步的深化了。
2、家居强电电路模拟程序-1从此次的大作业开始使用了抽象类的继承,以及对于电路中相关数据的计算进行了模拟,模拟电路中的电压、电流和电阻等物理量,并进行相应的计算,对比于之前的答题判断程序要求更加的严格了。此次只使用了串联电路相比较家居强电电路模拟程序-2简单许多。
3、家居强电电路模拟程序-2在上一次大作业的基础上对增加了新的类以及对与输入判断有了更加严格的要求,且在第一次的基础上加入了并联电路和电阻使得整个程序的编写相较于第一次的程序有了更多的困难。
题量:
三次题目集的题目量分别为3+3+1,其中答题判断程序-4题目集中包含了三道题。家居强电电路模拟程序-1题目集中包含了3道题,但是其中有一道题似乎出现了问题因此并没有写,最后家居强电电路模拟程序-2题目集只包含了一道题但是编写起来却十分的困难。
难度:
三次题目集的难度其中家居强电电路模拟程序-1是相比较而言最简单的。因为是一个新的开始所以对于其中的要求并没有过于细致,而另外两次的题目集则是困难了许多,其中、答题判断程序-4由于其是在前面的三次题目集的基础上进行迭代的所以会困难许多,而家居强电电路模拟程序-2在家居强电电路模拟程序-1的基础上加入了并联电路以及电阻,而且输入的形式也的多种多样因此在编写时也十分的困难。
二、设计与分析
1、答题判断程序-4
在答题判断程序-3的基础上增加了选择题题目的输入
1、输入选择题题目信息
题目信息为独行输入,一行为一道题,多道题可分多行输入。
格式:"#Z:"+题目编号+" "+"#Q:"+题目内容+" "#A:"+标准答案
格式基本的约束与一般的题目输入信息一致。
新增约束:标准答案中如果包含多个正确答案(多选题),正确答案之间用英文空格分隔。
多选题输出:
输出格式与一般答卷题目的输出一致,判断结果除了true、false,增加一项”partially correct”表示部分正确。
多选题给分方式:
答案包含所有正确答案且不含错误答案给满分;包含一个错误答案或完全没有答案给0分;包含部分正确答案且不含错误答案给一半分,如果一半分值为小数,按截尾规则只保留整数部分。
2、输入填空题题目信息
题目信息为独行输入,一行为一道题,多道题可分多行输入。
格式:"#K:"+题目编号+" "+"#Q:"+题目内容+" "#A:"+标准答案
格式基本的约束与一般的题目输入信息一致。
例如:#K:2 #Q:古琴在古代被称为: #A:瑶琴或七弦琴
填空题输出:
输出格式与一般答卷题目的输出一致,判断结果除了true、false,增加一项”partially correct”表示部分正确。
填空题给分方式:
答案与标准答案内容完全匹配给满分,包含一个错误字符或完全没有答案给0分,包含部分正确答案且不含错误字符给一半分,如果一半分值为小数,按截尾规则只保留整数部分。
根据题目的要求将该程序设计为五个类:1、抽象的问题父类 2、普通问题子类 3、多选题子类 4、答卷类 5、试卷类 在答题判断程序-3的基础上将问题类变为了抽象类,新增了普通问题类和多选题类。
以上三个类以及调用他们的部分Main函数。
for (AnswerPaperSheet sheet : answerSheets) {
TestPaper paper = testPapers.get(sheet.testPaperNumber);
if (paper == null) {
System.out.println("The test paper number does not exist");
continue;
}
String studentName = students.get(sheet.studentId);
List<Integer> scores = new ArrayList<>();
int totalScore = 0;
for (int i = 0; i < paper.questions.size(); i++) {
Question question = paper.questions.get(i);
String givenAnswer = i < sheet.answers.size() ? sheet.answers.get(i) : "";
String result = question.getScoreResult(givenAnswer);
System.out.println(question.content + "~" + givenAnswer + "~" + result);
int score = 0;
if ("true".equals(result)) {
score = paper.questionScores.get(question.number);
} else if ("partially correct".equals(result)) {
score = paper.questionScores.get(question.number) / 2;
}
scores.add(score);
totalScore += score;
}
System.out.println(sheet.studentId + " " + studentName + ": " +
String.join(" ", scores.stream().map(String::valueOf).toArray(String[]::new)) + "~" + totalScore);
其中AnsewerSheet类中包含了最后答卷的输出,再Main中调用answerSheet.printResult();来将结果显示出来。
SourceMonitor分析如下:
2、 家居强电电路模拟程序-1
1、控制设备模拟
本题模拟的控制设备包括:开关、分档调速器、连续调速器。
开关:包括0和1两种状态。
开关有两个引脚,任意一个引脚都可以是输入引脚,而另一个则是输出引脚。开关状态为0时,无论输入电位是多少,输出引脚电位为0。当开关状态为1时,输出引脚电位等于输入电位。
分档调速器
按档位调整,常见的有3档、4档、5档调速器,档位值从0档-2(3/4)档变化。本次迭代模拟4档调速器,每个档位的输出电位分别为0、0.3、0.6、0.9倍的输入电压。
连续调速器
没有固定档位,按位置比例得到档位参数,数值范围在[0.00-1.00]之间,含两位小数。输出电位为档位参数乘以输入电压。
所有调速器都有两个引脚,一个固定的输入(引脚编号为1)、一个输出引脚(引脚编号为2)。当输入电位为0时,输出引脚输出的电位固定为0,不受各类开关调节的影响。
所有控制设备的初始状态/档位为0。
2、受控设备模拟
本题模拟的受控设备包括:灯、风扇。两种设备都有两根引脚,通过两根引脚电压的电压差驱动设备工作。
灯有两种工作状态:亮、灭。在亮的状态下,有的灯会因引脚电位差的不同亮度会有区别。
风扇在接电后有两种工作状态:停止、转动。风扇的转速会因引脚的电位差的不同而有区别。
本次迭代模拟两种灯具。
白炽灯:
亮度在0~200lux(流明)之间。
电位差为0-9V时亮度为0,其他电位差按比例,电位差10V对应50ux,220V对应200lux,其他电位差与对应亮度值成正比。白炽灯超过220V。
日光灯:
亮度为180lux。
只有两种状态,电位差为0时,亮度为0,电位差不为0,亮度为180。
本次迭代模拟一种吊扇。
工作电压区间为80V-150V,对应转速区间为80-360转/分钟。80V对应转速为80转/分钟,150V对应转速为360转/分钟,超过150V转速为360转/分钟(本次迭代暂不考虑电压超标的异常情况)。其他电压值与转速成正比,输入输出电位差小于80V时转速为0。
输入信息:
1、设备信息
分别用设备标识符K、F、L、B、R、D分别表示开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇。
设备标识用标识符+编号表示,如K1、F3、L2等。
引脚格式:设备标识-引脚编号,例如:K1-1标识编号为1的开关的输入引脚。
三种控制开关的输入引脚编号为1,输出引脚编号为2。
受控设备的两个引脚编号分别为1、2。
约束条件:
不同设备的编号可以相同。
同种设备的编号可以不连续。
设备信息不单独输入,包含在连接信息中。
2、连接信息
一条连接信息占一行,用[]表示一组连接在一起的设备引脚,引脚与引脚之间用英文空格" "分隔。
格式:"["+引脚号+" "+...+" "+引脚号+"]"
例如:[K1-1 K3-2]表示K1的1引脚,K3的2引脚连接在一起。
约束条件:
本次迭代不考虑两个输出引脚短接的情况
不考虑调速器串联到其他调速器的情况。
不考虑各类控制设备的并联接入或反馈接入。例如,
K1的输出接到L2的输入,L2的输出再接其他设备属于串联接线。
K1的输出接到L2的输出,同时K1的输入接到L2的输入,这种情况属于并联。
K1的输出接到L2的输入,K1的输入接到L2的输出,属于反馈接线。
3、控制设备调节信息
开关调节信息格式:
#+设备标识K+设备编号,例如:#K2,代表切换K2开关的状态。
分档调速器的调节信息格式:
#+设备标识F+设备编号+"+" 代表加一档,例如:#F3+,代表F3输出加一档。
#+设备标识F+设备编号+"-" 代表减一档,例如:#F1-,代表F1输出减一档。
连续调速器的调节信息格式:
#+设备标识L+设备编号+":" +数值 代表将连续调速器的档位设置到对应数值,例如:#L3:0.6,代表L3输出档位参数0.6。
4、电源接地标识:VCC,电压220V,GND,电压0V。没有接线的引脚默认接地,电压为0V。
输入信息以end为结束标志,忽略end之后的输入信息。
输出信息:
按开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇的顺序依次输出所有设备的状态或参数。每个设备一行。同类设备按编号顺序从小到大输出。
输出格式:@设备标识+设备编号+":" +设备参数值(控制开关的档位或状态、灯的亮度、风扇的转速,只输出值,不输出单位)
连续调速器的档位信息保留两位小数,即使小数为0,依然显示两位小数.00。
开关状态为0(打开)时显示turned on,状态为1(合上)时显示closed
如:
@K1:turned on
@B1:190
@L1:0.60
本题不考虑输入电压或电压差超过220V的情况。
本题只考虑串联的形式,所以所有测试用例的所有连接信息都只包含两个引脚
本题电路中除了开关可能出现多个,其他电路设备均只出现一次。
电源VCC一定是第一个连接的第一项,接地GND一定是最后一个连接的后一项。
家居电路模拟系列所有题目的默认规则:
1、当计算电压值等数值的过程中,最终结果出现小数时,用截尾规则去掉小数部分,只保留整数部分。为避免精度的误差,所有有可能出现小数的数值用double类型保存并计算,不要作下转型数据类型转换,例如电压、转速、亮度等,只有在最后输出时再把计算结果按截尾规则,舍弃尾数,保留整数输出。
2、所有连接信息按电路从电源到接地的顺序依次输入,不会出现错位的情况。
3、连接信息如果只包含两个引脚,靠电源端的引脚在前,靠接地端的在后。
4、对于调速器,其输入端只会直连VCC,不会接其他设备。整个电路中最多只有一个调速器,且连接在电源上。
根据上述的要求进行分析将该程序设计为1、抽象设备父类 2、开关子类 3、分档调速器子类 4、连续调速器子类 5、白炽灯子类 6、日光灯子类 7、风扇子类共7个类
类图如下:
以及除了这七个类之外的Main之中的部分代码
根据对应的字母在模拟电路中加入相对应的类
String Line = scanner.nextLine();
while(!Line.equals("end")){
if(Line.contains("[")){
String result = Line.replaceAll("^\\[|\\]$", "");
String[] split = result.split(" ");
if(split[0].equals("VCC"))
{
String[] split1 = split[1].split("-");
StringBuilder result1 = new StringBuilder();
for (String s : split1) {
result1.append(s);
}
char[] charArray = result1.toString().toCharArray();
char ch = charArray[1]; // 获取 charArray 中的第二个字符
String str = Character.toString(ch); // 将字符转换为字符串
if(charArray[0] == 'K')
{
Switch switch1 = new Switch(str);
switches.add(switch1);
}
else if(charArray[0] == 'F')
{
SpeedControl speedControls1 = new SpeedControl(str);
speedControls.add(speedControls1);
}
else if(charArray[0] == 'L')
{
ContinuousSpeedControl continuousSpeedControl1 = new ContinuousSpeedControl(str);
continuousSpeedControls.add(continuousSpeedControl1);
}
else if(charArray[0] == 'B')
{
Incandescentlamp incandescentlamp1 = new Incandescentlamp(str);
incandescentlamps.add(incandescentlamp1);
}
else if(charArray[0] == 'R')
{
DayLight dayLight1 = new DayLight(str);
dayLights.add(dayLight1);
}
else if(charArray[0] == 'D')
{
Fan fans1 = new Fan(str);
fans.add(fans1);
}
Deviceids.add(str);
char ch1 = charArray[0]; // 获取 charArray 中的第二个字符
String str1 = Character.toString(ch1); // 将字符转换为字符串
Devicenames.add(str1);
}
else if(split[1].equals("GND")) {
}
else
{
String[] split1 = split[1].split("-");
StringBuilder result1 = new StringBuilder();
for (String s : split1) {
result1.append(s);
}
char[] charArray = result1.toString().toCharArray();
char ch = charArray[1]; // 获取 charArray 中的第二个字符
String str = Character.toString(ch); // 将字符转换为字符串
if(charArray[0] == 'K')
{
Switch switch1 = new Switch(str);
switches.add(switch1);
}
else if(charArray[0] == 'F')
{
SpeedControl speedControls1 = new SpeedControl(str);
speedControls.add(speedControls1);
}
else if(charArray[0] == 'L')
{
ContinuousSpeedControl continuousSpeedControl1 = new ContinuousSpeedControl(str);
continuousSpeedControls.add(continuousSpeedControl1);
}
else if(charArray[0] == 'B')
{
Incandescentlamp incandescentlamp1 = new Incandescentlamp(str);
incandescentlamps.add(incandescentlamp1);
}
else if(charArray[0] == 'R')
{
DayLight dayLight1 = new DayLight(str);
dayLights.add(dayLight1);
}
else if(charArray[0] == 'D')
{
Fan fans1 = new Fan(str);
fans.add(fans1);
}
Deviceids.add(str);
char ch1 = charArray[0]; // 获取 charArray 中的第二个字符
String str1 = Character.toString(ch1); // 将字符转换为字符串
Devicenames.add(str1);
}
}
SourceMonitor分析如下:
3、家居强电电路模拟程序-2
在家居强电电路模拟程序-1的基础上加入了电阻且所有开关的电阻为 0,白炽灯的电阻为 10,日光灯的电阻为 5,吊扇的电阻为 20,落地扇的电阻为 20。
迭代模拟一种落地扇。
工作电压区间为 [80V,150V],对应转速区间为 80-360 转/分钟。电压在[80,100)V 区间对应转速为 80 转/分 钟,[100-120)V 区间对应转速为 160 转/分钟,[120-140)V 区间对应转速为 260 转/分钟,超过 140V 转速 为 360 转/分钟(本次迭代暂不考虑电压超标的异常情况)
1)输入设备信息
分别用设备标识符K、F、L、B、R、D、A分别表示开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇、落地扇。
设备标识用标识符+编号表示,如K1、F3、L2等。
引脚格式:设备标识-引脚编号,例如:K1-1标识编号为1的开关的输入引脚。
三种控制开关的输入引脚编号为1,输出引脚编号为2。
受控设备的两个引脚编号分别为1、2。
约束条件:
不同设备的编号可以相同。
同种设备的编号可以不连续。
设备信息不单独输入,包含在连接信息中。
2)输入连接信息
一条连接信息占一行,用[]表示一组连接在一起的设备引脚,引脚与引脚之间用英文空格" "分隔。
格式:"["+引脚号+" "+...+" "+引脚号+"]"
例如:[K1-1 K3-2表示K1的1引脚,K3的2引脚连接在一起。
约束条件:
不考虑调速器串联到其他调速器的情况。
考虑各类设备的并联接入。例如,K1 的输出接到 L2 的输入,L2 的输出再接其他设备属于串联接线。K1 的输出接到 L2 的输出,同时 K1 的输入接到 L2 的输入,这种情况属于并联。
本次迭代的连接信息不单独输入,包含在线路信息中。
3)输入控制设备调节信息
开关调节信息格式:
#+设备标识K+设备编号,例如:#K2,代表切换K2开关的状态。
分档调速器的调节信息格式:
#+设备标识F+设备编号+"+" 代表加一档,例如:#F3+,代表F3输出加一档。
#+设备标识F+设备编号+"-" 代表减一档,例如:#F1-,代表F1输出减一档。
连续调速器的调节信息格式:
#+设备标识L+设备编号+":" +数值 代表将连续调速器的档位设置到对应数值,例如:#L3:0.6,代表L3输出档位参数0.6。
4)电源接地标识:
VCC,电压220V,GND,电压0V。没有接线的引脚默认接地,电压为0V。
5)输入串联电路信息
一条串联电路占一行,串联电路由按从靠电源端到接地端顺序依次输入的 n 个连接 信息组成,连接信息之间用英文空格" "分隔。
串联电路信息格式:
"#T"+电路编号+":"+连接信息+" "+连接信息+...+" "+连接信息
例如:#T1:[IN K1-1] [K1-2 D2-1] [D2-2 OUT] 一个串联电路的第一个引脚是 IN,代表起始端,靠电源。最后一个引脚是 OUT,代表结尾端, 靠接地。
约束条件:
不同的串联电路信息编号不同。
输入的最后一条电路信息必定是总电路信息,总电路信息的起始引脚是 VCC,结束引脚是 GND。
连接信息中的引脚可能是一条串联或并联电路的 IN 或者 OUT。例如:
#T1:[IN K1-1] [K1-2 T2-IN] [T2-OUT OUT]
#T1:[IN K1-1] [K1-2 T2-IN] [T2-OUT M2-IN] [M2-OUT OUT]
6)输入并联电路信息
一条并联电路占一行,并联电路由其包含的几条串联电路组成,串联电路标识之间用英文空格" "分隔。
格式:
"#M"+电路编号+":"+”[”+串联电路信息+" "+....+" "+串联电路信息+”]”
例如:#M1:[T1 T2 T3]
该例声明了一个并联电路,由 T1、T2、T3 三条串联电路并联而成,三条串联电路的 IN 短 接在一起构成 M1 的 IN,三条串联电路的 OUT 短接在一起构成 M1 的 OUT。
约束条件:
本次迭代不考虑并联电路中包含并联电路的情况,也不考虑多个并联电路串联的情况。
本题不考虑输入电压或电压差超过220V的情况。
输入信息以end为结束标志,忽略end之后的输入信息。
本题中的并联信息所包含的串联电路的信息都在并联信息之前输入,不考虑乱序输入的情况。
电路中的短路如果不会在电路中产生无穷大的电流烧坏电路,都是合理情况,在本题测试点的考虑范围之内。
本题不考虑一条串联电路中包含其他串联电路的情况。例如:
#T3:[VCC K1-1] [K1-2 T2-IN] [T2-OUT K2-1] [K2-2 T1-IN] [T1-OUT GND]
本例中T1\T2两条串联电路实际是T3的一个部分,本题不考虑这种类型的输入,而是当将T1\T2的所有连接信息直接包含在T3中定义。
下次迭代中需要考虑这种类型的输入。
以上为在家居强电电路模拟程序-1的基础上加入了的相关要求
以下为更改后的类图:
在之前的类图的基础之上增加了电路父类以及串联和并联子类
以下是主程序的简化版
public class Simulator {
private Map<String, ControlDevice> controlDevices;
private Map<String, ControlledDevice> controlledDevices;
private List<Circuit> circuits;
public Simulator() {
controlDevices = new HashMap<>();
controlledDevices = new HashMap<>();
circuits = new ArrayList<>();
}
// 模拟输入的设备和连接
public void parseInput(String[] inputLines) {
for (String line : inputLines) {
if (line.startsWith("#T")) {
circuits.add(new SeriesCircuit(line)); // 根据线路添加串联电路
} else if (line.startsWith("#M")) {
circuits.add(new ParallelCircuit(line)); // 添加并联电路
} else if (line.startsWith("#K")) {
controlDevices.put(line, new Switch(line)); // 添加开关
} else if (line.startsWith("#F")) {
controlDevices.put(line, new FanSwitch(line)); // 添加分档调速器
} else if (line.startsWith("#L")) {
controlDevices.put(line, new ContinuousFanSwitch(line)); // 添加连续调速器
} else if (line.startsWith("#B") || line.startsWith("#D")) {
controlledDevices.put(line, new IncandescentLight(line)); // 白炽灯
}
}
}
// 模拟电路
public void simulate() {
for (Circuit circuit : circuits) {
circuit.simulate(); // 模拟每个电路
}
}
Main函数的主体与答题判断程序-2的大致相同,但是新增了更多的报错以及输出。
SourceMonitor分析如下:
三、踩坑心得
答题判题程序4
主要踩的坑就是填空题的正则表达式有点不一样,在获取填空题信息时我们不能随便去掉空格,这会影响最终的判题
家居强电电路模拟程序1
正则表达式很关键,读取信息出问题的话后续处理很麻烦,也很难处理,然后再输出时要注意顺序不然这次题目中的某个测试点无法通过。
家居强电电路模拟程序2
并联电路的短路情况没有考虑到,电阻计算的方法没选好。
四、改进建议
在代码中,我的设备类型 (K
, F
, L
, B
, R
, D
) 和它们的标识符(identifier
)直接通过硬编码的字符进行操作。为了增强代码的可扩展性,可以通过使用枚举类来表示设备类型。对于电压的输入和输出的管理,在之后可以考虑创建一个电路管理类 CircuitManager
,将设备与电路的状态统一管理。由于写的过于匆忙所以我的main方法中的代码过于冗余,在之后可以使用枚举类代替硬编码的设备类型。将重复的代码提取成通用的逻辑,如 updateOutput()
和 toString()
。提供清晰的设备创建逻辑,避免代码重复。将设备管理、状态更新和输出打印等功能分离到不同的类中,遵循单一责任原则(SRP)。增强错误处理,确保系统健壮性。
五、总结
这三次Java作业的分为两个部分其中答题判断程序-4为上一次大作业留下来的进一步迭代,包括题目管理、答案录入以及结果评估功能。系统通过命令行界面与用户交互,用户可以输入题目和标准答案,然后录入自己的答案并获取结果。本次作业加深了对面向对象设计的理解,特别是如何通过类与对象封装数据和行为。本次作业特别强调了相关类的书写而且用过本次作业学习了正则表达式的用法,对以后代码的书写提供了便利。还学习到了如何通过重构提升代码的质量,注重代码的可读性和可维护性。而后面两次的家居强电电路模拟程序对于继承的用法提出了更加严格的要求,在进行电路相关的设计时我遇到了许多的困难,致使并未及时的完成这次的大作业,在之后我会花费更多的时间,并更早的开始大作业的代码的构思以及编写。经过这三次的java大作业我对我自己水平的不足有了深刻的认识,在许多地方都一知半解,导致每次都没法完整的完成作业,在之后我会花费更多的时间去练习java程序的编写。