第三次blog
一.前言
7-8次大作業對前幾次的大作業的設計進行了進一步的迭代,第七次大作業加入了並聯串並聯和串聯套串聯的情況,並且加入了相對比較麻煩的互斥開關,和一個受光窗簾;但是第八次大作業卻是真正的大boss,我寫了將近四個多小時才寫到36分,前面有幾次三小時就可以滿分了,並且因為最近到了考試周了而我很多科目說實話並沒有太大的把握所有我多花了一些時間給其他的科目和一些其他的原因導致的對這次大作業寫的不願意導致第八次大作業我給的時間沒有很多也導致了分不是很高。對於題量來說吧第七次和第八次簡直不是一個量級的,第七次花了我差不多三小時就接近滿分了(最後三分的錯誤寫第八次大作業的時候才發現,是沒有考慮窗簾在支路的情況),而第八次大作業四小時才斬獲36分,還有很多考慮的地方還沒寫進去,就已經寫了將近1500行了。難度也是第八次大作業最難.難寫。
二,大作業與程式碼分析
1,第七次大作業
第七次大作業相較於第六次大作業加入了互斥開關,窗簾,串聯套串聯的情況,總體較麻煩的是互斥開關,為了處理這個我將互斥開關看做是兩個獨立但是同時只能存在一個開啟的開關去處理,下面列舉一些相關程式碼
class Huchi extends Controler{ private int rank=0; private double R2=5; private double R3=10; private ArrayList<KaiGuan> kg=new ArrayList<>(); public Huchi(String name) { super(name); kg.add(new KaiGuan("er")); kg.add(new KaiGuan("san")); kg.get(0).changeCondition(); kg.get(0).setR(5); kg.get(1).setR(10); } public void changeCondition(){ kg.get(0).changeCondition(); kg.get(1).changeCondition(); } public ArrayList<KaiGuan> getKg() { return kg; } public double getR2(){ return R2; } public double getR3(){ return R3; } public int getRank() { return rank; } }
這是我設計的互斥開關類,其中包含了兩個開關與他們自帶的阻值,其中的rank是後面用於排序的,我前面也談到過,我在裡面還設計了一些方法比如互斥開關的改變等以處理互斥開關相關的事宜。
else if(c[0].startsWith("H")){ if(c[1].equals("1")) { x = e[j + 1].split(" ")[0].split("-"); boolean h = false; Huchi H = new Huchi(c[0]); for (int k = 0; k < QIKU.size(); k++) { if (QIKU.get(k).getName().equals(c[0])) { H = (Huchi) QIKU.get(k); h = true; break; } } if (h == false) { QIKU.add(H); } ArrayList<KaiGuan> kg = H.getKg(); if (x[1].equals("2")) { line.add(kg.get(0)); } else if (x[1].equals("3")) { line.add(kg.get(1)); } }else{ boolean h = false; Huchi H = new Huchi(c[0]); for (int k = 0; k < QIKU.size(); k++) { if (QIKU.get(k).getName().equals(c[0])) { H = (Huchi) QIKU.get(k); h = true; break; } } if (h == false) { QIKU.add(H); } ArrayList<KaiGuan> kg = H.getKg(); if (c[1].equals("2")) { line.add(kg.get(0)); } else if (c[1].equals("3")) { line.add(kg.get(1)); } } } }
考慮到互斥開關具有很強的可變性列如可以正接也可以反接,可以將二節點放在上面也可以將二節點放在下面所以對於它的輸入我單獨考慮了很多東西也導致它的輸入程式碼挺長,主要思路就是先判斷它是正接還是反接,然後判斷接的是二節點還是三節點,再進行相關的處理。
class SkChuanglian extends Equipment{ private int rank=-1; private double R=15; private double sumlux=0; private double openrate=100; public SkChuanglian(String name) { super(name); } public double getR(){ return R; } public int getRank() { return rank; } public void getNowOpenrate(ArrayList<Facility> ku) { for (int i = 0; i < ku.size(); i++) { if(ku.get(i) instanceof BaiChi){ sumlux=sumlux+((BaiChi)ku.get(i)).getBrightness(); }else if(ku.get(i) instanceof RiGuang){ sumlux=sumlux+((RiGuang)ku.get(i)).getBrightness(); } } if(sumlux>=0&&sumlux<50){ openrate=100; }else if(sumlux>=50&&sumlux<100){ openrate=80; }else if(sumlux>=100&&sumlux<200){ openrate=60; }else if(sumlux>=200&&sumlux<300){ openrate=40; }else if(sumlux>=300&&sumlux<400){ openrate=20; }else { openrate=0; } } public double getOpenrate() { return openrate; } }
還有就是受控窗簾,受控窗簾這個點並不是非常的難,他的處理應該放在所有用電器處理完之後,或者放在所有燈類用電器處理完之後。上面是我對受控窗簾類的設計,沒有什麼特殊的
for (int i = 0; i < QIKU.size(); i++) { if(QIKU.get(i) instanceof SkChuanglian){ SkChuanglian a=(SkChuanglian) QIKU.get(i); a.getNowOpenrate(QIKU); } }
這是在所有用電器處理完之後對於受控窗簾的處理,起算它的開合程度
而對於串聯套串聯,直接把串聯當做一個用電器連在電路里就好了,再對於這個串聯原件設計一個遞迴方法來處理相關問題,這裡就不進行程式碼演示了
總的來說這次大作業的難度中等,比較容易犯錯的地方就是互斥開關的反接和串聯套串聯的情況,還有就是受控窗簾的處理一定要放到最後來進行處理,這次寫的時候也忘了窗簾還可以放在支路里所以進行支路輸入的時候沒有判斷窗簾的情況導致這次沒有滿分,以後思維要更加嚴謹一點
下面放一下類圖
可以看出類還是比較多的
以及類的複雜度,可以看出對於其他類複雜度是比較合適的2,而對於工具類因為其擔任了對於電路的各種操作,所以其的複雜度也是超了挺多的,也可以看出tool類也是可以進行一定的最佳化的。
2,第八次大作業
說實話第八次大作業的難度應該相比較於前幾次大作業應該是斷崖式的增長,從最後的排名也可以看得出來,排名第一的孩子也沒有斬獲滿分的好成績,側面也是反應了這次大作業的無比棘手,從我對於周圍人的瞭解來說這次大作業也耗費了他們很多的時間。
這次大作業相較於前一次加入的東西就比較多了,包括什麼二極體,引腳電壓,還有什麼過載情況,相應的,對於這次的程式碼改進也會相應多很多,這次加入了一些相當麻煩的東西,比如引腳電壓的輸出,引腳電壓的獲取是相對於比較麻煩的,並且前幾次對於用電器的處理用分壓就好了根本用不上引腳導致很多人都沒有進行相關的處理,而這次的加入顯然就要在程式碼里加點東西了,並且有一些比較噁心的點就是對於斷了的電路居然還能有電壓傳遞,這是令我感覺到比較抽象的,沒有迴路的存在還能傳遞電壓有點違反我高中學的物理常識,所以我開始寫的時候並沒有考慮這點,還是看樣例的時候才發現的。
對於二極體來說一開始我的確給他單獨的建立了一個類去處理它,但是我寫著寫著發現好像這個二極體完全符合開關的一切屬性,正著代表著開關的閉合,反著接就代表著開關的開啟,而且這個玩意兒的開啟關閉是不會變的,所以嚴格意義上來說它更加易於處理,於是我就使用開關類來進行處理了,只是在輸出的時候根據名字來判斷是輸出開關的結果還是輸出二極體的結果
f (QIKU.get(i) instanceof KaiGuan) { KaiGuan a = (KaiGuan) QIKU.get(i); if (a.getName().startsWith("K")) { if(a.getelI()>=a.getI()) { if (a.getCondition() == 0) { result.add("@" + a.getName() + ":turned on" + " " + (int)a.getBegin() + "-" + (int)a.getEnd()); } else { result.add("@" + a.getName() + ":closed" + " " + (int)a.getBegin() + "-" + (int)a.getEnd()); } }else{ if (a.getCondition() == 0) { result.add("@" + a.getName() + ":turned on" + " " + (int)a.getBegin() + "-" + (int)a.getEnd()+guozai); } else { result.add("@" + a.getName() + ":closed" + " " + (int)a.getBegin() + "-" + (int)a.getEnd()+guozai); } } } else { if(a.getI()<=a.getlI()) { if (a.getCondition() == 0) { result.add("@" + a.getName() + ":cutoff" + " " + (int)a.getBegin() + "-" + (int)a.getEnd()); } else { result.add("@" + a.getName() + ":conduction" + " " + (int)a.getBegin() + "-" + (int)a.getEnd()); } }else{ if (a.getCondition() == 0) { result.add("@" + a.getName() + ":cutoff" + " " + (int)a.getBegin() + "-" + (int)a.getEnd()+guozai); } else { result.add("@" + a.getName() + ":conduction" + " " + (int)a.getBegin() + "-" + (int)a.getEnd()+guozai); } } } }
因為這次輸出加入了過載的情況,而開關和二極體又都有兩種輸出情況,所以達到了整整八種情況,所以看起來還是比較多的,還有就是引腳的處理,引腳的處理得分情況來處理,在一般電路里的處理還是比較好寫的,在之前的元器件處理方法程式碼里加上對於上一個用電器的尾引腳的電壓索取和根據自己分壓來給自己的尾引腳來賦值電壓,麻煩的一個是在已斷電路的引腳電壓賦值,另一個就是對於反接元器件的處理,因為我對於用電器的處理開始是沒有考慮反接情況的,導致反接後輸出的兩個引腳的電壓是反著的。
先來聊聊第一種情況,斷路的引腳電壓賦值,先給大家看一看我這部分的程式碼
else{ for (int i = 1; i < rline.size() - 1; i++) { if (rline.get(i) instanceof FenDuanControler) { continue; } else if (rline.get(i) instanceof LianXuControler) { continue; } else if(rline.get(i) instanceof KaiGuan){ KaiGuan a=(KaiGuan) rline.get(i); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin() - zv * (a.getR() / zR)); }else if(rline.get(i) instanceof SkChuanglian){ SkChuanglian a=(SkChuanglian) rline.get(i); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin()); }else if (rline.get(i) instanceof BaiChi) { BaiChi a = (BaiChi) rline.get(i); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin()); } else if (rline.get(i) instanceof RiGuang) { RiGuang a = (RiGuang) rline.get(i); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin()); } else if (rline.get(i) instanceof DiaoFan) { DiaoFan a = (DiaoFan) rline.get(i); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin()); } else if (rline.get(i) instanceof LuoDiFan) { LuoDiFan a = (LuoDiFan) rline.get(i); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin()); } else if (rline.get(i) instanceof BingLine) { BingLine a = (BingLine) rline.get(i); setBing(a, zv * (a.getR() / zR)); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin()); } else if (rline.get(i) instanceof ChuanLine) { ChuanLine a = (ChuanLine) rline.get(i); setChuan(a, zv * (a.getR() / zR)); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin()); } }
大家也可以看到前面有個“else”這是因為前面的if是用來判斷這個電路是否“死亡”,我會給每個開關斷開的電路附加“死亡”的屬性,所以加個else,而為了給這裡的引腳賦值我對於用電器處理的方法長度幾乎翻了一倍,導致我寫的十分難受,因為我想寫一些新的東西,而不是複製我的程式碼為了達到目的使其變得更加複雜(也可能是我沒有想到更好的方法),也是寫到這使我對於這次大作業的寫的慾望消減了很多,還有就是如果是並聯裡的支路出現這種情況也很難受,因為需要先給第一個用電器賦值再進行後面的引腳賦值。
其次就是反接。
反接對於我的程式碼我並沒有加進去,因為我那是還有點其他事導致時間不夠多了,而我想我加上反接估計也加不了多少分所以我就沒寫了,所以這裡我就只談一下我的思路
對於反接的元器件,我如果檢測到他是反接的,我會賦予它一個反接值,到最後輸出的時候我會根據這個反接值判斷他是否反接,若是反接我就先輸出它的尾再輸出他的頭。
隨後便是過載的問題,這裡有一個小情況便是最好來根據電路來計算電流,因為如果根據分壓來計算電流的話,開關等一些沒有電壓的電器是計算不了電流的,沒有電流的賦值是根本不能判斷,所以要計算整條電路的電流然後賦給這條電路的每一個電器
ouble zR = 0; double zI=0; for (int i = 0; i < rline.size(); i++) { zR = zR + rline.get(i).getR(); } if (zR == 0) { System.out.println("short circuit error"); System.exit(0); } if(exist) { zI=zv/zR; for (int i = 1; i < rline.size() - 1; i++) { rline.get(i).setI(zI); if (rline.get(i) instanceof FenDuanControler) { continue; } else if (rline.get(i) instanceof LianXuControler) { continue; } else if(rline.get(i) instanceof KaiGuan){ KaiGuan a=(KaiGuan) rline.get(i); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin() - zv * (a.getR() / zR)); }else if(rline.get(i) instanceof SkChuanglian){ SkChuanglian a=(SkChuanglian) rline.get(i); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin() - zv * (a.getR() / zR)); }else if (rline.get(i) instanceof BaiChi) { BaiChi a = (BaiChi) rline.get(i); a.getNowBrightness(zv * (a.getR() / zR)); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin() - zv * (a.getR() / zR)); } else if (rline.get(i) instanceof RiGuang) { RiGuang a = (RiGuang) rline.get(i); a.getNowBrightness(zv * (a.getR() / zR)); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin() - zv * (a.getR() / zR)); } else if (rline.get(i) instanceof DiaoFan) { DiaoFan a = (DiaoFan) rline.get(i); a.getNowSpeed(zv * (a.getR() / zR)); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin() - zv * (a.getR() / zR)); } else if (rline.get(i) instanceof LuoDiFan) { LuoDiFan a = (LuoDiFan) rline.get(i); a.getNowSpeed(zv * (a.getR() / zR)); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin() - zv * (a.getR() / zR)); }else if (rline.get(i) instanceof BingLine) { BingLine a = (BingLine) rline.get(i); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin() - zv * (a.getR() / zR)); if (a.getR() == 0) { continue; } else { setBing(((BingLine) rline.get(i)), zv * (a.getR() / zR)); } } else if (rline.get(i) instanceof ChuanLine) { ChuanLine a = (ChuanLine) rline.get(i); a.setBegin(rline.get(i - 1).getEnd()); a.setEnd(a.getBegin() - zv * (a.getR() / zR)); if (a.getR() == 0) { continue; } else { setChuan(((ChuanLine) a), zv * (a.getR() / zR)); } } } rline.get(rline.size() - 2).setEnd(0); for (int i = 0; i < QIKU.size(); i++) { if (QIKU.get(i) instanceof SkChuanglian) { SkChuanglian a = (SkChuanglian) QIKU.get(i); a.getNowOpenrate(QIKU); } } }
這是我對於電路的處理方法,裡面可以看出是先算出這條電路的總電阻,然後算出這條電路的總電流,然後根據迴圈賦予給電路的每一個電器,同時在迴圈中也會計算每個電器的狀態和給每個電器的引腳賦值
總的來說這次大作業的難度較高並且我自己沒有規劃好自己的時間導致我這次沒有拿到理想成績,我也會反思自己,改掉自己的一些壞毛病。
下面放一下類圖
也是可以看出比上一次大作業複雜了很多,無論是方法還是類