南昌航空大學大一下學期java-題目集1~3總結性Blog——蘇禮順23201608

苏礼顺-23201608發表於2024-04-20

一、前言

——總結三次題目集的知識點、題量、難度等情況

  《物件導向程式設計》這一門課,是教授我們設計程式碼,掌握類、類間關係,以及物件導向的三大設計原則——封裝、繼承、多型等物件導向的基本概念和方法,並以物件導向的程式語言java語言設計程式。因此在這三次的題目集都與類的設計與使用有關。

  這三次題目集目前僅涉及“封裝繼承多型”三大特性中的“封裝”,儘管如此,題目集中的題目還是有一定的難度。並且三次題目集對於類的知識點涵蓋極廣,包括但不限於類的宣告,建立,使用方法,類的構造方法,成員變數,成員方法的定義與使用方法。還有java語言中包的概念,以及papckage,import語句的使用,類中的組合、聚合、依賴、關聯關係,java中方法的過載的實現方式等。

  題目集一有五題,題目集二四題,題目集三三題。題目難度逐漸遞增。值得一提的是:每次題目集的最後一題都是“答題判斷程式”有關的題目。輸入的內容包括:題目內容,試卷內容,刪除題目等等,最後要求實現模擬小型測試,按要求輸出判斷結果。三次題目逐漸迭代,設計的類逐漸增多,可實現的功能也逐漸增多。目前沒有增加繼承與多型,但是後續的此題迭代則會依次增加。題目具有一定挑戰度,同時也是對我們類的掌握程度的考驗!!

二、設計與分析

——主要是對題目以及自己提交的原始碼進行分析,加上自己淺淺的解釋和心得

(一)題目集一

題目一二都是對類的簡單使用,除了主類之外,其他的類只有一個,且都是實體類只要按照題目要求,定義適當的類的屬性與方法就可以解決問題。特別地,在使用toString方法的時候,它的返回型別只能是String型別。

題目三四則是關於計算成績統計類的題目。第三題透過迴圈依次讀入資訊,再進行處理與輸出。第四題設計了Score類與Student類。Score類放了平時成績與期末成績,Student類與Score類是關聯關係,一個學生對應他自己的語文、數學、物理成績。這題自己的出彩之處在於Main裡面的對資料的讀入的處理方法,兩層迴圈,減少了寫讀入語句的次數。見如下程式碼:

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        for(int  i = 0; i < 3; i++) {       
        	String id = in.next();
            String name = in.next();
            Score chinese = new Score();
            Score math = new Score();
            Score physics = new Score();
            for(int j = 0; j < 3;j++) {
            	if(j!=0) {
            		String id0 = in.next();
                    String name0 = in.next();
            	}
                String subject = in.next();
                int score1 =in.nextInt();
                int score2 = in.nextInt();
                if(subject.equals("語文")) {
                	chinese.setUsual(score1);
                	chinese.setTerm(score2);
                }
                if(subject.equals("數學")) {
                	math.setUsual(score1);
                	math.setTerm(score2);
                }
                if(subject.equals("物理")) {
                	physics.setUsual(score1);
                	physics.setTerm(score2);
                }
            }
        	Student stu = new Student(name, id, chinese,math,physics);
            stu.printlnfo();
            System.out.printf("\n");
        }
    }
}

題目五是“答題判題程式-1”

輸入格式:

程式輸入資訊分三部分:

1、題目數量

格式:整數數值,若超過1位最高位不能為0,

樣例:34

2、題目內容

一行為一道題,可以輸入多行資料。

格式:"#N:"+題號+" "+"#Q:"+題目內容+" "#A:"+標準答案

格式約束:題目的輸入順序與題號不相關,不一定按題號順序從小到大輸入。

樣例:#N:1 #Q:1+1= #A:2

#N:2 #Q:2+2= #A:4

3、答題資訊

答題資訊按行輸入,每一行為一組答案,每組答案包含第2部分所有題目的解題答案,答案的順序號與題目題號相對應。

格式:"#A:"+答案內容

格式約束:答案數量與第2部分題目的數量相同,答案之間以英文空格分隔。

樣例:#A:2 #A:78

      2是題號為1的題目的答案
      78是題號為2的題目的答案

答題資訊以一行"end"標記結束,"end"之後的資訊忽略。

輸出格式:

1、題目數量

格式:整數數值,若超過1位最高位不能為0,

樣例:34

2、答題資訊

一行為一道題的答題資訊,根據題目的數量輸出多行資料。

格式:題目內容+" ~"+答案

樣例:1+1=~2

2+2= ~4

3、判題資訊

判題資訊為一行資料,一條答題記錄每個答案的判斷結果,答案的先後順序與題目題號相對應。

格式:判題結果+" "+判題結果

格式約束:

     1、判題結果輸出只能是true或者false,
     2、判題資訊的順序與輸入答題資訊中的順序相同

樣例:true false true

輸入樣例1:

單個題目。例如:

1
#N:1 #Q:1+1= #A:2
#A:2
end

輸出樣例1:

在這裡給出相應的輸出。例如:

1+1=~2
true

輸入樣例2:

單個題目。例如:

1
#N:1 #Q:1+1= #A:2
#A:4
end

輸出樣例2:

在這裡給出相應的輸出。例如:

1+1=~4
false

輸入樣例3:

多個題目。例如:

2
#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#A:2 #A:4
end

輸出樣例3:

在這裡給出相應的輸出。例如:

1+1=~2
2+2=~4
true true

輸入樣例4:

多個題目。例如:

2
#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#A:2 #A:2
end

輸出樣例4:

在這裡給出相應的輸出。例如:

1+1=~2
2+2=~2
true false

輸入樣例5:

多個題目,題號順序與輸入順序不同。例如:

2
#N:2 #Q:1+1= #A:2
#N:1 #Q:5+5= #A:10
#A:10 #A:2
end

輸出樣例5:

在這裡給出相應的輸出。例如:

5+5=~10
1+1=~2
true true

輸入樣例6:

含多餘的空格符。例如:

1
#N:1 #Q: The starting point of the Long March is #A:ruijin
#A:ruijin
end

輸出樣例6:

在這裡給出相應的輸出。例如:

The starting point of the Long March is~ruijin
true

輸入樣例7:

含多餘的空格符。例如:

1
#N: 1 #Q: 5 +5= #A:10
#A:10
end

輸出樣例7:

在這裡給出相應的輸出。例如:

5 +5=~10
true

讓我們分析下題目:

  題目輸入分為三個部分

  1.輸入題目數量,因此已知題目數量,便可以考慮利用確定長度的陣列進行對題目的儲存。

  2.題目輸入的形式為“#N:1 #Q:1+1= #A:2”,其中我們只要“1 1+1= 2”這題號,題目內容,標準答案這三個部分,因此考慮正規表示式進行分割。

  3.接著是輸入答題資訊,每一行便會輸入所有題目的答題資訊,因此我們有兩種讀取方式:

  • 一是:我們整行讀取資訊後,便需要提取對我們有用的資訊,即他輸入“#A:2”,但是我們只需要他的“2”,先進行空字元進行分割,然後再對每一個分割的部分進行去除“#A:”的操作得到我們想要的最終答案。
  • 二是:因為我們前面已經知道了題目總數,而且題目也告知我們“答案數量與第二部分題目數量相同”,因此我們進行迴圈讀入,讀入次數就為題目的總數量,這樣我們就一次的得到了“#A:2”的內容,然後我們進行去除“#A:”的操作就可以了。

  經過上述的分析,我們也大致可以確定了我們可以用三個實體類來進行我們的資訊讀入。

  • Question類儲存no-題目序號,questionTest-題目文字,standAnwer-題目標準答案。
  • Paper類用來儲存Question型別的陣列,即組裝試卷。
  • Answer類有Paper型別的物件,也有String型別的陣列,來是對我們的自己的答案進行儲存,還有一個boolean型別的名為judgeAnswer的陣列,進行我們的判斷答案進行儲存。

  題目輸出形式也為三個部分

  1.輸出題目數量

  2.輸出答題資訊,輸出形式為“題目內容+" ~"+答案”。另外我們觀察一種題目的輸入輸出樣例:

輸入:2             輸出:5+5=~10
   #N:2 #Q:1+1= #A:2       1+1=~2
   #N:1 #Q:5+5= #A:10 true true
   #A:10 #A:2
   end

在這一個輸入與輸出樣例中,輸入的題目順序是21但是題目數出的順序是1,2,再聯想到上面的輸入答題資訊時,“題目的輸入順序與題號不相關,不一定按題號順序從小到大輸入。”以及:輸入自己的答題資訊時:“答案的順序號與題目題號相對應”,因此自己對題目資訊進行儲存後,需要進行題目序號的排序,才能進行相應的後面的判斷處理。

  3.輸出題目數量,輸出答題資訊,輸出形式為“題目內容+" ~"+答案”,然後輸出判題資訊即trur 或者 false。

  下面是自己程式碼:

題目集一最後一題
 package one_seven_oop1_last;

import java.util.Scanner;

public class Last1 {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        String wu = in.nextLine();
        Question[] questions = new Question[n]; 
        // 傳入題目序號,題目,標準答案
        for(int i = 0; i < n ; i++) {
        	String list = in.nextLine();
        	String[] text = list.split("\\s*#N:\\s*|\\s*#Q:\\s*|\\s*#A:\\s*");
        	int k = Integer.parseInt(text[1]);
        	Question question = new Question(k,text[2],text[3]);
        	questions[i] = question;
        }
        
        Paper paper = new Paper(questions,n);
        
        // 傳入答題的答案
        String[] answer = new String [n];
        for(int i =0; i < n + 1; i++) {
        	String answerList = in.next();
        	if(answerList.equals("end"))
        		break;
        	String[] text = answerList.split("\\s*A:\\s*");
        	answer[i] = text[1];
        }
        Answer answers = new Answer(paper);
        answers.setAnswes(answer);
        answers.println(); 
    }
}

class Question {
	private int no;
	private String questionText;
	private String standardAnswer; 
	
	Question(){
	}

	public Question(int no, String questionText, String standardAnswer) {
		super();
		this.no = no;
		this.questionText = questionText;
		this.standardAnswer = standardAnswer;
	}

	public int getNo() {
		return no;
	}

	public void setNo(int no) {
		this.no = no;
	}

	public String getQuestionText() {
		return questionText;
	}

	public void setQuestionText(String questionText) {
		this.questionText = questionText;
	}

	public String getStandardAnswer() {
		return standardAnswer;
	}

	public void setStandardAnswer(String standardAnswer) {
		this.standardAnswer = standardAnswer;
	}

	public boolean answerJudge(String answer) {
		if(standardAnswer.equals(answer))
			return true;
		else
			return false;
	}
}

class Paper {
	private Question[] question;
	private int num;
	
	public Paper() {
		super();
	}

	public Paper(Question[] question, int num) {
		this.question = question;
		this.num = num;
	}

	public Question getQuestion(int i) {
		return question[i];
	}

	public void setQuestion(Question[] question) {
		this.question = question;
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}
	
	// 對題目排序
	public void sortQuestions() {
		for(int i = 0; i< num-1; i++) {
			for(int j = 0; j <num - 1 - i; j++) {
				Question t= new Question();
				if(question[j].getNo() > question[j+1].getNo()) {
					t = question[j];
					question[j] = question[j+1];
					question[j+1] = t;
				}
			}
		}
	}
}

class Answer {
	private Paper paper = new Paper();
	private String[] Answers;
	private boolean[] judgeAnswer = new boolean[paper.getNum()];;
	
	Answer(Paper paper){
		this.paper = paper;
		this.judgeAnswer = new boolean[paper.getNum()];
	}

	public Paper getPaper() {
		return paper;
	}

	public void setPaper(Paper paper) {
		this.paper = paper;
	}

	public String getAnswes(int i) {
		return Answers[i];
	}

	public void setAnswes(String[] standardAnswes) {
		this.Answers = standardAnswes;
	}

	public boolean[] getJudgeAnswer() {
		return judgeAnswer;
	}

	public void setJudgeAnswer(boolean[] judgeAnswer) {
		this.judgeAnswer = judgeAnswer;
	}
	
	public boolean[] compare() {
		for(int i = 0; i < paper.getNum(); i++) {
			if(paper.getQuestion(i).answerJudge(Answers[i]))
				judgeAnswer[i] = true;
			else
				judgeAnswer[i] = false;
		}
		return judgeAnswer;
	}
	
	public void println() {
		paper.sortQuestions();
		for(int i = 0; i < paper.getNum() ; i++) {
			System.out.printf(paper.getQuestion(i).getQuestionText() + "~" + getAnswes(i) + "\n");
		}
		compare();
		for(int i = 0; i < paper.getNum(); i++) {
			System.out.printf(judgeAnswer[i]+"");
			if(i != paper.getNum()-1)
				System.out.printf(" ");
		}
		
	}

}

  程式碼如上述所述,根據SOURCEMONITIOR生成的情況來看:南昌航空大學大一下學期java-題目集1~3總結性Blog——蘇禮順23201608

根據資料與雷達圖分析:

  • 分支語句佔比總語句數的百分比為12.8%,此比例較低,說明此程式碼中分支邏輯較少,更易於理解與維護
  • 在雷達圖中註釋語句佔總語句數的百分比最低,說明我的程式碼可讀性較差,可能也難以理解和維護,因此要增加程式碼的註釋比例
  • 同時,每個方法的平均語句和數量也較低,可能是因為這段程式碼不是很複雜,較多的set與get語句使得方法的平均語句和數量較低

而結合自己的程式碼編寫的實際來看,三個類的類間關係設計的並不合理,Question與Paper之間是聚合關係,因為試卷包含題目,而Answer與paper是關聯關係,這兩個之間的耦合性太強了。我們學過MVC模式,應該放置一個控制類controller,進行對資訊的處理,同時寫一個view類,來進行對資訊的輸出。此外,對於題目序號的排序可以進行compareTo方法的重寫。而不是用氣泡排序。


(二)題目集二

題目一是是對手機的價格排序以及查詢。

這一題新學到了兩個東西,一個是ArrayList實現動態陣列大小沒有限制,一個是利用實現comparable介面,重寫compareTo方法,,實行對price的大小來確定手機物件的大小關係 。透過Collections類的sort方法對連結串列中的物件按照price升序排序。

題目二三則是對類的成員變數,構造方法,等的簡單使用。

題目四是“答題判題程式-2”

設計實現答題程式,模擬一個小型的測試,以下粗體字顯示的是在答題判題程式-1基礎上增補或者修改的內容

要求輸入題目資訊、試卷資訊和答題資訊,根據輸入題目資訊中的標準答案判斷答題的結果。

輸入格式:

程式輸入資訊分三種,三種資訊可能會打亂順序混合輸入

1、題目資訊

一行為一道題,可輸入多行資料(多道題)。

格式:"#N:"+題目編號+" "+"#Q:"+題目內容+" "#A:"+標準答案

格式約束:

    1、題目的輸入順序與題號不相關,不一定按題號順序從小到大輸入。
    2、允許題目編號有缺失,例如:所有輸入的題號為1、2、5,缺少其中的3號題。此種情況視為正常。

樣例:#N:1 #Q:1+1= #A:2

#N:2 #Q:2+2= #A:4

2、試卷資訊

一行為一張試卷,可輸入多行資料(多張卷)。

格式:"#T:"+試卷號+" "+題目編號+"-"+題目分值

     題目編號應與題目資訊中的編號對應。

     一行資訊中可有多項題目編號與分值。

樣例:#T:1 3-5 4-8 5-2

3、答卷資訊

答卷資訊按行輸入,每一行為一張答卷的答案,每組答案包含某個試卷資訊中的題目的解題答案,答案的順序與試卷資訊中的題目順序相對應。

格式:"#S:"+試卷號+" "+"#A:"+答案內容

格式約束:答案數量可以不等於試卷資訊中題目的數量,沒有答案的題目計0分,多餘的答案直接忽略,答案之間以英文空格分隔。

樣例:#S:1 #A:5 #A:22

       1是試卷號 

       5是1號試卷的順序第1題的題目答案

       22是1號試卷的順序第2題的題目答案

答題資訊以一行"end"標記結束,"end"之後的資訊忽略。

輸出格式:

1、試卷總分警示

該部分僅當一張試卷的總分分值不等於100分時作提示之用,試卷依然屬於正常試卷,可用於後面的答題。如果總分等於100分,該部分忽略,不輸出。

格式:"alert: full score of test paper"+試卷號+" is not 100 points"

樣例:alert: full score of test paper2 is not 100 points

2、答卷資訊

一行為一道題的答題資訊,根據試卷的題目的數量輸出多行資料。

格式:題目內容+"~"+答案++"~"+判題結果(true/false)

約束:如果輸入的答案資訊少於試卷的題目數量,答案的題目要輸"answer is null"

樣例:3+2=~5~true

4+6=~22~false.

      answer is null

3、判分資訊

判分資訊為一行資料,是一條答題記錄所對應試卷的每道小題的計分以及總分,計分輸出的先後順序與題目題號相對應。

格式:題目得分+" "+....+題目得分+"~"+總分

格式約束:

 1、沒有輸入答案的題目計0分

 2、判題資訊的順序與輸入答題資訊中的順序相同

樣例:5 8 0~13

根據輸入的答卷的數量以上2、3項答卷資訊與判分資訊將重複輸出。

4、提示錯誤的試卷號

如果答案資訊中試卷的編號找不到,則輸出”the test paper number does not exist”,參見樣例9。

設計建議:

參考答題判題程式-1,建議增加答題類,類的內容以及類之間的關聯自行設計。

輸入樣例1:

一張試卷一張答卷。試卷滿分不等於100。例如:

#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-5 2-8
#S:1 #A:5 #A:22
end

輸出樣例1:

在這裡給出相應的輸出。例如:

alert: full score of test paper1 is not 100 points
1+1=~5~false
2+2=~22~false
0 0~0

輸入樣例2:

一張試卷一張答卷。試卷滿分不等於100。例如:

#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-70 2-30
#S:1 #A:5 #A:22
end

輸出樣例2:

在這裡給出相應的輸出。例如:

1+1=~5~false
2+2=~22~false
0 0~0

輸入樣例3:

一張試卷、一張答卷。各類資訊混合輸入。例如:

#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-70 2-30
#N:3 #Q:3+2= #A:5
#S:1 #A:5 #A:4
end

輸出樣例:

在這裡給出相應的輸出。例如:

1+1=~5~false
2+2=~4~true
0 30~30

輸入樣例4:

試卷題目的順序與題號不一致。例如:

#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 2-70 1-30
#N:3 #Q:3+2= #A:5
#S:1 #A:5 #A:22
end

輸出樣例:

在這裡給出相應的輸出。例如:

2+2=~5~false
1+1=~22~false
0 0~0

輸入樣例5:

亂序輸入。例如:

#N:3 #Q:3+2= #A:5
#N:2 #Q:2+2= #A:4
#T:1 3-70 2-30
#S:1 #A:5 #A:22
#N:1 #Q:1+1= #A:2
end

輸出樣例:

在這裡給出相應的輸出。例如:

3+2=~5~true
2+2=~22~false
70 0~70

輸入樣例6:

亂序輸入+兩份答卷。例如:

#N:3 #Q:3+2= #A:5
#N:2 #Q:2+2= #A:4
#T:1 3-70 2-30
#S:1 #A:5 #A:22
#N:1 #Q:1+1= #A:2
#S:1 #A:5 #A:4
end

輸出樣例:

在這裡給出相應的輸出。例如:

3+2=~5~true
2+2=~22~false
70 0~70
3+2=~5~true
2+2=~4~true
70 30~100

輸入樣例7:

亂序輸入+分值不足100+兩份答卷。例如:

#N:3 #Q:3+2= #A:5
#N:2 #Q:2+2= #A:4
#T:1 3-7 2-6
#S:1 #A:5 #A:22
#N:1 #Q:1+1= #A:2
#S:1 #A:5 #A:4
end

輸出樣例:

在這裡給出相應的輸出。例如:

alert: full score of test paper1 is not 100 points
3+2=~5~true
2+2=~22~false
7 0~7
3+2=~5~true
2+2=~4~true
7 6~13

輸入樣例8:

亂序輸入+分值不足100+兩份答卷+答卷缺失部分答案。例如:

#N:3 #Q:3+2= #A:5
#N:2 #Q:2+2= #A:4
#T:1 3-7 2-6
#S:1 #A:5 #A:22
#N:1 #Q:1+1= #A:2
#T:2 2-5 1-3 3-2
#S:2 #A:5 #A:4
end

輸出樣例:

在這裡給出相應的輸出。例如:

alert: full score of test paper1 is not 100 points
alert: full score of test paper2 is not 100 points
3+2=~5~true
2+2=~22~false
7 0~7
2+2=~5~false
1+1=~4~false
answer is null
0 0 0~0

輸入樣例9:

亂序輸入+分值不足100+兩份答卷+無效的試卷號。例如:

#N:3 #Q:3+2= #A:5
#N:2 #Q:2+2= #A:4
#T:1 3-7 2-6
#S:3 #A:5 #A:4
end

輸出樣例:

在這裡給出相應的輸出。例如:

alert: full score of test paper1 is not 100 points
The test paper number does not exist

讓我們分析下題目:

  對於輸入資訊

  1.首先是此次題目相對於上次題目最大的不同-就是增加了試卷資訊,對於試卷資訊裡面包含了試卷號,題目編號與題目分值然後是輸入資訊:

  2.題目資訊-這次沒有輸入題目數量,只是題目資訊,因此不能用定長度的陣列來進行對題目資訊的儲存,而是利用題目一學的Arraylist儲存題目的資料。
  3.試卷資訊-一行為一張試卷,可輸入多行試卷,
  4.答卷資訊-這次的答案資訊也多試卷的卷號這一條資訊,然後自己的答案按照對應試卷的題目順序來進行輸入
  5.設計考慮:試卷類在上一次題目中已經被定義了,因此在上次設計上增加答卷類,用於封裝答卷資訊。
  對於輸出資訊:
  1.輸出試卷總分警示:僅當一張試卷的總分分值不等於100分時作提示之用。
  2.答卷資訊-與上一次的輸入一樣,不同的是有輸出“answer is null”這一種資訊。因此最初的設計思路是考慮先遍歷試卷,因為題目的試卷的題目數量是一定的,然後找出對應的答題卷,當沒有這一題的時候將輸出 “answer is null”。同時當對應的答題卷子 找不到的時候,則會輸出“the test paper number does not exist”。
  3.接著輸出判分資訊判斷每一題的得分。並且彙總總分數。

  下面是自己程式碼:

題目集二最後一題
 package one_seven_oop2_last;

import java.util.Collections;
import java.util.ArrayList;
import java.util.Scanner;

public class Last2 {
	public static void main(String[] args) {
		Scanner  in = new Scanner(System.in);
		ArrayList<Question> question = new ArrayList<Question>();
		ArrayList<TestPaper> textPaper = new ArrayList<TestPaper>();
		ArrayList<Answer> answer = new ArrayList<Answer>();

		String input = in.nextLine();
		
//		int cnt = 0;
		while(!input.equals("end")) {
			// 對一行問題進行讀取與解析
			if(input.contains("#N")) {
				// controller
        		String[] text = input.split("\\s*#N:\\s*|\\s*#Q:\\s*|\\s*#A:\\s*");// 分割
            	Integer.parseInt(text[1]);// 讀取題號
            	Question q = new Question(Integer.parseInt(text[1]),text[2],text[3]);
            	question.add(q);// 加入question的陣列
			}
			
			else if(input.contains("#T")) {
        	    String[] texts = input.split("\\s*#T:\\s*|\\s+");// 第一次拆分
        	    TestPaper p = new TestPaper( (Integer.parseInt(texts[1])) );
        	    textPaper.add(p);
        		ArrayList<Question> q = new ArrayList<Question>();
        		
        	    for(int i = 2; i < texts.length; i++) {
        	        String text = texts[i];
        	        String[] singleText = text.split("-");// 第二次拆分
        	        // 傳入每一題的分數
        	        for(int j = 0; j < question.size(); j++) {
        	            if(question.get(j).getNumber() == Integer.parseInt(singleText[0])) {
        	            	Question q1 = new Question(question.get(j).getNumber(),question.get(j).getContent(), question.get(j).getStandAnswer(), Integer.parseInt(singleText[1]));
        	                q.add(q1);
//        	            	question.get(j).setScore(Integer.parseInt(singleText[1]));
//        	                q.add(question.get(j));
        	            }
        	        }
        	    }
        	    p.setQuestion(q);
        	    //cnt = question.size();// 這個操作是為了讓每次卷子生成的時候,從上一步結束後的問題列表繼續開始
			}
			
			else if(input.contains("#S")) {
				// 讀入自己的答案
        		String[] texts = input.split("\\s*#S:\\s*|\\s+");
        		Answer a = new Answer(Integer.parseInt(texts[1]));
        		ArrayList<String> list = new ArrayList<String>();
        		for (int i = 2; i < texts.length; i++) {
        		    String text = texts[i];
        		    String[] singleText = text.split("\\s*#A:\\s*");
        		    list.add(singleText[1]);
        		}
        		String[] array =list.toArray(new String[list.size()]);
        		a.setSelfAnswer(array);
        		answer.add(a);
			}
			
			else if(input.equals("end"))
        		break;
				
			input = in.nextLine();


		}
		
		AnswerSheet answerSheet = new AnswerSheet();
		answerSheet.setAnswer(answer);
		
//		 判斷每張試卷的總分數
		for(int i = 0;  i < textPaper.size(); i++) {
        	int t = 0;
        	for(int j = 0; j < textPaper.get(i).getQuestion().size(); j++) {
        		t = t + textPaper.get(i).getQuestion().get(j).getScore();
        	}
        	if(t != 100)
        		System.out.println("alert: full score of test paper"+(i+1)+" is not 100 points");
        }
		
//		answerSheet.getAnswer().size()
//		textPaper.size()
		int choice1 = 0, choice2 = 0;
		for(int i =0; i < answerSheet.getAnswer().size(); i++) {
			choice2 = 0;
			for(int j = 0; j < textPaper.size(); j++) {
				choice1 = 0;
				if(textPaper.get(j).getNumber() == answerSheet.getAnswer().get(i).getNumber()) {
					choice1 = 1;
					choice2 = 1;
					TestPaper p = textPaper.get(j);
					String[] selfanswer = answerSheet.getAnswer().get(i).getSelfAnswer();
					int[] score =  new int[p.getQuestion().size()];
					for(int k =0; k < p.getQuestion().size(); k++) {
						score[k] = p.getQuestion().get(k).getScore();
					}
					for(int k = 0; k < selfanswer.length; k++) {
						String d1 = p.getQuestion().get(k).getStandAnswer();
						String d2 = selfanswer[k];
						String result = d1.equals(d2) ? "true" : "false";
						if(result.equals("false"))
							score[k] = 0;
						System.out.println(p.getQuestion().get(k).getContent()+"~"+d2+"~"+result);
					}
					if(selfanswer.length < p.getQuestion().size()) {
						for(int k = selfanswer.length;k < p.getQuestion().size();k++)
							System.out.println("answer is null");
						if(selfanswer.length == 0)
							break;
						for(int w =selfanswer.length; w < p.getQuestion().size();w++)
							score[w] = 0;
					}

					int total = 0;
					for(int k = 0; k < score.length; k++) {
                    	total = total + score[k];
                    	System.out.printf("%d",score[k]);
                    	if(k!=score.length-1)
                    		System.out.printf(" ");
                    }
					System.out.println("~"+total);
				}
				
			}
			if(choice1== 0 && choice2 == 0)
				System.out.println("The test paper number does not exist");
		}

		
	}
}

// 問題類——封裝一個試卷的所有屬性與方法 
class Question {
	private int number;// 題號
	private String content;// 題目
	private String standAnswer;// 題目標準答案
	private int score;// 題目分數
	
	public Question() {
		super();
	}

	public Question(int number, String content, String standAnswer) {
		super();
		this.number = number;
		this.content = content;
		this.standAnswer = standAnswer;
	}

	public Question(int number, String content, String standAnswer, int score) {
		super();
		this.number = number;
		this.content = content;
		this.standAnswer = standAnswer;
		this.score = score;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getStandAnswer() {
		return standAnswer;
	}

	public void setStandAnswer(String standAnswer) {
		this.standAnswer = standAnswer;
	}

	public int getScore() {
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}
	
	
}

// 試卷類——封裝一種卷子
class TestPaper {
	private ArrayList<Question> question = new ArrayList<Question>();// 一種試卷有多張卷子
	private int number;// 此種試卷對應的編號
	
	public TestPaper() {
		super();
	}

	public TestPaper(int number) {
		super();
		this.number = number;
	}

	public TestPaper(ArrayList<Question> question, int number) {
		super();
		this.question = question;
		this.number = number;
	}

	public ArrayList<Question> getQuestion() {
		return question;
	}

	public void setQuestion(ArrayList<Question> question) {
		this.question = question;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}
	
	
}

// 答案類——封裝一張答卷及其所有答案,每道題對應的分數也在這裡頭
class Answer {
	private int number;
	private String[] selfAnswer;// 二維陣列用於左邊是自己的答案,右邊是對應的分數
	
	public Answer() {
		super();
	}

	public Answer(int t) {
		this.number = t;
	}
	
	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}

	public String getSelfAnswer(int i) {
		return selfAnswer[i];
	}
	
	public String[] getSelfAnswer() {
		return selfAnswer;
	}

	public void setSelfAnswer(String[] selfAnswer) {
		this.selfAnswer = selfAnswer;
	}
	
	
	
}

// 答卷類——封裝一種卷子的多張答案
class AnswerSheet {
	private ArrayList<Answer> answer = new ArrayList<Answer>();// 儲存多張答案
	
	public AnswerSheet() {
		super();
	}

	public ArrayList<Answer> getAnswer() {
		return answer;
	}

	public void setAnswer(ArrayList<Answer> answer) {
		this.answer = answer;
	}

	
}

  程式碼如上述所述,接著將對自己的原始碼進行分析。

  1.因為題目對於題目資訊,試卷資訊,答題資訊的輸入是亂序輸入的,所以自己在放入題目前是先判斷他是何種資訊,採用contains函式,來確定放入何處。

  2.但是對於資訊處理的不足之處是,所有資訊的處理都放在了主方法。一個大的while迴圈 ,裡面包含了所有的資訊的讀取與處理。對於日後的題目的迭代並不好修改以及閱讀。

  3.然後再在後面一個遍歷所有試卷的大迴圈之中,先找到對應的答卷。在裡面我自己使用了choice1與choice2來判斷是否找沒找到 ,首先從變數的名字上來說,自己的命名就不很規範,應該是以found來表示更能增加可讀性。其次自己大可以不必用兩個變數來判斷。一個足以,要是在遍歷答卷的時候沒找到就continue,然後遍歷整個答卷found仍未false,那麼便說明,這個沒有找到。然後輸出“The test paper number does not exist”便可以了。

  4.在上述的那個遍歷所有試卷的大迴圈,這個部分程式碼數太長,應該拆成幾部分:一是判斷正誤,二是儲存分數,三是輸出判斷結果與與得分。而且這個部分也不應該是放在主方法中,主方法只進行資訊的讀入與輸出。而不是對資訊的處理。

根據SOURCEMONITIOR生成的情況來看:

南昌航空大學大一下學期java-題目集1~3總結性Blog——蘇禮順23201608

根據資料與雷達圖分析:

  • 分支語句佔總語句數的百分比為 15%。仍然處於較低的水平
  • 方法呼叫語句數目為78,這次與上次相比增加很多,說明了這段程式碼的模組化程度比上次更高,但也是可能因為這段程式碼的難度比上次的更大的緣故。
  • 含有註釋的行佔比大幅度增大,上次只是1,6這次到了9.2,註釋的增多,說明了程式碼的可讀性也增強了。
  • 這段程式碼的平均深度與最大深度都比較大,可能就是因為我的while大迴圈與遍歷試卷的大迴圈的緣故。
  • 每個方法的平均語句數量比較少,這一點與上面的點相映襯。要是上面的大迴圈被拆除同時化為其他小部分,那麼這段程式碼就質量更高了。

(三)題目集三

題目一是對輸入資訊的簡單讀取並封裝到類中,然後提取資訊,以設定的格式輸出出來。

題目二是要求我們對日期類的簡單使用,對輸入的日期進行驗證和分析。首先,需要驗證給定的日期是否為合法日期,然後判斷該年是否為閏年,並計算該日期是當年第幾天、當月第幾天、當週第幾天。接著,需要判斷輸入的起始日期和結束日期是否合法,同時結束日期是否早於起始日期。如果輸入的日期全部合法且結束日期不早於起始日期,則輸出日期之間的相差天數、月數和年數。如果有任何日期輸入非法或結束日期早於起始日期,則輸出相應的錯誤資訊。

題目三是“答題判題程式-3”

設計實現答題程式,模擬一個小型的測試,以下粗體字顯示的是在答題判題程式-2基礎上增補或者修改的內容,要求輸入題目資訊、試卷資訊、答題資訊、學生資訊、刪除題目資訊,根據輸入題目資訊中的標準答案判斷答題的結果。

輸入格式:

程式輸入資訊分種,資訊可能會打亂順序混合輸入。

1、題目資訊
題目資訊為獨行輸入,一行為一道題,多道題可分多行輸入。

格式:"#N:"+題目編號+" "+"#Q:"+題目內容+" "#A:"+標準答案

格式約束:
    1、題目的輸入順序與題號不相關,不一定按題號順序從小到大輸入。
    2、允許題目編號有缺失,例如:所有輸入的題號為1、2、5,缺少其中的3號題。此種情況視為正常。
樣例:#N:1 #Q:1+1= #A:2
     #N:2 #Q:2+2= #A:4


2、試卷資訊

試卷資訊為獨行輸入,一行為一張試卷,多張卷可分多行輸入資料。
格式:"#T:"+試卷號+" "+題目編號+"-"+題目分值+" "+題目編號+"-"+題目分值+...

格式約束:
   題目編號應與題目資訊中的編號對應。
   一行資訊中可有多項題目編號與分值。 
樣例:#T:1 3-5 4-8 5-2   


3、學生資訊

學生資訊只輸入一行,一行中包括所有學生的資訊,每個學生的資訊包括學號和姓名,格式如下。

格式:"#X:"+學號+" "+姓名+"-"+學號+" "+姓名....+"-"+學號+" "+姓名

格式約束:
    答案數量可以不等於試卷資訊中題目的數量,沒有答案的題目計0分,多餘的答案直接忽略,答案之間以英文空格分隔。
 樣例:
       #S:1 #A:5 #A:22
       1是試卷號 
       5是1號試卷的順序第1題的題目答案 

4、答卷資訊

答卷資訊按行輸入,每一行為一張答卷的答案,每組答案包含某個試卷資訊中的題目的解題答案,答案的順序號與試 卷資訊中的題目順序相對應。答卷中:

格式:"#S:"+試卷號+" "+學號+" "+"#A:"+試卷題目的順序號+"-"+答案內容+...

格式約束:
       答案數量可以不等於試卷資訊中題目的數量,沒有答案的題目計0分,多餘的答案直接忽略,答案之間以英文空格分隔。
       答案內容可以為空,即””。
       答案內容中如果首尾有多餘的空格,應去除後再進行判斷。
樣例:
       #T:1 1-5 3-2 2-5 6-9 4-10 7-3
       #S:1 20201103 #A:2-5 #A:6-4
       1是試卷號
       20201103是學號
       2-5中的2是試卷中順序號,5是試卷第2題的答案,即T中3-2的答案 
       6-4中的6是試卷中順序號,4是試卷第6題的答案,即T中7-3的答案 
注意:不要混淆順序號與題號

5、刪除題目資訊

刪除題目資訊為獨行輸入,每一行為一條刪除資訊,多條刪除資訊可分多行輸入。該資訊用於刪除一道題目資訊,題目被刪除之後,引用該題目的試卷依然有效,但被刪除的題目將以0分計,同時在輸出答案時,題目內容與答案改為一條失效提示,例如:”the question 2 invalid~0”

格式:"#D:N-"+題目號

格式約束:

       題目號與第一項”題目資訊”中的題號相對應,不是試卷中的題目順序號。

       本題暫不考慮刪除的題號不存在的情況。      
樣例:
#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-5 2-8
#X:20201103 Tom-20201104 Jack
#S:1 20201103 #A:1-5 #A:2-4
#D:N-2
end

輸出
alert: full score of test paper1 is not 100 points
1+1=~5~false
the question 2 invalid~0
20201103 Tom: 0 0~0

答題資訊以一行"end"標記結束,"end"之後的資訊忽略。

輸出格式:


1、試卷總分警示


該部分僅當一張試卷的總分分值不等於100分時作提示之用,試卷依然屬於正常試卷,可用於後面的答題。如果總分等於100 分,該部分忽略,不輸出。


格式:"alert: full score of test paper"+試卷號+" is not 100 points"

樣例:alert: full score of test paper2 is not 100 points


2、答卷資訊


一行為一道題的答題資訊,根據試卷的題目的數量輸出多行資料。

格式:題目內容+"~"+答案++"~"+判題結果(true/false)

約束:如果輸入的答案資訊少於試卷的題目數量,答案的題目要輸"answer is null"   
樣例:
     3+2=~5~true
     4+6=~22~false.
     answer is null

3、判分資訊

判分資訊為一行資料,是一條答題記錄所對應試卷的每道小題的計分以及總分,計分輸出的先後順序與題目題號相對應。

格式:**學號+" "+姓名+": "**+題目得分+" "+....+題目得分+"~"+總分

格式約束:

     1、沒有輸入答案的題目、被刪除的題目、答案錯誤的題目計0分
     2、判題資訊的順序與輸入答題資訊中的順序相同

樣例:20201103 Tom: 0 0~0

       根據輸入的答卷的數量以上2、3項答卷資訊與判分資訊將重複輸出。


4、被刪除的題目提示資訊


當某題目被試卷引用,同時被刪除時,答案中輸出提示資訊。樣例見第5種輸入資訊“刪除題目資訊”。


5、題目引用錯誤提示資訊


試卷錯誤地引用了一道不存在題號的試題,在輸出學生答案時,提示”non-existent question~”加答案。例如:

輸入:

#N:1 #Q:1+1= #A:2
#T:1 3-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103 #A:1-4
end

輸出:
alert: full score of test paper1 is not 100 points
non-existent question~0
20201103 Tom: 0~0
如果答案輸出時,一道題目同時出現答案不存在、引用錯誤題號、題目被刪除,只提示一種資訊,答案不存在的優先順序最高,例如:
輸入:
#N:1 #Q:1+1= #A:2
#T:1 3-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103
end

輸出:
alert: full score of test paper1 is not 100 points
answer is null
20201103 Tom: 0~0


6、格式錯誤提示資訊


輸入資訊只要不符合格式要求,均輸出”wrong format:”+資訊內容。

      例如:wrong format:2 #Q:2+2= #4

7、試卷號引用錯誤提示輸出

如果答卷資訊中試卷的編號找不到,則輸出”the test paper number does not exist”,答卷中的答案不用輸出,參見樣例8。

8、學號引用錯誤提示資訊


如果答卷中的學號資訊不在學生列表中,答案照常輸出,判分時提示錯誤。參見樣例9。

本題暫不考慮出現多張答卷的資訊的情況。

輸入樣例1:

簡單輸入,不含刪除題目資訊。例如:

#N:1 #Q:1+1= #A:2
#T:1 1-5
#X:20201103 Tom
#S:1 20201103 #A:1-5
end

輸出樣例1:

在這裡給出相應的輸出。例如:

alert: full score of test paper1 is not 100 points
1+1=~5~false
20201103 Tom: 0~0

輸入樣例2:

簡單輸入,答卷中含多餘題目資訊(忽略不計)。例如:

#N:1 #Q:1+1= #A:2
#T:1 1-5
#X:20201103 Tom
#S:1 20201103 #A:1-2 #A:2-3
end

輸出樣例3

簡單測試,含刪除題目資訊。例如:

alert: full score of test paper1 is not 100 points
1+1=~2~true
20201103 Tom: 5~5

輸入樣例3:

簡單測試,含刪除題目資訊。例如:

#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-5 2-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103 #A:1-5 #A:2-4
#D:N-2
end

輸出樣例3:

在這裡給出相應的輸出,第二題由於被刪除,輸出題目失效提示。例如:

alert: full score of test paper1 is not 100 points
1+1=~5~false
the question 2 invalid~0
20201103 Tom: 0 0~0

輸入樣例4:

簡單測試,含試卷無效題目的引用資訊以及刪除題目資訊(由於題目本身無效,忽略)。例如:

#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-5 3-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103 #A:1-5 #A:2-4
#D:N-2
end

輸出樣例4:

輸出不存在的題目提示資訊。例如:

alert: full score of test paper1 is not 100 points
1+1=~5~false
non-existent question~0
20201103 Tom: 0 0~0

輸入樣例5:

綜合測試,含錯誤格式輸入、有效刪除以及無效題目引用資訊。例如:

#N:1 +1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-5 2-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103 #A:1-5 #A:2-4
#D:N-2
end

輸出樣例5:

在這裡給出相應的輸出。例如:

wrong format:#N:1 +1= #A:2
alert: full score of test paper1 is not 100 points
non-existent question~0
the question 2 invalid~0
20201103 Tom: 0 0~0

輸入樣例6:

綜合測試,含錯誤格式輸入、有效刪除、無效題目引用資訊以及答案沒有輸入的情況。例如:

#N:1 +1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-5 2-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103 #A:1-5
#D:N-2
end

輸出樣例6:

答案沒有輸入的優先順序最高。例如:

wrong format:#N:1 +1= #A:2
alert: full score of test paper1 is not 100 points
non-existent question~0
answer is null
20201103 Tom: 0 0~0

輸入樣例7:

綜合測試,正常輸入,含刪除資訊。例如:

#N:2 #Q:2+2= #A:4
#N:1 #Q:1+1= #A:2
#T:1 1-5 2-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103 #A:2-4 #A:1-5
#D:N-2
end

輸出樣例7:

例如:

alert: full score of test paper1 is not 100 points
1+1=~5~false
the question 2 invalid~0
20201103 Tom: 0 0~0

輸入樣例8:

綜合測試,無效的試卷引用。例如:

#N:1 #Q:1+1= #A:2
#T:1 1-5
#X:20201103 Tom
#S:2 20201103 #A:1-5 #A:2-4
end

輸出樣例8:

例如:

alert: full score of test paper1 is not 100 points
The test paper number does not exist

輸入樣例9:

無效的學號引用。例如:

#N:1 #Q:1+1= #A:2
#T:1 1-5
#X:20201106 Tom
#S:1 20201103 #A:1-5 #A:2-4
end

輸出樣例9:

答案照常輸出,判分時提示錯誤。例如:

alert: full score of test paper1 is not 100 points
1+1=~5~false
20201103 not found

輸入樣例10:

資訊可打亂順序輸入:序號不是按大小排列,各類資訊交錯輸入。但本題不考慮引用的題目在被引用的資訊之後出現的情況(如試卷引用的所有題目應該在試卷資訊之前輸入),所有引用的資料應該在被引用的資訊之前給出。例如:

#N:3 #Q:中國第一顆原子彈的爆炸時間 #A:1964.10.16
#N:1 #Q:1+1= #A:2
#X:20201103 Tom-20201104 Jack-20201105 Www
#T:1 1-5 3-8
#N:2 #Q:2+2= #A:4
#S:1 20201103 #A:1-5 #A:2-4
end

輸出樣例10:

答案按試卷中的題目順序輸出。例如:

alert: full score of test paper1 is not 100 points
1+1=~5~false
中國第一顆原子彈的爆炸時間~4~false
20201103 Tom: 0 0~0
對題目進行分析:
  此次增加了題目的迭代增加了學生的資訊,以及刪除題目的資訊這兩條資訊。因此初步設計在上次的基礎上增加學生類,以及對每個題目增加一條屬性,用於判斷這個題目刪沒被刪除。
  題目輸入:
  1.題目資訊,試卷資訊與上次相同。特別注意的是,因為並不是輸入的每一道題目試卷都會引用,並且試卷引用的題目可能試題還沒輸入,因此我們增加questionBank類,用於儲存所有的題目, 之後再組裝試卷。
  2.學生資訊。一行輸入所有的學生的資訊,包括他的學號與姓名。
  3.答卷資訊,與上次大體上相同,但是增加了學號資訊。
  4.刪除題目資訊,當刪除後,遍歷題目庫,將對應的題目exist屬性賦為false。
  題目輸出:
  1.試卷總分警示
  2.答題資訊-即根據試卷的題目的數量輸出多行資料,其中被刪除的資訊要輸出“the question 2 invalid~0”,試卷引用了一道不存在題號的試題則輸出“non-existent question~0”
  3.格式錯誤,即上述輸入的形式不按照 格式來,那麼便輸出“wrong format”+輸入的資訊。這個是最難辦的,要
  4.還要注意,試卷號引用錯誤提示輸出以及學號引用錯誤提示資訊。
下面是自己的程式碼:
題目集三最後一題
 package one_seven_oop3_last;

import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

 
public class Last3 {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		
		Controller controller = new Controller();
		
		String input = in.nextLine();
		while(!input.equals("end")) {
			
			if(input.matches("\\s*#N:\\s*\\d+\\s+#Q:\\s*[^#]*\\s*#A:.*")) {
				controller.inputN(input);
			}
			
			else if(input.matches("(#T:\\d+){1}(\\s+[0-9]+-[0-9]+){0,}\\s*")) {
				controller.inputT(input);
			}
			
			else if(input.matches("(\\s*#X:\\s*){1}(\\d+\\s+[^- ]+-){0,}(\\d+\\s+.+){1}\\s*")) {
				controller.inputX(input);
			}
			
			else if(input.matches("(\\s*#S:\\s*\\d+\\s+\\d+\\s*){1}(\\s*#A:\\s*\\d+-[^#]*){0,}\\s*")) {
				controller.inputS(input);
			}
						
			else if(input.matches("\\s*#D:\\s*N-\\s*\\d+\\s*")) {
				controller.inputD(input);
			}
			
			else {
				controller.view.wrongMenu(input);
			}
			
			input = in.nextLine();
		}
		
		// 組裝試卷
		controller.composePaper();
		
		// 輸出試卷不足100分警示資訊
		controller.lackScoreOutput();
		
		controller.judgeAnswer();
		
		// 以下皆為測試程式碼
		// N
//		System.out.println(controller.getQuestionBank().getQuestion().get(0).getNumber());
//		System.out.println(controller.getQuestionBank().getQuestion().get(0).getContent());
//		System.out.println(controller.getQuestionBank().getQuestion().get(0).getStandAnswer());
		// T
//		System.out.println(controller.getTestPaper().get(0).getNumber());
//		System.out.println(controller.getTestPaper().get(0).getNumScore());
		// X
//		System.out.println(controller.getStudent().get(0).getId());
//		System.out.println(controller.getStudent().get(0).getName());
//		System.out.println(controller.getStudent().get(1).getId());
//		System.out.println(controller.getStudent().get(1).getName());
		// S
//		System.out.println(controller.getAnswerSheet().getAnswer().get(0).getNumber());
//		System.out.println(controller.getAnswerSheet().getAnswer().get(0).getId());
//		System.out.println(controller.getAnswerSheet().getAnswer().get(0).getNoAnswer().get(0)[0]);
//		System.out.println(controller.getAnswerSheet().getAnswer().get(0).getNoAnswer().get(0)[1]);
//		System.out.println(controller.getAnswerSheet().getAnswer().get(0).getNoAnswer().get(1)[0]);
//		System.out.println(controller.getAnswerSheet().getAnswer().get(0).getNoAnswer().get(1)[1]);
		// D
//		System.out.println(controller.getQuestionBank().getQuestion().get(1).isExist());
		// composePaper
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(0).getNumber());
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(0).getContent());
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(0).getScore());
//		
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(1).getNumber());
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(1).getContent());
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(1).getScore());
//		
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(2).getNumber());
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(2).getContent());
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(2).getScore());
	}
}

// 題目類
class Question {
	private int number;// 題目編號
	private String content = "bank";// 題目內容
	private String standAnswer;// 題目標準答案
	private int score;// 題目分數
	private boolean exist = false;// 判斷題目刪沒被刪除
	
	public Question() {
		super();
	}

	public Question(int number, boolean exist) {
		super();
		this.number = number;
		this.exist = exist;
	}

	public Question(int number, String content, String standAnswer, boolean exist) {
		super();
		this.number = number;
		this.content = content;
		this.standAnswer = standAnswer;
		this.exist = exist;
	}

	public Question(boolean exist) {
		this.exist = exist;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getStandAnswer() {
		return standAnswer;
	}

	public void setStandAnswer(String standAnswer) {
		this.standAnswer = standAnswer;
	}

	public int getScore() {
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}

	public boolean isExist() {
		return exist;
	}

	public void setExist(boolean exist) {
		this.exist = exist;
	}
	
}

// 題庫類
class QuestionBank {
	private ArrayList<Question> question = new ArrayList<Question>();// 所有題目集合
	
	public QuestionBank() {
		super();
	}

	public ArrayList<Question> getQuestion() {
		return question;
	}

	public void setQuestion(ArrayList<Question> question) {
		this.question = question;
	}

}

// 試卷類
class TestPaper {
	private int number;// 試卷編號
	private ArrayList<Question> question = new ArrayList<Question>();// 一種試卷有多道題目
	private ArrayList<Integer[]> numScore = new ArrayList<Integer[]>();
	public TestPaper() {
		super();
	}

	public TestPaper(int number) {
		super();
		this.number = number;
	}

	public ArrayList<Question> getQuestion() {
		return question;
	}

	public void setQuestion(ArrayList<Question> question) {
		this.question = question;
	}

	public ArrayList<Integer[]> getNumScore() {
		return numScore;
	}

	public void setNumScore(ArrayList<Integer[]> numScore) {
		this.numScore = numScore;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}
	
	
}

// 一張答卷類
class Answer {
	private int number; // 試卷號
	private String id;// 做題學生的學號
	private ArrayList<Integer[]> noScore = new ArrayList<Integer[]>();// 試卷中的順序號與每道題目的得分
	private ArrayList<String[]> noAnswer = new ArrayList<String[]>();// 試卷中的順序號與對應的自己的答案
	private StringBuilder info;// 儲存一道題目要輸出的資訊
	private boolean exist = true;// 判斷這張答卷的引的試卷的題號在不在,預設是true,也就是有
	
	public Answer() {
		super();
	}

	public Answer(int number, String id) {
		super();
		this.number = number;
		this.id = id;
	}

	public boolean isExist() {
		return exist;
	}

	public void setExist(boolean exist) {
		this.exist = exist;
	}

	public ArrayList<Integer[]> getNoScore() {
		return noScore;
	}

	public void setNoScore(ArrayList<Integer[]> noScore) {
		this.noScore = noScore;
	}

	public ArrayList<String[]> getNoAnswer() {
		return noAnswer;
	}

	public void setNoAnswer(ArrayList<String[]> noAnswer) {
		this.noAnswer = noAnswer;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public StringBuilder getInfo() {
		return info;
	}

	public void setInfo(StringBuilder info) {
		this.info = info;
	}
	
}

// 多張答卷類
class AnswerSheet {
	private ArrayList<Answer> answer = new ArrayList<Answer>();// 儲存多張答案

	public AnswerSheet() {
		super();
	}

	public ArrayList<Answer> getAnswer() {
		return answer;
	}

	public void setAnswer(ArrayList<Answer> answer) {
		this.answer = answer;
	}

	
}

// 學生類
class Student {
	private String id;
	private String name;
	
	public Student(String id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	
}

// 儲存要輸出的內容 ? && 定義不同的輸入方式對應的方法
class Controller {
	// 題目庫
	QuestionBank questionBank = new QuestionBank();
	// 試卷庫
	ArrayList<TestPaper> testPaper = new ArrayList<TestPaper>();
	// 答卷庫
	AnswerSheet answerSheet = new AnswerSheet(); 
	// 學生庫
	ArrayList<Student> student = new ArrayList<Student>();
	
	View view = new View();
	
	public QuestionBank getQuestionBank() {
		return questionBank;
	}

	public void setQuestionBank(QuestionBank questionBank) {
		this.questionBank = questionBank;
	}

	public ArrayList<TestPaper> getTestPaper() {
		return testPaper;
	}

	public void setTextPaper(ArrayList<TestPaper> testPaper) {
		this.testPaper = testPaper;
	}

	public AnswerSheet getAnswerSheet() {
		return answerSheet;
	}

	public void setAnswerSheet(AnswerSheet answerSheet) {
		this.answerSheet = answerSheet;
	}

	public ArrayList<Student> getStudent() {
		return student;
	}

	public void setStudent(ArrayList<Student> student) {
		this.student = student;
	}

	public void inputN(String info) {
		Question q = null;
		// 分割問題
		String[] text = info.split("\\s*#N:\\s*|\\s*#Q:\\s*|\\s*#A:");
		if(text.length == 4) {
			if(text[3].equals("\\s+"))
				q = new Question(Integer.parseInt(text[1]),text[2],text[3],true);
			else {
				text[3] = text[3].trim();
				q = new Question(Integer.parseInt(text[1]),text[2],text[3],true);
			}	
		}
		if(text.length == 3) {
			q = new Question(Integer.parseInt(text[1]),text[2],"",true);
		}

		questionBank.getQuestion().add(q);
		
	}
	
	public void inputT(String info) {
		String[] texts = info.split("\\s*#T:\\s*|\\s+");// 第一次拆分
		TestPaper p = new TestPaper((Integer.parseInt(texts[1])));
		for(int i = 2; i < texts.length; i++) {
	        String text = texts[i];
	        String[] singleText = text.split("-");// 第二次拆分
	        // 傳入每一題的分數
	        Integer[] numscore = new Integer[singleText.length];
	        for (int k = 0; k < singleText.length; k++) {
	            numscore[k] = Integer.parseInt(singleText[k]);
	        }
	        p.getNumScore().add(numscore);
	    }
		testPaper.add(p);
	}
	
	// 有個點沒考慮,要是關於s的資訊輸入有錯怎麼辦?
	public void inputX(String info) {
		String[] texts = info.split("\\s*#X:\\s*|-");
		for(int i = 1; i < texts.length; i++) {
			String text = texts[i];
			String[] singleText = text.split("\\s+");
			Student s = new Student(singleText[0], singleText[1]);
			student.add(s);
		}
	}	
	
	public void inputS(String info) {
		Answer a = null;
		// 分割前面的
		Pattern pattern = Pattern.compile("\\s*#S:\\s*\\d+\\s* \\d+\\s*");
        Matcher matcher = pattern.matcher(info);
        if(matcher.find()) {
        	String[] texts = matcher.group().split("\\s*#S:\\s*|\\s+");
    		a = new Answer(Integer.parseInt(texts[1]),texts[2]);
        }
		//分割後面的
        info = info.replaceAll("#S:\\d+\\s+\\d+\\s+", " ");
        String[] texts = info.split("\\s+#A:\\s*");
        for(int i = 1; i < texts.length;i++) {
        	String text = texts[i];
        	String[] singleText = text.split("#A:\\s*|-");
        	
        	// 防止答案輸入為空,為空則為這一題答案變為null
		    String[] noAnswer = new String[3];
		    
		    if(singleText.length == 1) {
		    	noAnswer[0] = singleText[0];
		    	noAnswer[1] = " ";
		    }
		    else {
		    	noAnswer[0] = singleText[0];
			    noAnswer[1] = singleText[1];
		    }
		    a.getNoAnswer().add(noAnswer);
		    
		    Integer[] noScore = new Integer[2];
		    noScore[0] = Integer.parseInt(singleText[0]);
		    noScore[1] = 0;
		    a.getNoScore().add(noScore);
        }
        
//        String regex1 = "\\s+#A:\\s+\\d+-\\s*";
//        String regex2 = "#A:\\d+-\\s*\\S+.*?(?=\\s)";
//        String regex3 = "#A:\\d+-\\w+(\\s+\\w+)*";
//        pattern = Pattern.compile("#A:\\d+-\\w+(\\s+\\w+)*|#A:\\d+-\\s*");
//        matcher = pattern.matcher(info);
//        while (matcher.find()) {
//        	String text = matcher.group();
//        	String[] singleText = text.split("#A:|-");
//        	// 防止答案輸入為空,為空則為這一題答案變為null
//		    String[] noAnswer = new String[3];
//		    if(singleText.length == 2) {
//		    	noAnswer[0] = singleText[1];
//		    	noAnswer[1] = "";
//		    }
//		    else {
//		    	noAnswer[0] = singleText[1];
//			    noAnswer[1] = singleText[2];
//		    }
//		    a.getNoAnswer().add(noAnswer);
//		    
//		    Integer[] noScore = new Integer[singleText.length];
//		    noScore[0] = Integer.parseInt(singleText[1]);
//		    noScore[1] = 0;
//		    a.getNoScore().add(noScore); 
//        }
        answerSheet.getAnswer().add(a);
	}

	public void  inputD(String info) {
		String[] texts = info.split("\\s*#D:N-\\s*");
		for(int i = 0; i < questionBank.getQuestion().size();i++) {
			if(questionBank.getQuestion().get(i).getNumber() == Integer.parseInt(texts[1]))
				questionBank.getQuestion().get(i).setExist(false);
		}
	}
	
	// 至此,所有資訊都已放入該放的地方
	
	// 組裝試卷(引數是題庫,與試卷的集合)
	public void composePaper() {
		for(int i = 0; i < testPaper.size(); i++) {
			// 下面這個迴圈進入的是每張卷子-對於第i張卷子
			for(int j = 0; j < testPaper.get(i).getNumScore().size(); j++) {
				// 得到的是這張卷子的第j題的題號
				int num = testPaper.get(i).getNumScore().get(j)[0];
				Question q = new Question();
				// 遍歷題庫,若是可以找到就q賦值分數,然後跳出迴圈.如果找不到則found為0
				int found = 0;
				for(int k = 0; k < questionBank.getQuestion().size(); k++) {
					if(questionBank.getQuestion().get(k).getNumber() == num) {
						q = questionBank.getQuestion().get(k);
						q.setScore(testPaper.get(i).getNumScore().get(j)[1]);
						found = 1;
						break;
					}
				}
				// found == 0,那麼也建立一個,同時只給這題目賦值題號
				// 若是日後,則判斷他的題目是不是bank
				if(found == 0) {
					q.setNumber(num);
				}
				// 加進去題目
				testPaper.get(i).getQuestion().add(q);
			}
			
		}
	}
	
	// 輸出試卷不足100分警示資訊
	public void lackScoreOutput() {
		for(int i = 0; i < testPaper.size(); i++) {
			int cnt = 0;
			for(int j = 0; j < testPaper.get(i).getNumScore().size(); j++) {
				// 這裡有個爭議,就是要是一張卷子加一起滿足100分,但是又被刪除了一題,它後面是不是輸出不是滿分警示呢?
				if(testPaper.get(i).getQuestion().get(j).isExist() == true)
					cnt = cnt + testPaper.get(i).getQuestion().get(j).getScore();
			}
			if(cnt != 100) {
				view.alertMenu(i);
			}
		}
	}
	
	
	public void judgeAnswer() {
		// 遍歷所有答題的卷子
		for(int i = 0; i < answerSheet.getAnswer().size(); i++) {
			// 找這張答卷對應的試卷p
			int number = answerSheet.getAnswer().get(i).getNumber();
			int paperFound = 0;
			TestPaper p = null;
			for(int w = 0; w < testPaper.size(); w++) {
				if(number == testPaper.get(w).getNumber()) {
					p = testPaper.get(w);
					paperFound = 1;
					break;
				}
			}
			// 判斷找沒找得到這張試卷
			if(paperFound == 0) {
				view.notExitPaperNumber();
				continue;
			}
			// 把臨時p的分數變為0全部
			ArrayList<Integer[]> numScore0 = new ArrayList<Integer[]>();
			for(int j = 0; j < p.getQuestion().size(); j++) {				
					Integer noScore[] = {p.getNumScore().get(j)[0],0};
					numScore0.add(noScore);
			}
			// 得到了第i張答題卷子
			// j應當小於對應的試卷的題目數量,因為多的題目直接忽略-answerSheet.getAnswer().get(i).getNoAnswer().size()
			for(int j = 0; j < p.getQuestion().size(); j++) {
				// 得到對應試卷的第j個問題
				Question q = p.getQuestion().get(j);
				int questionFound = 0;
				int answerk = 0;
				for(int k = 0; k < answerSheet.getAnswer().get(i).getNoAnswer().size(); k++) {
					// 如果第j個問題==答卷的題號
					if(j+1 == answerSheet.getAnswer().get(i).getNoScore().get(k)[0]) {
						questionFound = 1;
						answerk = k;
						break;
					}
				}
				// 試卷的這一題在答卷中沒找到
				if(questionFound == 0) {
					view.answerNullMenu();
					continue;
				}
				// 引用了錯誤題號
				if(q.getContent().equals("bank")){
					view.existentMenu();
					continue;
				}
				// 題目是被刪除了的
				if(q.isExist() == false) {
					view.invalidMenu(j+1);
					continue;
				}

				// 得到這張卷子的對應的答案
				String selfAnswer = answerSheet.getAnswer().get(i).getNoAnswer().get(answerk)[1];
				if(selfAnswer.equals(q.getStandAnswer())) {
					Integer noScore[] = {p.getNumScore().get(j)[0],p.getNumScore().get(j)[1]};
					numScore0.set(j, noScore);
					System.out.println(q.getContent()+"~"+q.getStandAnswer()+"~true");
				}
				else {
					System.out.println(q.getContent()+"~"+selfAnswer+"~false");
				}						
			}
			int cnt = 0;
			int stuFound = 0;
			for(int j = 0; j < student.size(); j++) {
				if(student.get(j).getId().equals(answerSheet.getAnswer().get(i).getId())) {
					System.out.print(student.get(j).getId()+" "+student.get(j).getName()+":");
					stuFound = 1;
					break;
				}
			}
			if(stuFound == 0) {
				System.out.println(answerSheet.getAnswer().get(i).getId()+" not found");
				continue;
			}
			for(int j = 0; j < numScore0.size(); j++) {
				cnt = cnt + numScore0.get(j)[1];
				System.out.print(" "+numScore0.get(j)[1]);
			}
			System.out.println("~"+cnt);
		}
		
	}

	
}

// 儲存輸出類
class View  {
	
	public void wrongMenu(String info) {
		System.out.println("wrong format:"+info);
	}
	
	public void alertMenu(int i) {
		System.out.println("alert: full score of test paper"+ (i+1) + " is not 100 points");
	}
	
	public void notExitPaperNumber() {
		System.out.println("The test paper number does not exist");
	}
	
	public void answerNullMenu() {
		System.out.println("answer is null");
	}
	
	public void invalidMenu(int no) {
		System.out.println("the question "+(no)+" invalid~0");
	}
	
	public void existentMenu() {
		System.out.println("non-existent question~0");
	}
}

程式碼結構如圖所示——

南昌航空大學大一下學期java-題目集1~3總結性Blog——蘇禮順23201608

分析自己的程式碼:

1.主方法進行資訊的讀入:因為會有錯誤資訊的輸入所以要進行正規表示式的匹配,只是之前的contains是遠不能足以勝任的。當輸入的資訊匹配這種模式的時候,才可能被讀入,否則就輸出出來。但是我的正規表示式太長太複雜了。可讀性非常差,也不利於後面的程式碼的維護。

2.比上次好的是,增加了controller類,裡面的各種方法來進行對資訊的輸入切割與處理判斷。

3.controller來進行對nstxd的讀入,以及組裝試卷compose功能,judgeAnswer功能。降低了其他實體類之間的耦合度。

4.而view類則存放輸出語句,提高程式碼的覆用性。

根據SOURCEMONITIOR生成的情況來看:

南昌航空大學大一下學期java-題目集1~3總結性Blog——蘇禮順23201608

根據資料與雷達圖分析:

  • 分支語句佔總語句數的百分比為 14.2%。仍然處於較低的水平,保持。
  • 方法呼叫語句數目為131,這次與上次相比增加很多,說明了這段程式碼的模組化程度比上次更高,但也是可能因為這段程式碼的難度比上次的進一步更大的緣故。
  • 這段程式碼的平均深度與最大深度都比較適中
  • 每個方法的平均語句數量比較少,這一點估計是因為controller類中一個大迴圈幹了很多功能的緣故。

三、踩坑心得

  1.在寫第二次題目集的時候,自己其實寫了兩遍。第一遍的時候因為命名不規範,一個是題目編號,一個是題目序號,搞得比較亂,還有試卷與答卷內部屬性的命名都非常地像,導致後面在那個遍歷試卷的迴圈的時候,自己都看不懂自己的程式碼,很難再進行下去的時候,就花費了一兩個小時重新把程式碼寫了一遍,邏輯更加清晰,而且程式碼命名也得到了最佳化。
  2.在寫第三次的程式碼的時候,起初對於題目輸入的錯誤資訊,想的太單純了,以為只是只有題目資訊會出輸入形式錯誤,因此只是對題目資訊的輸入做了判斷,實際上是所有的資訊都會有可能是 錯誤的。因此自己將contains函式改成了matches函式,匹配題目要求的模式,否則的話就會認為是錯誤輸入,這其中正規表示式的處理最為難辦。
  3.在處理判斷分數的那一節的時候,自己一開始用的是hashmap,因為想的是每一題正好對應每一個分數,但是hashmap是無序的,無法記錄插入順序,而且hashmap的key與value並不好遍歷,在處理分數的時候,原本每一題分數的儲存我是放在了answer裡面,然後在判斷對錯的時候再將分數提取出來,對的給他賦值上原本的分數,否則就是為0。最後我是用了arraylist,還是它最香。
  4.有一個比較噁心的是我自己一開始題目沒看清,不知道最後分數輸出的順序是按照試卷的順序來進行輸出的,我一開始是按照自己答題的順序來進行輸出,於是就呵呵呵了。所以導致最後的四個測試點老是不過,最終在那天晚上1點多的時候,經過再一次檢視題目,改變我的分數輸出順序,oh year!終於一下子過了三個。

四、改進建議

  鑑於最後一題目是迭代的,所以我的最終的改進建議只是在最後一題的基礎上提出改進想法

  1.在主方法中,修改掉那個大迴圈,只是讀入一條語句,然後交由controller進行匹配,匹配到某種資訊再進行切割。

  2.切割設定一個方法,用於不同型別的切割,也方便對後續的不同的切割型別進行繼承。

  3.主類的形式大體不會改變,question儲存單個題目資訊,queationBank儲存多個題目,構成題庫,testPaper是對應的試卷。但是Answer由儲存一個答卷改為儲存一道答案,包括他的序號,答案,分數。為後續的增加多選題與填空題做準備。AnswerPaper是組裝試題卷。

  4.對於大迴圈中,將主要只是進行遍歷,判斷的事情另寫一個方法,交由那個方法,降低程式碼深度。

五、總結

終於啊。今天上從9點開始手打敲到了下午5點多!就只是今天的打字,還不算我之前的打字的數目,我的輸入法就剛告訴我已經打了4931個字。好了言歸正傳。

這幾次pta真的寫的令我酣暢淋漓,令我等膽顫心驚。前一秒還大風捲我三重茅,舉杯銷愁愁更愁。後一秒就千樹萬樹梨花開,一日看盡長安花了。

其實總結看來,現在回首,之前的題目也不是有多難。現在閉著眼睛都能把題目複述一遍。可能很大的情況就是畏難情緒,以及看到別人得到分了時候讓你急躁。其餘就只是自己的認真讀懂題目 ,多讀幾遍,一定多讀幾遍,把需求看清了,然後按照需求來寫!寫錯了大不了重新刪了重新來過唄,也不是要死要活的,畢竟提升程式碼能力,鍛鍊設計能力才是正道!!然後平常注意休息,保持精神充沛,提高寫程式碼時的專注度,也為自己日後某天猛熬夜做準備。

自己的邊寫邊除錯的習慣是蠻好的。當寫完一個模組的時候,就自己除錯驗證他的正確性,保證程式碼的正確。

需要提升的就是自己的效率了,要是別人和我同時寫程式碼,我可能要讀題目理解題目,構思好長時間,而構思的程度也可能是和別人差不多的。所以這部分要加強。

相關文章