题目集7~8的总结性Blog 第三次Blog

题目集7~8的总结性Blog 第三次Blog
前言
这第7次和第8次大作业是在前两次家居强电电路模拟程序的基础上进行再次迭代,难度较上两次有提升,加上最近考试周,时间紧张,没能拿多少分。

设计与分析:
第7次大作业题目:

智能家居是在当下家庭中越来越流行的一种配置方案,它通过物联网技术将家中的各种设备(如音视频设备、照明系统、窗帘控制、空调控制、安防系统、数字影院系统、影音服务器、影柜系统、网络家电等)连接到一起,提供家电控制、照明控制、电话远程控制、室内外遥控、防盗报警、环境监测、暖通控制、红外转发以及可编程定时控制等多种功能和手段。与普通家居相比,智能家居不仅具有传统的居住功能,兼备建筑、网络通信、信息家电、设备自动化,提供全方位的信息交互功能。请根据如下要去设计一个智能家居强电电路模拟系统。以下题目介绍中加粗的部分为本次迭代在“家居强电电路模拟程序-2”的基础上增加的功能要求。

1、控制设备

本题模拟的控制设备包括:开关、分档调速器、连续调速器、互斥开关。

开关:包括0和1两种状态。

开关有两个引脚,任意一个引脚都可以是输入引脚(接往电源端),而另一个则是输出引脚(接网接地端)。开关状态为0时,无论输入电位是多少,输出引脚电位为0。当开关状态为1时,输出引脚电位等于输入电位。
互斥开关:

互斥开关有3个引脚:1个是汇总引脚,另两个是分支引脚。

开关电路示意图如图1所示,左边是汇总引脚,编号为1;右边两个是分支引脚,右上的输出引脚为2,右下输出引脚为3。图中1、2、3引脚均可以是输入引脚,当1为输入引脚时,2、3引脚为输出引脚;1为输出引脚时,2、3引脚为输入引脚。

互斥开关只有两种状态:开关接往上面的2号引脚、接往下面的3号引脚。开关每次只能接通其中一个分支引脚,而另一个分支引脚处于断开状态。

互斥开关的默认状态为1、2引脚接通,1、3引脚断开。

图1中所示的互斥开关可以反过来接入电路,即汇总引脚接往接地端,两个分支引脚接往电源端。
image.png 

图1 互斥开关

为避免短路,互斥开关设置了限流电阻,12引脚之间默认电阻为5,13引脚之间默认电阻为10。

分档调速器

按档位调整,常见的有3档、4档、5档调速器,档位值从0档-2(3/4)档变化。本次迭代模拟4档调速器,每个档位的输出电位分别为0、0.3、0.6、0.9倍的输入电压。
连续调速器

没有固定档位,按位置比例得到档位参数,数值范围在[0.00-1.00]之间,含两位小数。输出电位为档位参数乘以输入电压。
所有调速器都有两个引脚,一个固定的输入(引脚编号为1)、一个输出引脚(引脚编号为2)。当输入电位为0时,输出引脚输出的电位固定为0,不受各类开关调节的影响。

开关、调速器的初始状态/档位为0。

调速器的输入引脚编号为1,输出引脚编号为2。
除互斥开关外,其他控制设备的电阻为 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。
落地扇:

工作电压区间为 80V-150V,对应转速区间为 80-360 转/分钟;[80V,100V) 对应转速为 80 转/分钟;[100,120)V 对应转速为 160 转/分钟;[120,140)V 对应转速为 260 转/分钟;大于等于 140V 转速 为 360 转/分钟(本次迭代暂不考虑电压超标的异常情况)。
 

本次迭代模拟一种受控窗帘:

受控窗帘的电路符号为S,其最低工作电压为50V,电压达到或超过50V,窗帘即可正常工作,不考虑室外光照强度和室内空间大小等因素,窗帘受室内灯光的光照强度控制。

当电路中所有灯光的光照强度总和在[0,50)lux范围内,窗帘全开;
在[50,100)lux范围内,窗帘打开比例为0.8;
在[100,200)lux范围内,窗帘打开比例为0.6;
在[200,300)lux范围内,窗帘打开比例为0.4;
在[300,400)lux范围内,窗帘打开比例为0.2;
在400lux及以上范围内,窗帘关闭。
当电压低于50V,窗帘不工作,默认为全开状态。
如果电路中没有灯或者灯全部关闭,光照强度为0,窗帘处于全开状态。
受控设备电阻:白炽灯的电阻为 10,日光灯的电阻为 5,吊扇的电阻为 20,落地扇的电阻为 20,窗帘电阻为15。

3、输入信息

1)输入设备信息

分别用设备标识符K、F、L、B、R、D、A、H、S分别表示开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇、落地扇、互斥开关、受控窗帘。

设备标识用标识符+编号表示,如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开关的状态。
#+设备标识H+设备编号,例如:#H2,代表切换H2互斥开关的状态。
分档调速器的调节信息格式:

#+设备标识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的一个部分,本题考虑这种类型的输入。



4、输出信息:

按开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇、互斥开关、受控窗帘的顺序依次输出所有设备的状态或参数。每个设备一行。同类设备按编号顺序从小到大输出。

输出格式:

@设备标识+设备编号+":" +设备参数值(控制开关的档位或状态、灯的亮度、风扇的转速,只输出值,不输出单位)
连续调速器的档位信息保留两位小数,即使小数为0,依然显示两位小数.00。
开关状态为0(打开)时显示turned on,状态为1(合上)时显示closed
如:
@K1:turned on
@B1:190
@L1:0.60
互斥开关显示1、2引脚的接通状态,接通时显示closed,断开时显示turned on。

如:

@H1:turned on

受控窗帘显示窗帘打开的百分比,如:

@S1:80%

 

5、家居电路模拟系列所有题目的默认规则:

1)当计算电压值等数值的过程中,最终结果出现小数时,用截尾规则去掉小数部分,只保留整数部分。为避免精度的误差,所有有可能出现小数的数值用double类型保存并计算,不要作下转型数据类型转换,例如电压、转速、亮度等,只有在最后输出时再把计算结果按截尾规则,舍弃尾数,保留整数输出。

2)所有连接信息按电路从电源到接地的顺序依次输入,不会出现错位的情况。电源VCC一定是第一个连接的第一项,接地GND一定是最后一个连接的后一项。

3)连接信息如果只包含两个引脚,靠电源端的引脚在前,靠接地端的在后。

4)调速器的输入端只会直连VCC,不会接其他设备。整个电路最多只有连接在电源上的一个调速器,且不包含在并联单路中。

 

6、家居电路模拟系列1-4题目后续迭代设计:

1)电路结构变化:

迭代1:只有一条线路,所有元件串联
迭代2:线路中包含一个并联电路
迭代3:线路中包含多个串联起来的并联电路
迭代4:并联电路之间可能出现包含关系

电路结构变化示意图见图1。

2)计算方式的变化

迭代1只包含1个受控元件,不用计算电流,之后的电路计算要包含电流、电阻等电路参数。

3)电路元件的变化

每次迭代会增加1-2个新的电路元件。

image.png

图1:电路结构示意图

设计建议:

1、电路设备类:描述所有电路设备的公共特征。

2、受控设备类、控制设备类:对应受控、控制设备

3、串联电路类:一条由多个电路设备构成的串联电路,也看成是一个独立的电路设备

4、并联电路类:继承电路设备类,也看成是一个独立的电路设备

其他类以及类的属性、方法自行设计。


image.png

图2:建议设计类图

输入样例1:
在这里给出一组输入。例如:

#T1:[IN H1-1] [H1-2 D2-1] [D2-2 OUT]
#T2:[IN H1-1] [H1-3 D1-1] [D1-2 OUT]
#M1:[T1 T2]
#T4:[IN K3-1] [K3-2 B2-1] [B2-2 OUT]
#T5:[IN K1-1] [K1-2 B1-1] [B1-2 OUT]
#M2:[T4 T5]
#T3:[VCC K2-1] [K2-2 M1-IN] [M1-OUT M2-IN] [M2-OUT GND]
#K1
#K2
end
输出样例1:
在这里给出相应的输出。例如:

@K1:closed
@K2:closed
@K3:turned on
@B1:87
@B2:0
@D1:0
@D2:262
@H1:closed
输入样例2:
在这里给出一组输入。例如:

#T1:[IN D2-1] [D2-2 H1-2] [H1-1 OUT]
#T2:[IN D1-1] [D1-2 H1-3] [H1-1 OUT]
#M1:[T1 T2]
#T4:[IN K3-1] [K3-2 B2-1] [B2-2 OUT]
#T5:[IN K1-1] [K1-2 B1-1] [B1-2 OUT]
#M2:[T4 T5]
#T3:[VCC K2-1] [K2-2 M1-IN] [M1-OUT M2-IN] [M2-OUT GND]
#K1
#K2
end
输出样例2:
在这里给出相应的输出。例如:

@K1:closed
@K2:closed
@K3:turned on
@B1:87
@B2:0
@D1:0
@D2:262
@H1:closed
输入样例3:
在这里给出一组输入。例如:

#T1:[IN K1-1] [K1-2 B2-1] [B2-2 OUT]
#T2:[IN K2-1] [K2-2 R1-1] [R1-2 OUT]
#M1:[T1 T2]
#T3:[VCC K3-1] [K3-2 M1-IN] [M1-OUT S1-1] [S1-2 GND]
#K1
#K2
#K3
end
输出样例3:
在这里给出相应的输出。例如:

@K1:closed
@K2:closed
@K3:closed
@B2:71
@R1:180
@S1:40%
输入样例4:
在这里给出一组输入。例如:

#T1:[IN K2-1] [K2-2 D2-1] [D2-2 OUT]
#T2:[IN K3-1] [K3-2 D1-1] [D1-2 OUT]
#T3:[VCC K1-1] [K1-2 T1-IN] [T1-OUT T2-IN] [T2-OUT GND]
#K1
#K2
#K3
end
输出样例4:
在这里给出相应的输出。例如:

@K1:closed
@K2:closed
@K3:closed
@D1:200
@D2:200
输入样例5:
在这里给出一组输入。例如:

#T3:[VCC B2-1] [B2-2 K1-1] [K1-2 S1-1] [S1-2 H1-1] [H1-2 GND]
#K1
end
输出样例5:
在这里给出相应的输出。例如:

@K1:closed
@B2:95
@H1:closed
@S1:80%

分析思路
定义设备类:首先,我们需要定义各种设备类。这些设备类应该继承一个通用的设备基类,该基类包含设备的基本属性和方法。
定义电路类:包括串联电路类和并联电路类,用于表示复杂的电路结构。
输入解析:解析输入的信息,包括设备连接、控制信息等。
计算电路状态:根据设备连接和控制信息,计算各设备的状态和输出。
输出结果:按要求的格式输出各设备的状态或参数。

1,设备基类

点击查看代码
abstract class Device {
    String id;
    int inputPin;
    int outputPin;

    public Device(String id, int inputPin, int outputPin) {
        this.id = id;
        this.inputPin = inputPin;
        this.outputPin = outputPin;
    }

    abstract void updateState();
    abstract String getStatus();
}

2,开关类
点击查看代码
class Switch extends Device {
    boolean state; // false for turned on, true for closed

    public Switch(String id) {
        super(id, 1, 2);
        this.state = false;
    }

    void toggle() {
        state = !state;
    }

    @Override
    void updateState() {
        // Implement logic to update the switch state
    }

    @Override
    String getStatus() {
        return "@K" + id + ":" + (state ? "closed" : "turned on");
    }
}

3,分档调速器类
点击查看代码
class StepRegulator extends Device {
    int level; // 0, 1, 2, 3
    double[] voltageLevels = {0, 0.3, 0.6, 0.9};

    public StepRegulator(String id) {
        super(id, 1, 2);
        this.level = 0;
    }

    void increaseLevel() {
        if (level < 3) level++;
    }

    void decreaseLevel() {
        if (level > 0) level--;
    }

    @Override
    void updateState() {
        // Implement logic to update the step regulator state
    }

    @Override
    String getStatus() {
        return "@F" + id + ":" + level;
    }
}

4,连续调速器类
点击查看代码
class ContinuousRegulator extends Device {
    double level; // [0.00, 1.00]

    public ContinuousRegulator(String id) {
        super(id, 1, 2);
        this.level = 0.0;
    }

    void setLevel(double level) {
        this.level = Math.min(1.0, Math.max(0.0, level));
    }

    @Override
    void updateState() {
        // Implement logic to update the continuous regulator state
    }

    @Override
    String getStatus() {
        return String.format("@L%s:%.2f", id, level);
    }
}

5,灯类
点击查看代码
abstract class Light extends Device {
    int brightness; // in lux

    public Light(String id, int resistance) {
        super(id, 1, 2);
        this.brightness = 0;
    }

    @Override
    abstract void updateState();

    @Override
    String getStatus() {
        return "@D" + id + ":" + brightness;
    }
}

class IncandescentLight extends Light {
    public IncandescentLight(String id) {
        super(id, 10);
    }

    @Override
    void updateState() {
        // Implement logic to update the incandescent light brightness
    }
}

class FluorescentLight extends Light {
    public FluorescentLight(String id) {
        super(id, 5);
    }

    @Override
    void updateState() {
        // Implement logic to update the fluorescent light brightness
    }
}

6,风扇类
点击查看代码
abstract class Fan extends Device {
    int speed; // in RPM

    public Fan(String id, int resistance) {
        super(id, 1, 2);
        this.speed = 0;
    }

    @Override
    abstract void updateState();

    @Override
    String getStatus() {
        return "@A" + id + ":" + speed;
    }
}

class CeilingFan extends Fan {
    public CeilingFan(String id) {
        super(id, 20);
    }

    @Override
    void updateState() {
        // Implement logic to update the ceiling fan speed
    }
}

class FloorFan extends Fan {
    public FloorFan(String id) {
        super(id, 20);
    }

    @Override
    void updateState() {
        // Implement logic to update the floor fan speed
    }
}

7,互斥开关类
点击查看代码
class MutexSwitch extends Device {
    boolean state; // false for 1-2 closed, true for 1-3 closed

    public MutexSwitch(String id) {
        super(id, 1, 3);
        this.state = false;
    }

    void toggle() {
        state = !state;
    }

    @Override
    void updateState() {
        // Implement logic to update the mutex switch state
    }

    @Override
    String getStatus() {
        return "@H" + id + ":" + (state ? "closed" : "turned on");
    }
}

8,受控窗帘类
点击查看代码
class ControlledCurtain extends Device {
    int openPercentage;

    public ControlledCurtain(String id) {
        super(id, 1, 2);
        this.openPercentage = 100; // default to fully open
    }

    @Override
    void updateState() {
        // Implement logic to update the curtain state
    }

    @Override
    String getStatus() {
        return "@S" + id + ":" + openPercentage + "%";
    }
}

9,串联电路类
点击查看代码
class SerialCircuit extends Device {
    List<Device> devices;

    public SerialCircuit(String id) {
        super(id, -1, -1); // Serial circuits don't have fixed input/output pins
        this.devices = new ArrayList<>();
    }

    void addDevice(Device device) {
        devices.add(device);
    }

    @Override
    void updateState() {
        // Implement logic to update the state of devices in the serial circuit
    }

    @Override
    String getStatus() {
        // Implement logic to get the status of devices in the serial circuit
        return "";
    }
}

10,并联电路类
点击查看代码
class ParallelCircuit extends Device {
    List<SerialCircuit> circuits;

    public ParallelCircuit(String id) {
        super(id, -1, -1); // Parallel circuits don't have fixed input/output pins
        this.circuits = new ArrayList<>();
    }

    void addCircuit(SerialCircuit circuit) {
        circuits.add(circuit);
    }

    @Override
    void updateState() {
        // Implement logic to update the state of circuits in the parallel circuit
    }

    @Override
    String getStatus() {
        // Implement logic to get the status of circuits in the parallel circuit
        return "";
    }
}

类之间的关系:

点击查看代码
继承关系:

Device 类是所有具体设备类的基类。所有具体的设备类(如 Switch、StepRegulator、ContinuousRegulator、Light、Fan、MutexSwitch、ControlledCurtain)都继承自 Device 类。
Light 类是一个抽象类,具体的灯具类(如 IncandescentLight 和 FluorescentLight)继承自 Light 类。
Fan 类也是一个抽象类,具体的风扇类(如 CeilingFan 和 FloorFan)继承自 Fan 类。
组合关系:

SerialCircuit 类和 ParallelCircuit 类组合了多个 Device 对象或 SerialCircuit 对象。每个 SerialCircuit 对象包含一个 List<Device>,用于存储串联电路中的所有设备;每个 ParallelCircuit 对象包含一个 List<SerialCircuit>,用于存储并联电路中的所有串联电路。
行为关系:

所有设备类都实现了 updateState 和 getStatus 方法,这些方法用于更新设备的状态和获取设备的状态信息。不同设备的 updateState 方法实现了不同的逻辑,确保每种设备的状态能够根据电路的输入和控制信息正确更新。
CircuitSimulator 类负责解析输入信息、更新设备状态并输出设备状态。它维护了一个 Map<String, Device>,用于存储所有设备,并提供了 parseInput、updateStates 和 outputStatus 方法。这些方法分别用于解析输入信息、更新所有设备的状态并输出设备的状态。

类图:

点击查看代码
                      +----------------------+
                      |       Device         |
                      +----------------------+
                          /            \
                         /              \
+--------------------+     +--------------------+
|      Light         |     |         Fan        |
+--------------------+     +--------------------+
         / \                      / \
        /   \                    /   \
+---------------+       +-------------------+
|IncandescentLight|   |   CeilingFan      |
+---------------+       +-------------------+
+------------------+    +---------------+
| FluorescentLight |    |   FloorFan    |
+------------------+    +---------------+

+-------------+       +--------------+
|    Switch   |       |StepRegulator |
+-------------+       +--------------+
+-------------+       +-----------------+
|  MutexSwitch|       |ContinuousRegulator|
+-------------+       +-----------------+
+-----------------+
|ControlledCurtain|
+-----------------+
                ^
                |
                +-----------+
                            |
                    +---------------+
                    | SerialCircuit |
                    +---------------+
                    +---------------+
                    | ParallelCircuit|
                    +---------------+
                             |
                       +-----------+
                       |CircuitSimulator|
                       +-----------+

设备类 (Device):基类,定义了所有设备的基本特性和行为,如设备 ID 和引脚信息。
灯类 (Light) 和 风扇类 (Fan):抽象类,分别定义了灯和风扇的共性行为。具体的灯具和风扇类继承这些抽象类,实现具体的状态更新逻辑。
开关类 (Switch)、分档调速器 (StepRegulator)、连续调速器 (ContinuousRegulator)、互斥开关 (MutexSwitch) 和 受控窗帘 (ControlledCurtain):具体设备类,继承自 Device 类,分别实现各自的状态更新逻辑。
串联电路类 (SerialCircuit) 和 并联电路类 (ParallelCircuit):用于表示电路结构,包含多个设备或电路。它们可以组合成更复杂的电路结构。
电路模拟器类 (CircuitSimulator):负责整个电路模拟过程,包括解析输入信息、更新设备状态并输出设备状态。

易踩坑点:

输入解析的复杂性:

坑点:输入格式较为复杂,解析时容易出错,尤其是嵌套的串联电路和并联电路。
改进:使用正则表达式进行输入验证,并在解析时详细记录解析过程中的步骤和状态。可以引入状态机或解析树来处理复杂的输入结构。
设备状态更新的顺序问题:

坑点:设备的状态更新可能存在依赖关系,必须按正确的顺序更新,否则会出现状态错误。
改进:采用拓扑排序确定设备更新顺序,确保依赖的设备先于被依赖的设备更新。
电压和电流计算的精度问题:

坑点:计算过程中可能会出现浮点数精度问题,导致最终结果不准确。
改进:使用高精度数据类型(如 BigDecimal)进行计算,确保在更新状态时保留足够的精度。最终输出时再进行截尾处理。
并联和串联电路的处理:

坑点:并联和串联电路的组合和嵌套可能会导致电路结构的管理变得复杂,容易出现逻辑错误。
改进:将并联电路和串联电路统一抽象为 Circuit 类,采用组合设计模式,使得处理嵌套电路时更加统一和简洁。
电路状态更新的循环依赖:

坑点:如果电路中存在循环依赖,会导致无限循环更新状态,程序崩溃。
改进:在更新状态前进行依赖关系检查,确保没有循环依赖。可以使用图论中的检测环算法来实现。
输出排序的遗漏:

坑点:输出结果的设备按编号排序时可能会遗漏某些设备,尤其是设备编号不连续时。
改进:在输出前对设备列表进行全面的排序检查,并确保所有设备都按要求输出。

改进后的部分示例代码:
解析输入

点击查看代码
class CircuitSimulator {
    Map<String, Device> devices = new HashMap<>();

    void parseInput(String input) {
        
    }

    void validateInput(String input) throws IllegalArgumentException {
        

    void updateStates() {
        
    }

    void outputStatus() {
        List<String> statuses = new ArrayList<>();
        for (Device device : devices.values()) {
            statuses.add(device.getStatus());
        }
        statuses.sort();
        for (String status : statuses) {
            System.out.println(status);
        }
    }

    public static void main(String[] args) {
        CircuitSimulator simulator = new CircuitSimulator();
        simulator.parseInput("your input here");
        simulator.updateStates();
        simulator.outputStatus();
    }
}

高精度计算

点击查看代码
class ContinuousRegulator extends Device {
    BigDecimal level; // [0.00, 1.00]

    public ContinuousRegulator(String id) {
        super(id, 1, 2);
        this.level = BigDecimal.ZERO;
    }

    void setLevel(BigDecimal level) {
        this.level = level.min(BigDecimal.ONE).max(BigDecimal.ZERO);
    }

    @Override
    void updateState() {
       
    }

    @Override
    String getStatus() {
        return String.format("@L%s:%.2f", id, level.setScale(2, RoundingMode.FLOOR));
    }
}

统一电路抽象

点击查看代码
abstract class Circuit {
    List<Device> devices = new ArrayList<>();

    void addDevice(Device device) {
        devices.add(device);
    }

    abstract void updateState();

    abstract String getStatus();
}

class SerialCircuit extends Circuit {
    @Override
    void updateState() {
        
    }

    @Override
    String getStatus() {
        
        return "";
    }
}

class ParallelCircuit extends Circuit {
    @Override
    void updateState() {
        
    }

    @Override
    String getStatus() {
        
        return "";
    }
}

通过以上改进,代码的鲁棒性和可维护性将得到显著提高。解析输入和更新状态的逻辑更加清晰,计算的精度得到保证,处理复杂电路结构时的代码更加简洁和统一。这样设计的系统不仅能够更好地模拟智能家居的强电电路,还具有良好的扩展性和可维护性。

第8次大作业题目:

智能家居是在当下家庭中越来越流行的一种配置方案,它通过物联网技术将家中的各种设备(如音视频设备、照明系统、窗帘控制、空调控制、安防系统、数字影院系统、影音服务器、影柜系统、网络家电等)连接到一起,提供家电控制、照明控制、电话远程控制、室内外遥控、防盗报警、环境监测、暖通控制、红外转发以及可编程定时控制等多种功能和手段。与普通家居相比,智能家居不仅具有传统的居住功能,兼备建筑、网络通信、信息家电、设备自动化,提供全方位的信息交互功能。请根据如下要去设计一个智能家居强电电路模拟系统。以下题目介绍中加粗的部分为本次迭代在“家居强电电路模拟程序-3”的基础上增加的功能要求。

1、控制设备
本题模拟的控制设备包括:开关、分档调速器、连续调速器、互斥开关。

开关:包括0和1两种状态。

开关有两个引脚,任意一个引脚都可以是输入引脚(接往电源端),而另一个则是输出引脚(接网接地端)。开关状态为0时,无论输入电位是多少,输出引脚电位为0。当开关状态为1时,输出引脚电位等于输入电位。
互斥开关:

互斥开关有3个引脚:1个是汇总引脚,另两个是分支引脚。

 

开关电路示意图如图1所示,左边是汇总引脚,编号为1;右边两个是分支引脚,右上的输出引脚为2,右下输出引脚为3。图中1、2、3引脚均可以是输入引脚,当1为输入引脚时,2、3引脚为输出引脚;1为输出引脚时,2、3引脚为输入引脚。
互斥开关只有两种状态:开关接往上面的2号引脚、接往下面的3号引脚。开关每次只能接通其中一个分支引脚,而另一个分支引脚处于断开状态。
互斥开关的默认状态为1、2引脚接通,1、3引脚断开。
图1中所示的互斥开关可以反过来接入电路,即汇总引脚接往接地端,两个分支引脚接往电源端。
 

image.png 

图1 互斥开关

为避免短路,互斥开关设置了限流电阻,1、2引脚之间默认电阻为5,1、3引脚之间默认电阻为10。


分档调速器

按档位调整,常见的有3档、4档、5档调速器,档位值从0档-2(3/4)档变化。本次迭代模拟4档调速器,每个档位的输出电位分别为0、0.3、0.6、0.9倍的输入电压。
连续调速器

没有固定档位,按位置比例得到档位参数,数值范围在[0.00-1.00]之间,含两位小数。输出电位为档位参数乘以输入电压。
所有调速器都有两个引脚,一个固定的输入(引脚编号为1)、一个输出引脚(引脚编号为2)。当输入电位为0时,输出引脚输出的电位固定为0,不受各类开关调节的影响。

开关、调速器的初始状态/档位为0。

开关的两个引脚编号为1、2。
除互斥开关外,其他控制设备的电阻为 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。
落地扇:

工作电压区间为 80V-150V,对应转速区间为 80-360 转/分钟;[80V,100V) 对应转速为 80 转/分钟;[100,120)V 对应转速为 160 转/分钟;[120,140)V 对应转速为 260 转/分钟;大于等于 140V 转速 为 360 转/分钟(本次迭代暂不考虑电压超标的异常情况)。
 

本次迭代模拟一种受控窗帘:

受控串联的电路符号为S,其最低工作电压为50V,电压达到或超过50V,窗帘即可正常工作,不考虑室外光照强度和室内空间大小等因素,窗帘受室内灯光的光照强度控制。
当电路中所有灯光的光照强度总和在[0,50)lux范围内,窗帘全开;
在[50,100)lux范围内,窗帘打开比例为0.8;
在[100,200)lux范围内,窗帘打开比例为0.6;
在[200,300)lux范围内,窗帘打开比例为0.4;
在[300,400)lux范围内,窗帘打开比例为0.2;
在400lux及以上范围内,窗帘关闭。
当电压低于50V,窗帘不工作,默认为全开状态。
如果电路中没有灯或者灯全部关闭,光照强度为0,窗帘处于全开状态。
受控设备电阻:白炽灯的电阻为 10,日光灯的电阻为 5,吊扇的电阻为 20,落地扇的电阻为 20,窗帘电阻为15。


3、输入信息
1)输入设备信息

分别用设备标识符K、F、L、B、R、D、A、H、S、P分别表示开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇、落地扇、互斥开关、受控窗帘、二极管(见第6部分说明)。

设备标识用标识符+编号表示,如K1、F3、L2等。

引脚格式:
设备标识-引脚编号,例如:K1-1标识编号为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开关的状态。
#+设备标识H+设备编号,例如:#H2,代表切换H2互斥开关的状态。
分档调速器的调节信息格式:

#+设备标识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。
 在本题中,并联电路M中的串联电路可以包含别的并联电路。

约束条件:

本题不考虑输入电压或电压差超过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的一个部分,本题考虑这种类型的输入。
4、输出信息:
按开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇、互斥开关、受控窗帘、二极管(见第6部分说明)的顺序依次输出所有设备的状态或参数。每个设备一行。同类设备按编号顺序从小到大输出。

输出格式:
@设备标识+设备编号+":" +设备参数值(控制开关的档位或状态、灯的亮度、风扇的转速,只输出值,不输出单位)+" "+设备所有引脚的电压(按编号从小到大顺序依次输出,电压的小数部分直接丢弃,保留整数输出,电压之间用”-”分隔)

说明:
连续调速器的档位信息保留两位小数,即使小数为0,依然显示两位小数.00。
开关状态为0(打开)时显示turned on,状态为1(合上)时显示closed
如:
@K1:turned on 32-15
@B1:190 68-17
@L1:0.60 220-176
互斥开关按1、2引脚的接通状态显示,1,2接通-1,3断开时显示closed,1,3接通-1,2断开时显示turned on。
如:
@H1:turned on
受控窗帘显示窗帘打开的百分比,如:
@S1:80%
 

5、家居电路模拟系列所有题目的默认规则
1)当计算电压值等数值的过程中,最终结果出现小数时,用截尾规则去掉小数部分,只保留整数部分。为避免精度的误差,所有有可能出现小数的数值用double类型保存并计算,不要作下转型数据类型转换,例如电压、转速、亮度等,只有在最后输出时再把计算结果按截尾规则,舍弃尾数,保留整数输出。

2)所有连接信息按电路从靠电源端到靠接地端的顺序依次输入,不会出现错位的情况。VCC/IN一定是第一个连接的第一项,GND/OUT一定是最后一个连接的后一项。

3)连接信息如果只包含两个引脚,靠电源端的引脚在前,靠接地端的在后。

4)调速器的输入端只会直连VCC,不会接其他设备。整个电路最多只有连接在电源上的一个调速器,且不包含在并联单路中。

 5)本系列题目中元件的管脚除了互斥开关的1引脚,其他所有引脚在电路中最多只出现一次。

6、本题新增内容:
1)增加管脚电压的显示

在输出每个电器的状态信息后,再依次输出该电器每个管脚的电压。(格式详见输出信息部分)


2)电流限制

电器在工作时,过大的电流会引起电器过热,从而烧坏电路。本次迭代,每个元器件都有最大电流的设置,当实时电流超过最大电流时,在该电器输出信息的最后加入提示“exceeding current limit error”,与前面的信息之间用英文空格分隔。

例如:@B1:190 68-17 exceeding current limit error

本题各类电器的最大限定电流如下:

开关20、分档调速器18、连续调速器18、白炽灯9、日光灯5、吊扇12、落地扇14、互斥开关20、受控窗帘12、二极管8。


3)短路检测

如果电路出现无穷大的电流造成短路,所有元器件信息不输出,仅输出提示“short circuit error”


4)并联电路中包含并联

本次迭代考虑并联电路中包含并联电路的情况,即构成并联电路的串联电路可以包含别的并联电路。例如如下输入的电路,并联电路M2的其中一条串联电路T4中包含了另一条并联电路M1:

#T1:[IN D2-1] [D2-2 H1-2] [H1-1 OUT]

#T2:[IN D1-1] [D1-2 H1-3] [H1-1 OUT]

#M1:[T1 T2]

#T4:[IN K3-1] [K3-2 M1-IN] [M1-OUT OUT]

#T5:[IN K1-1] [K1-2 B1-1] [B1-2 OUT]

#M2:[T4 T5]
5)二极管

增加二极管元件,其电路特性为:正向导通,反向截止;其电器符号如图4所示,当电流从左至右流过时,二极管导通”conduction”,电阻为0;电流从右至左流动时,二极管截止”cutoff”,电阻无穷大,相当于开关打开。

image.png 

图2 二极管符号

二极管的标识符为’P’,左侧管脚编号为1,右侧管脚编号为2。

二极管如果两端电压相等,没有电流流过,分以下两种情况输出:

1、如果两端电压为0,二极管的导通/截止状态由接入方向决定,1号引脚靠近电源则状态为导通,反之为截止。
2、如果两端电压不为0,二极管导通。
 

7、设计建议
本题包含以下电路图中的所有连接情况:


image.png

图3 电路示意图

1、电路设备类:描述所有电路设备的公共特征。

2、受控设备类、控制设备类:对应受控、控制设备

3、串联电路类:一条由多个电路设备构成的串联电路,也看成是一个独立的电路设备

4、并联电路类:继承电路设备类,也看成是一个独立的电路设备

其他类以及类的属性、方法自行设计。


image.png

图4:建议设计类图

输入样例1:
在这里给出一组输入。例如:

#T1:[IN P2-2] [P2-1 H1-2] [H1-1 OUT]
#T2:[IN D1-1] [D1-2 H1-3] [H1-1 OUT]
#M1:[T1 T2]
#T4:[IN K3-1] [K3-2 M1-IN] [M1-OUT OUT]
#T5:[IN K1-1] [K1-2 B1-1] [B1-2 OUT]
#M2:[T4 T5]
#T3:[VCC K2-1] [K2-2 M2-IN] [M2-OUT GND]
#K1
#K2
end
输出样例1:
在这里给出相应的输出。例如:

@K1:closed 220-220 exceeding current limit error
@K2:closed 220-220 exceeding current limit error
@K3:turned on 220-0
@B1:200 220-0 exceeding current limit error
@D1:0 0-0
@H1:closed 0-0-0
@P2:cutoff 0-0
输入样例2:
在这里给出一组输入。例如:

#T1:[IN P2-1] [P2-2 H1-2] [H1-1 OUT]
#T2:[IN D1-1] [D1-2 H1-3] [H1-1 OUT]
#M1:[T1 T2]
#T4:[IN K3-1] [K3-2 M1-IN] [M1-OUT OUT]
#T5:[IN K1-1] [K1-2 B1-1] [B1-2 OUT]
#M2:[T4 T5]
#T3:[VCC K2-1] [K2-2 M2-IN] [M2-OUT GND]
#K1
#K3
#K2
end
输出样例2:
在这里给出相应的输出。例如:

@K1:closed 220-220 exceeding current limit error
@K2:closed 220-220 exceeding current limit error
@K3:closed 220-220 exceeding current limit error
@B1:200 220-0 exceeding current limit error
@D1:0 220-220
@H1:closed 0-220-220 exceeding current limit error
@P2:conduction 220-220 exceeding current limit error
输入样例3:
在这里给出一组输入。例如:

#T1:[IN P2-2] [P2-1 H1-2] [H1-1 OUT]
#T2:[IN D1-1] [D1-2 H1-3] [H1-1 OUT]
#M1:[T1 T2]
#T4:[IN K3-1] [K3-2 M1-IN] [M1-OUT OUT]
#T5:[IN K1-1] [K1-2 B1-1] [B1-2 OUT]
#M2:[T4 T5]
#T3:[VCC K2-1] [K2-2 M2-IN] [M2-OUT GND]
#K1
#K3
#K2
end
输出样例3:
在这里给出相应的输出。例如:

@K1:closed 220-220 exceeding current limit error
@K2:closed 220-220 exceeding current limit error
@K3:closed 220-220
@B1:200 220-0 exceeding current limit error
@D1:0 220-220
@H1:closed 0-0-220
@P2:cutoff 0-220
输入样例4:
在这里给出一组输入。例如:

#T3:[VCC K2-1] [K2-2 GND]
#K2
end
输出样例4:
在这里给出相应的输出。例如:

short circuit error
输入样例5:
在这里给出一组输入。如果两端电压为0,二极管的导通/截止状态由接入方向决定,1号引脚靠近电源则状态为导通,反之截止。 例如:

#T3:[VCC K2-2] [K2-1 P1-1] [P1-2 K1-2] [K1-1 GND]
end
输出样例5:
在这里给出相应的输出。例如:

@K1:turned on 0-0
@K2:turned on 0-220
@P1:conduction 0-0
输入样例6:
在这里给出一组输入。如果两端电压为0,二极管的导通/截止状态由接入方向决定,1号引脚靠近电源则状态为导通,反之截止。 例如:

#T3:[VCC K2-2] [K2-1 P1-2] [P1-1 K1-2] [K1-1 GND]
end
输出样例6:
####### 。例如:

@K1:turned on 0-0
@K2:turned on 0-220
@P1:cutoff 0-0

分析思路:
解析输入:解析输入信息,包括设备连接信息、控制信息等。
建模电路设备:通过面向对象的方法建模各种电路设备。
计算电压和电流:根据电路连接关系,计算各设备的电压和电流。
检测短路和电流超限:检测电路中是否存在短路或电流超限情况。
输出结果:按要求的格式输出各设备的状态和参数。
1,设备基类

点击查看代码
abstract class Device {
    String id; // 设备标识
    int inputPinVoltage; // 输入引脚电压
    int outputPinVoltage; // 输出引脚电压
    double current; // 电流
    double maxCurrent; // 最大电流

    public Device(String id, double maxCurrent) {
        this.id = id;
        this.maxCurrent = maxCurrent;
        this.inputPinVoltage = 0;
        this.outputPinVoltage = 0;
        this.current = 0;
    }

    abstract void updateState();

    abstract String getStatus();

    public boolean isCurrentExceeding() {
        return current > maxCurrent;
    }

    public void setVoltage(int inputPinVoltage, int outputPinVoltage) {
        this.inputPinVoltage = inputPinVoltage;
        this.outputPinVoltage = outputPinVoltage;
    }
}

2,开关类

点击查看代码
class Switch extends Device {
    boolean state; // false for turned on, true for closed

    public Switch(String id) {
        super(id, 20);
        this.state = false;
    }

    void toggle() {
        state = !state;
    }

    @Override
    void updateState() {
        if (state) {
            outputPinVoltage = inputPinVoltage;
        } else {
            outputPinVoltage = 0;
        }
    }

    @Override
    String getStatus() {
        return "@K" + id + ":" + (state ? "closed" : "turned on") + " " + inputPinVoltage + "-" + outputPinVoltage + (isCurrentExceeding() ? " exceeding current limit error" : "");
    }
}

3,分档调速器类
点击查看代码
class StepRegulator extends Device {
    int level; // 0, 1, 2, 3
    double[] voltageLevels = {0, 0.3, 0.6, 0.9};

    public StepRegulator(String id) {
        super(id, 18);
        this.level = 0;
    }

    void increaseLevel() {
        if (level < 3) level++;
    }

    void decreaseLevel() {
        if (level > 0) level--;
    }

    @Override
    void updateState() {
        outputPinVoltage = (int) (inputPinVoltage * voltageLevels[level]);
    }

    @Override
    String getStatus() {
        return "@F" + id + ":" + level + " " + inputPinVoltage + "-" + outputPinVoltage + (isCurrentExceeding() ? " exceeding current limit error" : "");
    }
}

4,连续调速器类
点击查看代码
class ContinuousRegulator extends Device {
    double level; // [0.00, 1.00]

    public ContinuousRegulator(String id) {
        super(id, 18);
        this.level = 0.0;
    }

    void setLevel(double level) {
        this.level = Math.min(1.0, Math.max(0.0, level));
    }

    @Override
    void updateState() {
        outputPinVoltage = (int) (inputPinVoltage * level);
    }

    @Override
    String getStatus() {
        return String.format("@L%s:%.2f %d-%d", id, level, inputPinVoltage, outputPinVoltage) + (isCurrentExceeding() ? " exceeding current limit error" : "");
    }
}

5,灯类
点击查看代码
abstract class Light extends Device {
    int brightness; // 亮度

    public Light(String id, double maxCurrent) {
        super(id, maxCurrent);
        this.brightness = 0;
    }

    @Override
    abstract void updateState();

    @Override
    String getStatus() {
        return "@D" + id + ":" + brightness + " " + inputPinVoltage + "-" + outputPinVoltage + (isCurrentExceeding() ? " exceeding current limit error" : "");
    }
}

class IncandescentLight extends Light {
    public IncandescentLight(String id) {
        super(id, 9);
    }

    @Override
    void updateState() {
        if (outputPinVoltage <= 9) {
            brightness = 0;
        } else {
            brightness = (int) ((outputPinVoltage - 9) * 150 / 211 + 50);
        }
    }
}

class FluorescentLight extends Light {
    public FluorescentLight(String id) {
        super(id, 5);
    }

    @Override
    void updateState() {
        brightness = (outputPinVoltage == 0) ? 0 : 180;
    }
}

6,风扇类
点击查看代码
abstract class Fan extends Device {
    int speed; // 转速

    public Fan(String id, double maxCurrent) {
        super(id, maxCurrent);
        this.speed = 0;
    }

    @Override
    abstract void updateState();

    @Override
    String getStatus() {
        return "@A" + id + ":" + speed + " " + inputPinVoltage + "-" + outputPinVoltage + (isCurrentExceeding() ? " exceeding current limit error" : "");
    }
}

class CeilingFan extends Fan {
    public CeilingFan(String id) {
        super(id, 12);
    }

    @Override
    void updateState() {
        if (outputPinVoltage < 80) {
            speed = 0;
        } else if (outputPinVoltage > 150) {
            speed = 360;
        } else {
            speed = (int) ((outputPinVoltage - 80) * 280 / 70 + 80);
        }
    }
}

class FloorFan extends Fan {
    public FloorFan(String id) {
        super(id, 14);
    }

    @Override
    void updateState() {
        if (outputPinVoltage < 80) {
            speed = 0;
        } else if (outputPinVoltage < 100) {
            speed = 80;
        } else if (outputPinVoltage < 120) {
            speed = 160;
        } else if (outputPinVoltage < 140) {
            speed = 260;
        } else {
            speed = 360;
        }
    }
}

7,互斥开关类
点击查看代码
class MutexSwitch extends Device {
    boolean state; // false for 1-2 closed, true for 1-3 closed

    public MutexSwitch(String id) {
        super(id, 20);
        this.state = false;
    }

    void toggle() {
        state = !state;
    }

    @Override
    void updateState() {
        if (state) {
            outputPinVoltage = inputPinVoltage;
        } else {
            outputPinVoltage = 0;
        }
    }

    @Override
    String getStatus() {
        return "@H" + id + ":" + (state ? "closed" : "turned on") + " " + inputPinVoltage + "-" + outputPinVoltage + (isCurrentExceeding() ? " exceeding current limit error" : "");
    }
}

8,受控窗帘类
点击查看代码
class ControlledCurtain extends Device {
    int openPercentage; // 打开比例

    public ControlledCurtain(String id) {
        super(id, 12);
        this.openPercentage = 100; // 默认全开
    }

    @Override
    void updateState() {
        if (outputPinVoltage < 50) {
            openPercentage = 100;
        } else {
            // 计算所有灯光的光照强度总和
            int totalLux = ... // 此处需根据具体电路计算
            if (totalLux < 50) {
                openPercentage = 100;
            } else if (totalLux < 100) {
                openPercentage = 80;
            } else if (totalLux < 200) {
                openPercentage = 60;
            } else if (totalLux < 300) {
                openPercentage = 40;
            } else if (totalLux < 400) {
                openPercentage = 20;
            } else {
                openPercentage = 0;
            }
        }
    }

    @Override
    String getStatus() {
        return "@S" + id + ":" + openPercentage + "%" + " " + inputPinVoltage + "-" + outputPinVoltage + (isCurrentExceeding() ? " exceeding current limit error" : "");
    }
}

9,二极管类
点击查看代码
class Diode extends Device {
    public Diode(String id) {
        super(id, 8);
    }

    @Override
    void updateState() {
        if (inputPinVoltage > outputPinVoltage) {
            // 正向导通
            current = ... // 计算电流
        } else if (inputPinVoltage < outputPinVoltage) {
            // 反向截止
            current = 0;
        }
    }

    @Override
    String getStatus() {
        String state = inputPinVoltage > outputPinVoltage ? "conduction" : "cutoff";
        return "@P" + id + ":" + state + " " + inputPinVoltage + "-" + outputPinVoltage + (isCurrentExceeding() ? " exceeding current limit error" : "");
    }
}

10,串联电路类
点击查看代码
class SerialCircuit extends Device {
    List<Device> devices;

    public SerialCircuit(String id) {
        super(id, Double.MAX_VALUE); // 串联电路没有固定的电流限制
        this.devices = new ArrayList<>();
    }

    void addDevice(Device device) {
        devices.add(device);
    }

    @Override
    void updateState() {
        // 更新串联电路中所有设备的状态
        for (Device device : devices) {
            device.updateState();
        }
    }

    @Override
    String getStatus() {
        // 获取串联电路中所有设备的状态
        StringBuilder status = new StringBuilder();
        for (Device device : devices) {
            status.append(device.getStatus()).append("\n");
        }
        return status.toString();
    }
}

11,并联电路类
点击查看代码
class ParallelCircuit extends Device {
    List<SerialCircuit> circuits;

    public ParallelCircuit(String id) {
        super(id, Double.MAX_VALUE); // 并联电路没有固定的电流限制
        this.circuits = new ArrayList<>();
    }

    void addCircuit(SerialCircuit circuit) {
        circuits.add(circuit);
    }

    @Override
    void updateState() {
        // 更新并联电路中所有串联电路的状态
        for (SerialCircuit circuit : circuits) {
            circuit.updateState();
        }
    }

    @Override
    String getStatus() {
        // 获取并联电路中所有串联电路的状态
        StringBuilder status = new StringBuilder();
        for (SerialCircuit circuit : circuits) {
            status.append(circuit.getStatus()).append("\n");
        }
        return status.toString();
    }
}

12,电路模拟器类
点击查看代码
class CircuitSimulator {
    Map<String, Device> devices = new HashMap<>();

    void parseInput(String input) {
        // 解析输入信息
    }

    void validateInput(String input) throws IllegalArgumentException {
        // 验证输入信息的有效性
    }

    void updateStates() {
        // 更新所有设备的状态
        for (Device device : devices.values()) {
            device.updateState();
        }
    }

    void outputStatus() {
        // 输出所有设备的状态
        List<String> statuses = new ArrayList<>();
        for (Device device : devices.values()) {
            statuses.add(device.getStatus());
        }
        statuses.sort();
        for (String status : statuses) {
            System.out.println(status);
        }
    }

    public static void main(String[] args) {
        CircuitSimulator simulator = new CircuitSimulator();
        simulator.parseInput("your input here");
        simulator.updateStates();
        simulator.outputStatus();
    }
}

Device类是所有设备的基类,包含设备的基本属性和方法,如设备ID、引脚电压、电流和最大电流。它定义了更新设备状态和获取设备状态的抽象方法。
Switch类继承自Device,表示开关设备。它有一个状态(打开或关闭),并根据状态更新输出引脚的电压。
StepRegulator类表示分档调速器,可以通过增加或减少档位来调节输出电压。
ContinuousRegulator类表示连续调速器,可以设置任意档位(0.00到1.00),根据档位比例调节输出电压。
Light类表示灯具设备,包含亮度属性。具体灯具类型如白炽灯和日光灯继承自Light类,并实现不同的亮度计算逻辑。
Fan类表示风扇设备,包含转速属性。具体风扇类型如吊扇和落地扇继承自Fan类,并实现不同的转速计算逻辑。
MutexSwitch类表示互斥开关设备,具有两个状态(1-2接通或1-3接通),并根据状态更新输出引脚的电压。
ControlledCurtain类表示受控窗帘,根据电压和灯光强度决定窗帘的打开比例。
Diode类表示二极管设备,根据输入输出引脚电压决定导通或截止状态,并计算电流。
SerialCircuit类表示串联电路,包含多个设备,并提供更新和获取所有设备状态的方法。
arallelCircuit类表示并联电路,包含多个串联电路,并提供更新和获取所有串联电路状态的方法。
CircuitSimulator类负责整个电路模拟过程,包括解析输入信息、更新设备状态并输出设备状态。它维护了一个设备的映射表,并提供了解析输入、验证输入、更新状态和输出状态的方法。

踩坑心得:

输入解析的复杂性:

坑点:输入格式较为复杂,解析时容易出错,尤其是嵌套的串联电路和并联电路。
改进:使用正则表达式进行输入验证,并在解析时详细记录解析过程中的步骤和状态。可以引入状态机或解析树来处理复杂的输入结构。
设备状态更新的顺序问题:

坑点:设备的状态更新可能存在依赖关系,必须按正确的顺序更新,否则会出现状态错误。
改进:采用拓扑排序确定设备更新顺序,确保依赖的设备先于被依赖的设备更新。
电压和电流计算的精度问题:

坑点:计算过程中可能会出现浮点数精度问题,导致最终结果不准确。
改进:使用高精度数据类型(如 BigDecimal)进行计算,确保在更新状态时保留足够的精度。最终输出时再进行截尾处理。
并联和串联电路的处理:

坑点:并联和串联电路的组合和嵌套可能会导致电路结构的管理变得复杂,容易出现逻辑错误。
改进:将并联电路和串联电路统一抽象为 Circuit 类,采用组合设计模式,使得处理嵌套电路时更加统一和简洁。
电路状态更新的循环依赖:

坑点:如果电路中存在循环依赖,会导致无限循环更新状态,程序崩溃。
改进:在更新状态前进行依赖关系检查,确保没有循环依赖。可以使用图论中的检测环算法来实现。
输出排序的遗漏:

坑点:输出结果的设备按编号排序时可能会遗漏某些设备,尤其是设备编号不连续时。
改进:在输出前对设备列表进行全面的排序检查,并确保所有设备都按要求输出。

代码改进:
解析输入

点击查看代码
class CircuitSimulator {
    Map<String, Device> devices = new HashMap<>();

    void parseInput(String input) {
        
    }

    void validateInput(String input) throws IllegalArgumentException {
        

    }

    void updateStates() {
        
    }

    void outputStatus() {
        List<String> statuses = new ArrayList<>();
        for (Device device : devices.values()) {
            statuses.add(device.getStatus());
        }
        statuses.sort();
        for (String status : statuses) {
            System.out.println(status);
        }
    }

    public static void main(String[] args) {
        CircuitSimulator simulator = new CircuitSimulator();
        simulator.parseInput("your input here");
        simulator.updateStates();
        simulator.outputStatus();
    }
}

高精度计算
点击查看代码
class ContinuousRegulator extends Device {
    BigDecimal level; 

    public ContinuousRegulator(String id) {
        super(id, 18);
        this.level = BigDecimal.ZERO;
    }

    void setLevel(BigDecimal level) {
        this.level = level.min(BigDecimal.ONE).max(BigDecimal.ZERO);
    }

    @Override
    void updateState() {
        outputPinVoltage = (int) (inputPinVoltage * level.doubleValue());
    }

    @Override
    String getStatus() {
        return String.format("@L%s:%.2f %d-%d", id, level.setScale(2, RoundingMode.FLOOR), inputPinVoltage, outputPinVoltage) + (isCurrentExceeding() ? " exceeding current limit error" : "");
    }
}

统一电路抽象
点击查看代码
abstract class Circuit extends Device {
    List<Device> devices = new ArrayList<>();

    void addDevice(Device device) {
        devices.add(device);
    }

    abstract void updateState();

    abstract String getStatus();
}

class SerialCircuit extends Circuit {
    @Override
    void updateState() {
        // Implement logic to update the state of devices in the serial circuit
    }

    @Override
    String getStatus() {
        // Implement logic to get the status of devices in the serial circuit
        StringBuilder status = new StringBuilder();
        for (Device device : devices) {
            status.append(device.getStatus()).append("\n");
        }
        return status.toString();
    }
}

class ParallelCircuit extends Circuit {
    @Override
    void updateState() {
        
    }

    @Override
    String getStatus() {
        
        StringBuilder status = new StringBuilder();
        for (Device device : devices) {
            status.append(device.getStatus()).append("\n");
        }
        return status.toString();
    }
}

总结

虽然就两次大作业,但最近考试频繁和复习紧张,这次大作业没有以前那么用心,没有拿多少分,后面考完后准备再把没写完的补上
posted @ 2024-06-28 23:10  zengfangzhi  阅读(26)  评论(0)    收藏  举报