OOP第三次Blog作業

Linmo10發表於2024-06-28

前言

距離上一次寫Blog作業已經過去差不多一個月了,但在這段時間之中我與程式碼的交鋒無時無刻不在進行,先不說結果怎麼樣,單就這過程就值得人細細琢磨,並且令人印象深刻。當然,經過這一段時間艱苦的磨練,我也學到了許多之前不曾瞭解的東西複習鞏固了已經學過的知識點,我相信我的程式設計能力也會有所提升,同時,他們都說寫程式碼最考驗的就是耐心,我覺得確實如此,有的時候某一個或某幾個測試點過不了就會比較影響心情,然後就會想著把它改正確,這過程需要不斷的debug,這麼就沒鍛鍊耐心呢?不過話說回來,無論學哪一個科目,耐心都是必不可少的!
下面開始7~8次P他的總結性報告:

  • 所涉及到的知識點:
  1. List的應用
  2. 正規表示式
  3. HashMap、setMap等
  4. 簡單工廠模式的應用
  5. 繼承與多型
  6. 介面的靈活運用
  7. 有關電路知識的考查
  • 題量:
    7~8次的pta練習每次都僅僅有一道題目,but!你以為每次一道題目就很好寫完嗎?就會很快寫完嗎?大錯特錯!這裡的一道題目考察了多方面知識的靈活運用。
  • 難度:
    前面提到題量不多,但考察的內容多,這無疑會增加題目的難度,這兩次的PTA考查的深度較之前確實大有增加,而且題目的測試點考慮的情況也是多方面的,但是依然有同學能拿到滿分!

設計與分析

家居強電電路模擬程式三

nchu-software-oop-2024-上-7
這次的迭代題目集相較於第二次迭代有了以下新增內容:

  1. 互斥開關

互斥開關有3個引腳:1個是彙總引腳,另兩個是分支引腳。

開關電路示意圖如圖1所示,左邊是彙總引腳,編號為1;右邊兩個是分支引腳,右上的輸出引腳為2,右下輸出引腳為3。圖中1、2、3引腳均可以是輸入引腳,當1為輸入引腳時,2、3引腳為輸出引腳;1為輸出引腳時,2、3引腳為輸入引腳。

互斥開關只有兩種狀態:開關接往上面的2號引腳、接往下面的3號引腳。開關每次只能接通其中一個分支引腳,而另一個分支引腳處於斷開狀態。

互斥開關的預設狀態為1、2引腳接通,1、3引腳斷開。

圖1中所示的互斥開關可以反過來接入電路,即彙總引腳接往接地端,兩個分支引腳接往電源端。
為避免短路,互斥開關設定了限流電阻,12引腳之間預設電阻為5,13引腳之間預設電阻為10。
image
2. 受控窗簾
受控窗簾的電路符號為S,其最低工作電壓為50V,電壓達到或超過50V,窗簾即可正常工作,不考慮室外光照強度和室內空間大小等因素,窗簾受室內燈光的光照強度控制。窗簾電阻為15
當電路中所有燈光的光照強度總和在[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,窗簾處於全開狀態。

  1. 電路連線
    本次迭代考慮多個並聯電路串聯在一起的情況。

本題考慮一條串聯電路中包含其他串聯電路的情況。例如:

#T3:[VCC K1-1] [K1-2 T2-IN] [T2-OUT K2-1] [K2-2 T1-IN] [T1-OUT GND]

本例中T1\T2兩條串聯電路T3的一個部分,本題考慮這種型別的輸入。

  • 類圖如下:
    image
    從這張類圖中可以看到一共有16個類,相較於上次迭代的14個類,這次增加了互斥開關類和受控窗簾類,互斥開關類的設計和應用都是蠻難的,因為互斥開關有三個引腳,而且不同的引腳可能出現在不同的串聯電路中,對應互斥開關的不同情況,串聯電路的連通情況可能不相同,為此,我在串聯電路類中新增了一個屬性,代表該串聯電路是對應互斥開關的第幾個引腳,然後在判斷串聯電路是否連通時也做了一些修改:
    image
    透過判斷串聯電路的引腳和互斥開關的引腳是否相等來判斷其是否連通。當然,這就需要在儲存互斥開關相關資訊的時候獲取其引腳:
    image
  • SourceMonitor生成報表:
    image
    ennnnnn從圖中看來,相較於上次的最大進步就是註釋的比例,已經達到了預期範圍。不過最大圈複雜度還是超過了預期的範圍,看來以後還是要儘量少用點if-else等對圈複雜度貢獻較大的語句啊。由此看來學習程式設計之路任重而道遠啊!!!
  • 踩坑心得:
    做題之前要認真分析題目!(儘管題目實在是太長了image還是要認真看!
    )就比如這次題目,剛開始的時候,對於這次迭代我還是隻注意到了互斥開關和受控窗簾,後來才發現電路連線方面還有變化,於是做了如下修改:
    image
    就是串聯中可能還會有串聯的情況,我是把裡面一層串聯中的電氣裝置都放到外面一層的串聯中。
  • 改進建議
  1. if-else可以少用,這樣可以提高程式碼質量。
  2. 並聯中應該考慮有三層串聯一起並聯的情況。(我當時沒有考慮這種情況,所以並沒有得滿分,老師設定測試點時考慮的情況還是很全面的! )
家居強電電路模擬程式八

nchu-software-oop-2024-上-6
這次迭代可謂是發生了巨大變化,不僅電器增加了二極體,就連輸出都有很大變化,要輸出每個引腳的電流,和每個電器的電壓,以及電路中的電流是否超過最大電流時輸出情況也有所不同:

  1. 新增的電器二極體:

增加二極體元件,其電路特性為:正向導通,反向截止;其電器符號如圖4所示,當電流從左至右流過時,二極體導通”conduction”,電阻為0;電流從右至左流動時,二極體截止”cutoff”,電阻無窮大,相當於開關開啟。

image

圖2 二極體符號

二極體的識別符號為’P’,左側管腳編號為1,右側管腳編號為2。

二極體如果兩端電壓相等,沒有電流流過,分以下兩種情況輸出:
a、如果兩端電壓為0,二極體的導通/截止狀態由接入方向決定,1號引腳靠近電源則狀態為導通,反之為截止。
b、如果兩端電壓不為0,二極體導通。
2. 輸出格式:
按開關、分檔調速器、連續調速器、白熾燈、日光燈、吊扇、互斥開關、受控窗簾、二極體(見第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%
3. 增加管腳電壓的顯示
在輸出每個電器的狀態資訊後,再依次輸出該電器每個管腳的電壓。(格式詳見輸出資訊部分)
4. 電流限制
電器在工作時,過大的電流會引起電器過熱,從而燒壞電路。本次迭代,每個元器件都有最大電流的設定,當實時電流超過最大電流時,在該電器輸出資訊的最後加入提示“exceeding current limit error”,與前面的資訊之間用英文空格分隔。

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

本題各類電器的最大限定電流如下:

開關20、分檔調速器18、連續調速器18、白熾燈9、日光燈5、吊扇12、落地扇14、互斥開關20、受控窗簾12、二極體8。

  1. 短路檢測
    如果電路出現無窮大的電流造成短路,所有元器件資訊不輸出,僅輸出提示“short circuit error”
  2. 並聯電路中包含並聯
    本次迭代考慮並聯電路中包含並聯電路的情況,即構成並聯電路的串聯電路可以包含別的並聯電路。例如如下輸入的電路,並聯電路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]
  1. 本題包含以下電路圖中的所有連線情況:
    image
  • 類圖如下:
    image
    這次多增加了一個二極體類。由於這次輸出的結果相較於之前有了較大的改變,需要得出電路中的電流,電器各個引腳的電壓,所以增加了方法:
public void getpower(T t,double input,double output){
        if(t.getRes()==0){
            for(int i=0;i<t.getList().size();i++) {
                if (t.getList().get(i).getId().contains("K")) {
                    t.getList().get(i).setPin1(input);
                    if(t.getList().get(i).getState().equals("closed")){
                        t.getList().get(i).setPin2(input);
                    }else {
                        break;
                    }
                }
                else if(t.getList().get(i).getId().contains("H")){
                    int g=t.getA();
                    if(g==2){
                        t.getList().get(i).setPin2(input);
                    }
                    if(g==3){
                        ((MutexSwitch)t.getList().get(i)).setPin3(input);
                    }
                    else{
                        t.getList().get(i).setPin1(input);
                    }
                } else if (t.getList().get(i).getId().contains("P")) {
                    if( ((Diode)t.getList().get(i)).getState().equals("cutoff")){
                        t.getList().get(i).setPin2(input);
                        input=0;
                    }
                    else{
                        t.getList().get(i).setPin1(input);
                        t.getList().get(i).setPin2(input);
                    }
                } else if (t.getList().get(i).getId().contains("M")) {
                    for(int k=0;k<((M)t.getList().get(i)).getList().size();k++){
                        getpower(((M)t.getList().get(i)).getList().get(k),input,0);
                    }

                } else{
                    t.getList().get(i).setPin1(input);
                    t.getList().get(i).setPin2(input);
                }
            }
        }else{
            double pindif=input-output;
            double ele=pindif/t.getRes();
            for(int i=0;i<t.getList().size();i++){
                if(!(t.getList().get(i).getId().contains("M")))
                    t.getList().get(i).setEle(ele);
            }
            for(int i=0;i<t.getList().size();i++){
                if(!(t.getList().get(i).getId().contains("M"))){
                    if(t.getList().get(i).getId().contains("H")){
                        int p=t.getA();
                        if(p==1){
                            t.getList().get(i).setPin1(input);
                        } else if (p==2) {
                            t.getList().get(i).setPin2(input);
                        } else if (p==3) {
                            ((MutexSwitch)t.getList().get(i)).setPin3(input);
                        }
                        input = input - ele * t.getList().get(i).getRes();
                    }else {
                        t.getList().get(i).setPin1(input);
                        input = input - ele * t.getList().get(i).getRes();
                        t.getList().get(i).setPin2(input);
                        if(t.getList().get(i).getId().contains("S")){
                            ((Curtain)t.getList().get(i)).getS(getall(tmo));
                        }
                    }
                }
                else if(t.getList().get(i).getId().contains("M")){
                    for(int k=0;k<((M)t.getList().get(i)).getList().size();k++){
                        double pindif1=t.getList().get(i).getRes()*ele;
                        double output1=input-pindif1;
                        getpower(((M)t.getList().get(i)).getList().get(k),input,output1);
                    }
                    input=input-t.getList().get(i).getRes()*ele;
                }
            }
        }

    }

同時判斷某串聯電路是否是通路也有所不同,這次不僅僅只看開關是否關閉,二極體接入電路的方向也要考慮:

public boolean istrue(T t){
        boolean flag=true;
        for(int i=0;i<t.getList().size();i++){
            if(t.getList().get(i).getId().contains("K")){
                if(t.getList().get(i).getState().equals("turned on")){
                    flag=false;
                    break;
                }
            }
            if(t.getList().get(i).getId().contains("H")){
                if((t.getA()==2)&&(((MutexSwitch)t.getList().get(i)).getA()==3)){
                    flag=false;
                    break;
                }
                if(t.getA()==3&&(((MutexSwitch)t.getList().get(i)).getA()==2)){
                    flag=false;
                    break;
                }
            }
            if(t.getList().get(i).getId().contains("P")){
                if(((Diode)t.getList().get(i)).getState().equals("cutoff")){
                    flag=false;
                    break;
                }
            }
            if(t.getList().get(i).getId().contains("M")){
                int p=0;
                for(int j=0;j<((M)t.getList().get(i)).getList().size();j++){
                    if(istrue(((M)t.getList().get(i)).getList().get(j)))
                        p++;
                }
                if(p==0){
                    flag=false;
                    break;
                }
            }
        }
        return flag;
    }
  • SourceMonitor生成報表:
    image
    哎~這次還是有問題,還是最大圈複雜度!但是呢,有的情況是真的避免不了啊,就比如解析輸入字串,看來,還需要找更好的方法來解決這個問題。
  • 踩坑心得:
    計算電路中電阻還是挺麻煩的,所以後來我在串聯電路類,並聯電路類中分別寫了一個計算電阻的函式:
    串聯電路:
public double getRes(){
        double all=0;
        if(istrue(this)) {
            for (int i = 0; i < list.size(); i++) {
                all = all + list.get(i).getRes();
            }
        }
        return all;
    }

並聯電路:

 public double getRes(){
        double all=0;
        for(int i=0;i<list.size();i++){
            if(istrue(list.get(i))) {
                all = all + (1 / list.get(i).getRes());
            }
        }
        return 1/all;
    }
  • 改進建議:
    這次的得分不是很高,後來我看了下,有一部分原因出在電器中引腳的電壓值,就比如白熾燈,它兩個引腳無論正接還是反接,效果都是一樣的,但是引腳的電壓值卻不同,而我在解析輸入的時候並沒有判斷是不是正接,也就是說我在儲存的時候預設是正接,這導致後來輸出每個引腳電壓值的時候可能會出現相反的結果,所以,如果要改進的話我覺得可以在解析輸入的時候判斷一下電氣裝置的引腳的輸入順序。