前言:
(1) 第七次題集只有一道題目——家居強電電路模擬程式-3,這是第三次迭代,這次迭代主要的點有四個。
首先本次迭代新增了線路中存在多個串聯起來的並聯電路。不同於上次的單並聯,本次更復雜。
然後本次還新迭代了一種控制器——互斥開關,互斥開關一共有三個觸腳,預設狀態是1,2相連,但是互斥開關可以反接所以互斥開關還需要考慮接入的方向,這顯然需要需要引入一個新的變數進行判定。然後就是這個互斥開關是有電阻的,並不是理想開關,所以對於短路的判斷需要重新考慮。
再然後是串聯中包含串聯電路,不論是主路還是支路都有可能出現串聯電路,這一點還是比較好處理的,本身就是將串聯電路設定為了電路裝置。
最後是引入了一種受控電器——受控窗簾,收到電壓和室內亮度的控制,預設狀態為全開。
總體而言本次題解較上次迭代而言難度增幅不算太大。
(2) 第八次題集同樣只有一道題目——家居強電電路模擬程式-4,這是本系列題目的第四次迭代,這次迭代引入了很多新的功能,主要有五點。
首先是增加管腳電壓的顯示,在輸出每個電器的狀態資訊後,再依次輸出該電器每個管腳的電壓。這一點是最讓人頭疼的地方,需要好好回憶一下高中的電路,同時有幾種特殊情況需要注意情況,不然很容易錯。
然後是電流限制,電器在工作時,過大的電流會引起電器過熱,從而燒壞電路。本次迭代,每個元器件都有最大電流的設定,當實時電流超過最大電流時,在該電器輸出資訊的最後加入提示“exceeding current limit error”,與前面的資訊之間用英文空格分隔。
再次是短路檢測,如果電路出現無窮大的電流造成短路,所有元器件資訊不輸出,僅輸出提示“short circuit error”。
再然後是並聯電路中包含並聯,本次迭代考慮並聯電路中包含並聯電路的情況,即構成並聯電路的串聯電路可以包含別的並聯電路。這一點比較好處理,因為並聯電路本身也別看作一個電路裝置,在支路的輸入時,加入這種情況就行。
最後是二極體,增加二極體元件,其電路特性為:正向導通,反向截止;其電器符號如圖4所示,當電流從左至右流過時,二極體導通”conduction”,電阻為0;電流從右至左流動時,二極體截止”cutoff”,電阻無窮大,相當於開關開啟。
總體而言,本次迭代的難度增加了很多,讓人眼前一黑,主要是管腳電壓的顯示,確實需要考慮很多情況。
第七次題集
設計與分析:
首先本次迭代比起上次需要將串聯電路也設定為一個電路裝置類,以下是一個簡易類圖:
對串聯類同時也加入了很多新的方法,以下是部分程式碼展示:
class Series extends Equipment{
public double getVoltage() {
return voltage;
}
public void setVoltage(double voltage) {
this.voltage = voltage;
}
private double voltage;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
public void VoltageDivision()
{
double aver=getVoltage()/getResistor();
for(int i=0;i<list.size();i++)
{
Equipment e= list.get(i);
if(e instanceof Switch || e instanceof Governor || e instanceof ContinueGovernor||e instanceof Hswitch)
continue;
else if(e instanceof Series)
{
e.setVoltage(aver*e.getResistor());
e.VoltageDivision();
}
else
{
e.setVoltage(aver*e.getResistor());
}
}
}
private double resistor;
public double getResistor() {
resistor = 0;
for (int i = 0; i < list.size(); i++) {
Equipment e = list.get(i);
if (e instanceof Switch || e instanceof Governor || e instanceof ContinueGovernor)
continue;
else if(e instanceof Hswitch&&e.IfHswitchPath(this.name))
{
resistor+=e.getResistor();
}
else
{
resistor += e.getResistor();
}
}
return resistor;
}
public boolean IfPathway()
{
for(int i=0;i< list.size();i++)
{
Equipment e= list.get(i);
if(e instanceof Switch)
{
if(e.switchstyle==0)
{
return false;
}
}
else if(e instanceof Parallel&&e.IfPathway()==false)
{
return false;
}
else if(e instanceof Hswitch&&e.IfHswitchPath(this.name)==false)
{
return false;
}
else if(e instanceof Series&&!e.IfPathway())
{
return false;
}
}
return true;
}
public boolean Ifshort()//檢查是否短路 短路就是true 不短路就是false
{
boolean flag=true;
for(int i=0;i<list.size();i++)
{
Equipment e= list.get(i);
if(e instanceof Switch&&e.switchstyle==1)
{
continue;
}
else if(e instanceof Series&& e.Ifshort())
{
continue;
}
else
{
flag=false;
break;
}
}
return flag;
}
public ArrayList<Equipment> getList() {
return list;
}
public void setList(ArrayList<Equipment> list) {
this.list = list;
}
private ArrayList<Equipment> list;
Series() {
list = new ArrayList<>();
}
public void addEquipment(Equipment e) {
list.add(e);
}
public Equipment getEquipment(int idex) {
return list.get(idex - 1);
}
}
在串聯電路類中對短路和斷路的判定方法改了,如果遇見了串聯電路,則再次呼叫該方法,然後就是setVoltage()方法這是負責分壓的方法,遇見串聯電路時,和遇見其他受控裝置一樣分壓,但是要多加一點,那就是再次分壓。
然後就是本次新迭代的受控裝置——互斥開關,這個在輸入時就需要十分注意它的方向,以下是部分程式碼:
class Hswitch extends Equipment implements Comparable<Hswitch>{
Hswitch(String name)
{
this.name=name;
}
public void setHchoice(int hchoice)
{
if(hchoice%2==0)
{
Hchoice=2;
}
else
Hchoice=3;
}
private int Hchoice;
String H2;
public void setH2(String tname)
{
H2=tname;
}
String H3;
public void setH3(String tname)
{
H3=tname;
}
@Override
double getResistor() {
if(Hchoice==2)
return 5;
else
return 10;
}
@Override
public boolean IfHswitchPath(String tname)
{
if(Hchoice==2&&H2!=null&&H2.equals(tname))
{
return true;
}
else if(Hchoice==3&&H3!=null&&H3.equals(tname))
{
return true;
}
else
return false;
}
@Override
void display() {
if(Hchoice==2)
{
System.out.println("@"+name+":closed");
}
else
System.out.println("@"+name+":turned on");
}
@Override
public int compareTo(Hswitch o) {
if(this.name.compareTo(o.getName())<0)
return -1;
else
return 1;
}
}
互斥開關中有一個特殊的布林變數Hchoice,專門判斷互斥開關的觸腳1與那個觸腳相連,
其中的IfHswitchPath()方法用於判斷某條路這個互斥開關是否接通,主要用於判斷某條串聯是否斷路。
互斥開關中也實現了Comparable這個介面,在輸出是需要進行排序。
最後是本次迭代的一個新的受控裝置——受控窗簾,它只受電壓和室內光線的控制,所以判斷窗簾的開啟程度需要最後判斷,在所有分壓完成後,以下是部分程式碼:
class Curtains extends Equipment implements Comparable<Curtains>{
private int sumlux;
Curtains(String name)
{
this.name=name;
}
@Override
public void setVoltage(double c) {
voltage=c;
}
public void setSumlux(int sumlux)
{
this.sumlux=sumlux;
}
@Override
double getResistor() {
return 15;
}
@Override
void display() {
if(voltage<50||sumlux<50)
{
System.out.println("@"+name+":100%");
}
else if(sumlux>=50&&sumlux<100)
{
System.out.println("@"+name+":80%");
}
else if(sumlux>=100&&sumlux<200)
{
System.out.println("@"+name+":60%");
}
else if(sumlux>=200&&sumlux<300)
{
System.out.println("@"+name+":40%");
}
else if(sumlux>=300&&sumlux<400)
{
System.out.println("@"+name+":20%");
}
else if(sumlux>=400)
{
System.out.println("@"+name+":0%");
}
}
@Override
void close() {
voltage=0;
}
@Override
public int compareTo(Curtains o) {
if(this.name.compareTo(o.getName())<0)
return -1;
else
return 1;
}
}
其中的sumlux就是所以燈泡的光亮總和,然後和電壓一起判定就行了,這是一個比較簡單地受控裝置,
同時也同其他裝置一樣,需要實現Comparable介面,從而重寫compareTo方法,便於在最後輸出之前進行排序。
踩坑心得:
(1) 開關的閉合情況我沒有正確判斷,我之前是根據字串方法contain()方法進行判斷是否改變情況,而我對於輸入資訊中的調節開關的資訊沒有進行字串的抓取,就導致一些判斷錯誤。
例如:開關K11,遇見判斷資訊#K112也會進行調節,可是這兩個開關並不是一個,導致答案錯誤。
例如輸入:
#T1:[IN K12-1] [K12-2 D2-1] [D2-2 OUT]
#T2:[IN K123-1] [K123-2 D1-1] [D1-2 OUT]
#T3:[VCC K1-1] [K1-2 T1-IN] [T1-OUT T2-IN] [T2-OUT GND]
#K1
#K12
#K123
end
就會造成錯誤輸出:
@K1:turned on
@K12:closed
@K123:closed
@D1:0
@D2:0
因此在輸入開關的判斷資訊是就需要進行字串的抓取,
就像下面這樣:
if(Line.contains("#K"))
{
String regstr="#(K[0-9]+)";
Pattern pattern=Pattern.compile(regstr);
Matcher matcher= pattern.matcher(Line);
String name="";
if(matcher.find())
{
name=matcher.group(1);
}
changNumList.add(name);
}
這樣在比較的時候用equal()方法就不會造成錯誤。
(2) 然後是一個非常非常非常非常不該出現的錯誤,可是我又錯了,我由於有一個雙層迴圈,內層迴圈數和外層的迴圈數寫反了,導致有時候會出現null的引用,我一直以為是正規表示式出現了錯誤,找了很久很久才發現,是我寫反了,浪費了大量時間。
這件事告訴我們寫程式碼一定要耐心和細心,不然一步錯,想要回頭找出來是很艱難的過程,也很痛苦。
改進建議:
(1)程式碼結構最佳化:
- 重構程式碼,確保程式碼遵循良好的程式設計實踐,如程式碼的封裝、繼承和多型。
- 最佳化類的設計,確保每個類都有單一職責,並且職責之間保持清晰的界限。
- 使用包和類層次結構來組織程式碼,保持清晰的命名規範,方便其他人理解。
(2)效能最佳化:
-
分析程式的效能瓶頸,並採取相應的最佳化措施。
-
對於頻繁執行的計算,考慮使用更高效的演算法或資料結構。
第八次題集
設計與分析:
這次迭代新加入了二極體類,但是類與類之間的基本關係沒有變化,
基本類圖如下:
本次新增的二極體類,如果正向接入則相當於閉合開關,反向接入則相當於開關開啟,所以對於短路和斷路這些情況的特殊判定也要增加,以下是部分程式碼:
class Diode extends Equipment implements Comparable<Diode> {
private int pre;
Diode(String name, int pre) {
this.name = name;
this.pre = pre;
doidepre = pre;
}
@Override
int getRatedcurrent() {
return 8;
}
@Override
public void setVoltage(double c) {
voltage = 0;
}
@Override
double getResistor() {
return 0;
}
@Override
void display() {
if (pre == 1) {
System.out.print("@" + name + ":conduction" + " " + (int) contact1 + "-" + (int) contact2);
} else {
System.out.print("@" + name + ":cutoff" + " " + (int) contact1 + "-" + (int) contact2);
}
if (Ifexceed) {
System.out.println(" exceeding current limit error");
} else {
System.out.println();
}
}
@Override
public int compareTo(Diode o) {
if (this.name.compareTo(o.getName()) < 0)
return -1;
else
return 1;
}
}
其中變數pre就是前驅觸腳,根據輸入資訊確定前驅觸腳,然後在進行判斷是否斷開。
然後是電流的限制,就在電路裝置類中都加入了一個方法getRatedcurrent(),用來獲取額定電流,並透過方法Ifexceed分流,從而確定每一個電器是否超出限制。
以下是方法程式碼:
public void Ifexceed(double current) {
for (int i = 0; i < list.size(); i++) {
Equipment e = list.get(i);
if (e instanceof Parallel) {
e.Ifexceed(current);
} else if (e instanceof Series) {
e.Ifexceed(current);
} else if (e instanceof Hswitch) {
if (e.IfHswitchPath(this.name) && current > e.getRatedcurrent()) {
e.Ifexceed = true;
}
} else {
if (current > e.getRatedcurrent()) {
e.Ifexceed = true;
} else
e.Ifexceed = false;
if(e instanceof Diode)
{
if(current==0)
{
e.Ifdiode=false;
}
else
{
e.Ifdiode=true;
}
}
}
}
}
對每一條支路進行分流,確定它的電流,串聯電路電流相等。
然後是管腳電壓的計算,首先確定總路的電壓,然後確定·總路中所有裝置(當然也包括並聯和串聯等)的電壓,
然後依次減去,可以得到每個用電器兩端的電壓,如果是並聯或者串聯,則繼續呼叫相應方法。
主要判斷短路和斷路的情況,其中斷路是還要考慮斷開的裝置的觸腳電壓可能是0,這需要額外判斷。
同時注意這次題目將受控窗簾的預設情況改了,和上次不一樣。
以下是計算的部分程式碼:
public void footvoltage(double v, double v1) {
~~~
double total = v;
for (int i = 0; i < list.size(); i++) {
Equipment e = list.get(i);
if (e instanceof Governor || e instanceof ContinueGovernor)
continue;
else if (e instanceof Series) {
e.footvoltage(total, total - e.getVoltage());
total -= e.getVoltage();
} else if (e instanceof Parallel) {
e.footvoltage(total, total - e.getVoltage());
total -= e.getVoltage();
} else if (e instanceof Hswitch) {//有問題
if (e.ifhswitch) {
e.contact1 = total;
if (e.IfHswitchPath2(this.name)) {
e.contact2 = total - e.getVoltage();
} else {
e.contact3 = total - e.getVoltage();
}
total -= e.getVoltage();
} else {
if (e.IfHswitchPath2(this.name)) {
e.contact2 = total;
e.contact1 = total - e.getVoltage();
} else {
e.contact3 = total;
e.contact1 = total - e.getVoltage();
}
total -= e.getVoltage();
}
} else {
if (e.Ifrigth) {
e.contact1 = total;
e.contact2 = (total - e.getVoltage());
total -= e.getVoltage();
} else {
e.contact2 = total;
e.contact1 = (total - e.getVoltage());
total -= e.getVoltage();
}
}
}
}
這只是正常的情況,斷路和短路的程式碼過於繁瑣,就不展示了。
最後還有一個短路檢測,這個就很簡單了,只有直接判斷總路是不是短路,如果是直接輸出就行,然後return。
if (mainPathway.Ifshort())//短路
{
System.out.println("short circuit error");
return;
}
踩坑心得:
這次題集難度很大,特殊情況也很多,所以真的踩了很多坑,以下是幾個重點的坑:
(1) 首先是讀題沒有仔細看,想當然的以為窗簾這些受控電器沒有變化和上次一樣,結果它改了,預設情況改成了全開。
導致錯了一個測試點,最後仔細看題終於發現了。
(2) 還有就是電路的電壓觸腳沒有弄清楚,高中電路沒有學好,如果並聯的一條電路斷路了,它的觸腳電壓可能為0,如果
他有多個斷開的裝置,則開頭和結尾的斷開裝置中間的所有電器的觸腳都是0。
例如輸入:
#T1:[IN K1-1] [K1-2 OUT]
#T2:[IN K2-1] [K2-2 K3-1] [K3-2 B2-1] [B2-2 OUT]
#M1:[T1 T2]
#T3:[VCC M1-IN] [M1-OUT B1-1] [B1-2 GND]
#K1
end
錯誤輸出:
@K1:closed 220-220 exceeding current limit error
@K2:turned on 220-0
@K3:turned on 0-220
@B1:200 220-0 exceeding current limit error
@B2:0 0-0
正確的輸出:
@K1:closed 220-220 exceeding current limit error
@K2:turned on 220-0
@K3:turned on 0-220
@B1:200 220-0 exceeding current limit error
@B2:0 220-220
(3) 如果並聯電路短路,則每條短路的電路均分電流,其他電路電流為0。
我下意識以為只會有一條短路電流,所有第一條短路會分全部電流,其他的則全部是0。
這就會導致電路裝置是否超出電路限制做出影響。
例如輸入:
#T1:[IN K1-1] [K1-2 OUT]
#T2:[IN K4-1] [K4-2 OUT]
#T4:[IN K3-1] [K3-2 OUT]
#M1:[T1 T2 T4]
#T3:[VCC K2-1] [K2-2 M1-IN] [M1-OUT B1-1] [B1-2 GND]
#K1
#K3
#K2
end
我的錯誤輸出:
@K1:closed 220-220 exceeding current limit error
@K2:closed 220-220 exceeding current limit error
@K3:closed 220-220 exceeding current limit error
@K4:turned on 220-220
@B1:200 220-0 exceeding current limit error
正確輸入為:
@K1:closed 220-220
@K2:closed 220-220 exceeding current limit error
@K3:closed 220-220
@K4:turned on 220-220
@B1:200 220-0 exceeding current limit error
改進建議:
(1)程式碼結構最佳化:
- 重構程式碼,確保程式碼遵循良好的程式設計實踐,如程式碼的封裝、繼承和多型。
- 最佳化類的設計,確保每個類都有單一職責,並且職責之間保持清晰的界限。
- 使用包和類層次結構來組織程式碼,保持清晰的命名規範,方便其他人理解。
(2)效能最佳化:
-
分析程式的效能瓶頸,並採取相應的最佳化措施。
-
對於頻繁執行的計算,考慮使用更高效的演算法或資料結構。
-
在寫程式碼時,加入多一些錯誤異常處理,這可以很好的幫助除錯程式碼,發現錯誤。
總結
在本次家居強電電路模擬程式的迭代中,我主要關注了以下幾個方面的改進:
- 電路複雜度的提升:我們引入了更復雜的電路結構,如多個串聯的並聯電路和包含串聯電路的並聯電路。這樣的設計使得程式能夠更真實地模擬現實生活中的電路佈局。
- 新功能的加入:在第七次迭代中,我們增加了互斥開關和受控窗簾的功能。這些新功能的加入使得程式更加貼近實際應用,併為使用者提供了更多的操作可能性。
- 程式碼結構的最佳化:在程式碼設計方面,我們採取了模組化設計、使用設計模式、文件和註釋等措施,以提高程式碼的可讀性和可維護性。
- 效能最佳化和錯誤處理:在第八次迭代中,我們最佳化了程式的效能,並引入了電流限制和短路檢測等錯誤處理機制。這些改進使得程式更加健壯和可靠。
總的來說,這幾次迭代確實很有鍛鍊效果,我能明顯感覺到我的程式碼除錯能力增強了,遇到錯誤會不斷的測試,找到錯誤,然後修改。
我明白了持續學習的重要性。在未來專案開發過程中,我們可能遇到了許多新問題和挑戰。為了找到解決方案,我不得不查閱相關資料,學習新的知識和技能。這種持續學習的過程讓我不斷進步,也讓我意識到只有不斷學習,才能適應不斷變化的技術環境。
此外,我認識到程式設計不僅僅是一門技術,更是一種解決問題的能力。在專案開發過程中,我們需要面對各種各樣的技術難題。透過不斷嘗試和思考,我們找到了解決問題的方法。這種解決問題的能力讓我更加自信,也讓我明白了程式設計的價值所在。
最後,我感激這幾次PTA給我帶來的成長和收穫。在這個過程中,我提高了自己的程式設計技能,還收穫了豐富的經驗。這些經驗和技能將對我未來的學習和職業發展產生深遠的影響。