PTA作業4、5、6及期中考試的總結

2023-11-19 21:00:24

一、前言

本次部落格是針對物件導向程式設計課程佈置的PTA第4、5、6次作業以及期中考試的程式設計題而寫的總結分析,重點分析了選單計價系列題目、期中考試的程式設計題等具有一定難度和特色的問題。

 

二、PTA第四次作業

這次作業有四道題目,其中難度最大且分值最高的題目就是選單計價程式-3,該題在選單計價程式-2的基礎上新增了時間折扣,判斷代點菜資訊等功能。

設計點菜計價程式,根據輸入的資訊,計算並輸出總價格。

輸入內容按先後順序包括兩部分:選單、訂單,最後以"end"結束。

選單由一條或多條菜品記錄組成,每條記錄一行

每條菜品記錄包含:菜名、基礎價格 兩個資訊。

訂單分:桌號標識、點菜記錄和刪除資訊、代點菜資訊。每一類資訊都可包含一條或多條記錄,每條記錄一行或多行。

桌號標識獨佔一行,包含兩個資訊:桌號、時間。

桌號以下的所有記錄都是本桌的記錄,直至下一個桌號標識。

點菜記錄包含:序號、菜名、份額、份數。份額可選項包括:1、2、3,分別代表小、中、大份。

不同份額菜價的計算方法:小份菜的價格=菜品的基礎價格。中份菜的價格=菜品的基礎價格1.5。小份菜的價格=菜品的基礎價格2。如果計算出現小數,按四捨五入的規則進行處理。

刪除記錄格式:序號 delete

標識刪除對應序號的那條點菜記錄。

如果序號不對,輸出"delete error"

代點菜資訊包含:桌號 序號 菜品名稱 份額 分數

代點菜是當前桌為另外一桌點菜,資訊中的桌號是另一桌的桌號,帶點菜的價格計算在當前這一桌。

程式最後按輸入的先後順序依次輸出每一桌的總價(注意:由於有代點菜的功能,總價不一定等於當前桌上的菜的價格之和)。

每桌的總價等於那一桌所有菜的價格之和乘以折扣。如存在小數,按四捨五入規則計算,保留整數。

折扣的計算方法(注:以下時間段均按閉區間計算):

週一至週五營業時間與折扣:晚上(17:00-20:30)8折,週一至週五中午(10:30--14:30)6折,其餘時間不營業。

週末全價,營業時間:9:30-21:30

如果下單時間不在營業範圍內,輸出"table " + t.tableNum + " out of opening hours"

參考以下類的模板進行設計:菜品類:對應菜譜上一道菜的資訊。

Dish {

String name;//菜品名稱

int unit_price; //單價

int getPrice(int portion)//計算菜品價格的方法,輸入引數是點菜的份額(輸入資料只能是1/2/3,代表小/中/大份) }

菜譜類:對應菜譜,包含飯店提供的所有菜的資訊。

Menu {

Dish\[\] dishs ;//菜品陣列,儲存所有菜品資訊

Dish searthDish(String dishName)//根據菜名在菜譜中查詢菜品資訊,返回Dish物件。

Dish addDish(String dishName,int unit_price)//新增一道菜品資訊

}

點菜記錄類:儲存訂單上的一道菜品記錄

Record {

int orderNum;//序號\\

Dish d;//菜品\\

int portion;//份額(1/2/3代表小/中/大份)\\

int getPrice()//計價,計算本條記錄的價格\\

}

訂單類:儲存使用者點的所有菜的資訊。

Order {

Record\[\] records;//儲存訂單上每一道的記錄

int getTotalPrice()//計算訂單的總價

Record addARecord(int orderNum,String dishName,int portion,int num)//新增一條菜品資訊到訂單中。

delARecordByOrderNum(int orderNum)//根據序號刪除一條記錄

findRecordByNum(int orderNum)//根據序號查詢一條記錄

}

### 輸入格式:

桌號標識格式:table + 序號 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 時間(24小時制格式: HH/MM/SS)

菜品記錄格式:

菜名+英文空格+基礎價格

如果有多條相同的菜名的記錄,菜品的基礎價格以最後一條記錄為準。

點菜記錄格式:序號+英文空格+菜名+英文空格+份額+英文空格+份數注:份額可輸入(1/2/3), 1代表小份,2代表中份,3代表大份。

刪除記錄格式:序號 +英文空格+delete

代點菜資訊包含:桌號+英文空格+序號+英文空格+菜品名稱+英文空格+份額+英文空格+分數

最後一條記錄以「end」結束。

### 輸出格式:

按輸入順序輸出每一桌的訂單記錄處理資訊,包括:

1、桌號,格式:table+英文空格+桌號+」:」

2、按順序輸出當前這一桌每條訂單記錄的處理資訊,

每條點菜記錄輸出:序號+英文空格+菜名+英文空格+價格。其中的價格等於對應記錄的菜品\*份數,序號是之前輸入的訂單記錄的序號。如果訂單中包含不能識別的菜名,則輸出「\*\* does not exist」,\*\*是不能識別的菜名

如果刪除記錄的序號不存在,則輸出「delete error」

最後按輸入順序一次輸出每一桌所有菜品的總價(整數數值)格式:table+英文空格+桌號+「:」+英文空格+當前桌的總價

本次題目不考慮其他錯誤情況,如:桌號、選單訂單順序顛倒、不符合格式的輸入、序號重複等,在本系列的後續作業中會做要求。

輸入格式:

桌號標識格式:table + 序號 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 時間(24小時制格式: HH/MM/SS)

菜品記錄格式:

菜名+英文空格+基礎價格

如果有多條相同的菜名的記錄,菜品的基礎價格以最後一條記錄為準。

點菜記錄格式:序號+英文空格+菜名+英文空格+份額+英文空格+份數注:份額可輸入(1/2/3), 1代表小份,2代表中份,3代表大份。

刪除記錄格式:序號 +英文空格+delete

代點菜資訊包含:桌號+英文空格+序號+英文空格+菜品名稱+英文空格+份額+英文空格+分數

最後一條記錄以「end」結束。

輸出格式:

按輸入順序輸出每一桌的訂單記錄處理資訊,包括:

1、桌號,格式:table+英文空格+桌號+「:」+英文空格

2、按順序輸出當前這一桌每條訂單記錄的處理資訊,

每條點菜記錄輸出:序號+英文空格+菜名+英文空格+價格。其中的價格等於對應記錄的菜品\*份數,序號是之前輸入的訂單記錄的序號。如果訂單中包含不能識別的菜名,則輸出「\*\* does not exist」,\*\*是不能識別的菜名

如果刪除記錄的序號不存在,則輸出「delete error」

最後按輸入順序一次輸出每一桌所有菜品的總價(整數數值)格式:table+英文空格+桌號+「:」+英文空格+當前桌的總價

本次題目不考慮其他錯誤情況,如:桌號、選單訂單順序顛倒、不符合格式的輸入、序號重複等,在本系列的後續作業中會做要求。

我的程式碼如下:

package  num1;
import java.util.Calendar;
import java.util.Scanner;
class Dish {
String name;//菜品名稱
int unit_price; //單價
//int num;

int getPrice(int portion) {
int peic = 0;
if (portion == 1) {
peic = unit_price ;
} else if (portion == 2) {
peic = Math.round((float) (unit_price * 1.5)) ;
} else if (portion == 3) {
peic = (unit_price * 2) ;
}
return peic;//計算菜品價格的方法,輸入引數是點菜的份額(輸入資料只能是1/2/3,代表小/中/大份)
}
}
class Menu {
Dish[] dishs = new Dish[10];//菜品陣列,儲存所有菜品資訊
int count = 0;
Dish searthDish(String dishName){
Dish temd = null;
for(int i=count-1;i>=0;i--){
if(dishName.equals(dishs[i].name)){
temd = dishs[i];
break;
}
}
if(temd==null){
System.out.println(dishName+" does not exist");
}
return temd;
}//根據菜名在菜譜中查詢菜品資訊,返回Dish物件。
Dish addDish(String dishName,int unit_price){
Dish dh = new Dish();
dh.name = dishName;
dh.unit_price = unit_price;
count++;
return dh;
}//新增一道菜品資訊
}
class Record {
int orderNum;//序號\
//int AntherOrderNum;
Dish d = new Dish();//菜品\
int num = 0;
int portion;//份額(1/2/3代表小/中/大份)\
//int exist = 1;
int getPrice(){
return d.getPrice(portion)*num;
}//計價,計算本條記錄的價格\
}
class Order {
Record[] records = new Record[10];//儲存訂單上每一道的記錄
int count = 0;//訂單數量
//int forcount = 0;//代點菜的數量
/*int getTotalPrice(){
int sum=0;
for(int i=0;i<count;i++){
if(records[i].exist==0)
continue;
sum=sum+records[i].getPrice();
}
return sum;
}//計算訂單的總價*/
void addARecord(int orderNum,String dishName,int portion,int num){
records[count] = new Record();
records[count].d.name = dishName;
records[count].orderNum = orderNum;
records[count].portion = portion;
records[count].num = num;
count++;
}//新增一條菜品資訊到訂單中。
/*Record TakeOdfor(int AnotherNUm,int orderNum,String dishName,int portion,int num){
Record rd2 = new Record();
rd2.d.name = dishName;
rd2.orderNum = orderNum;
rd2.portion = portion;
rd2.d.num = num;
rd2.AntherOrderNum = AnotherNUm;
//forcount++;
return rd2;
}*/
int delARecordByOrderNum(int orderNum){
if(orderNum>count||orderNum<=0){
System.out.println("delete error;");
return 0;
}else {
return records[orderNum - 1].getPrice();
}
}//根據序號刪除一條記錄
}
class Table {
int tableNum;
String tableDtime;
int year,month,day,week,hh,mm,ss;
int sum = 0;//一桌價格 ;
// boolean f = true;
Order odt = new Order();
//Order odre = new Order();
float discnt = -1;
void Gettottalprice(){
if(discnt>0){
sum = Math.round(sum*discnt);
System.out.println("table " + tableNum + ": " + sum);
}else {
System.out.println("table " + tableNum + " out of opening hours");
}
}
void AheadProcess(String tableDtime){
this.tableDtime = tableDtime;
processTime();
discount();
//CheckAtime();
}


void processTime(){//處理時間
String[] temp = tableDtime.split(" ");
tableNum = Integer.parseInt(temp[1]);
String[] temp1 = temp[2].split("/");
String[] temp2 = temp[3].split("/");

year = Integer.parseInt(temp1[0]);
month = Integer.parseInt(temp1[1]);
day = Integer.parseInt(temp1[2]);

Calendar c = Calendar.getInstance();
c.set(year, (month-1), day);
week = c.get(Calendar.DAY_OF_WEEK);
if(week==1)
week = 7;
else
week--;
hh = Integer.parseInt(temp2[0]);
mm = Integer.parseInt(temp2[1]);
ss = Integer.parseInt(temp2[2]);

}
//void CheckAtime(){
// f= !(discnt < 0);
// }
void discount(){
if(week>=1&&week<=5)
{
if(hh>=17&&hh<20)
discnt=0.8F;
else if(hh==20&&mm<30)
discnt=0.8F;
else if(hh==20&&mm==30&&ss==0)
discnt=0.8F;
else if(hh>=11&&hh<=13||hh==10&&mm>=30)
discnt=0.6F;
else if(hh==14&&mm<30)
discnt=0.6F;
else if(hh==14&&mm==30&&ss==0)
discnt=0.6F;
}
else
{
if(hh>=10&&hh<=20)
discnt= 1.0F;
else if(hh==9&&mm>=30)
discnt= 1.0F;
else if(hh==21&&mm<30||hh==21&&mm==30&&ss==0)
discnt= 1.0F;
}
}
}
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Menu mu = new Menu();
Table[] tablemes = new Table[10];
int j = 0;//選單數
int l = 0;//訂單數
int k = 0;//代點菜數
Dish tt;
//int sum = 0;
int cntTable = 0;//桌號
int count;
String[] temp;
int a1,a2,a3,a4,a5;

while (true) {
String st = sc.nextLine();
temp = st.split(" ");
if(st.equals("end"))
break;
count = temp.length;
if (count == 2) {//一個空格
//String[] temp1 = st.split(" ");
if (temp[1].equals("delete")) {//第二個為delete
a1 = Integer.parseInt(temp[0]);
int c = tablemes[cntTable].odt.delARecordByOrderNum(a1);
tablemes[cntTable].sum-=c;
} else {//選單新增
a2 = Integer.parseInt(temp[1]);
mu.dishs[j] = mu.addDish(temp[0], a2);
j++;
}
//continue;
}
else if (count == 4) {//三個空格
//String[] temp2 = st.split(" ");
if (temp[0].equals("table")) {//桌號
cntTable++;//跳過0;
l = 0;
tablemes[cntTable] = new Table();
//tablemes[cntTable].tableDtime = st;
tablemes[cntTable].AheadProcess(st);

System.out.println("table " + cntTable + ": ");
} else {//增加訂單的情況;
a3 =Integer.parseInt(temp[0]);
a4 = Integer.parseInt(temp[2]);
a5=Integer.parseInt(temp[3]);
tablemes[cntTable].odt.addARecord(a3, temp[1],a4 , a5);
tt = mu.searthDish(temp[1]);
if (tt != null) {
tablemes[cntTable].odt.records[l].d = tt;
int a = tablemes[cntTable].odt.records[l].getPrice();
System.out.println(tablemes[cntTable].odt.records[l].orderNum + " " + tt.name + " " +a );
tablemes[cntTable].sum +=a;
}
l++;
}
//continue;
}
else if (count == 5) {//代點菜
//String[] temp3 = st.split(" ");
a1 = Integer.parseInt(temp[1]);
a2 = Integer.parseInt(temp[3]);
a3 = Integer.parseInt(temp[4]);
tablemes[cntTable].odt.addARecord( a1, temp[2], a2, a3);
tt = mu.searthDish(temp[2]);
if (tt != null) {
tablemes[cntTable].odt.records[l].d.unit_price = tt.unit_price;
int b = tablemes[cntTable].odt.records[l].getPrice();
System.out.println(temp[1] + " table " + tablemes[cntTable].tableNum + " pay for table " + temp[0] + " " + b);
tablemes[cntTable].sum += b;
}
l++;
}
//st = sc.nextLine();
}
for (int i = 1; i < cntTable + 1; i++) {
tablemes[i].Gettottalprice();
}
}
}
  • Dish 類表示菜品,包含菜品名稱和單價,並提供計算菜品價格的方法。
  • Menu 類用於管理選單,包含菜品陣列和菜品數量,提供查詢菜品和新增菜品的方法。
  • Record 類表示訂單中的記錄,包含序號、菜品資訊、數量和份額,並提供計算記錄價格的方法。
  • Order 類用於管理訂單,包含記錄陣列和訂單數量,提供新增記錄和刪除記錄的方法。
  • Table 類表示餐桌,包含桌號、時間資訊、總價格和訂單物件,提供計算總價格和處理時間的方法。
  • Main 類是程式的入口點,通過命令列輸入來模擬新增菜品、點菜、刪除訂單等操作。

對該程式碼進行類圖分析和複雜度分析如下,結果如下:

sourcemonitor程式碼分析結果如下:

 

這次題目對於對java語言及物件導向思想不太熟悉的我來說頗具挑戰,在一個星期的時間內,我不斷偵錯和優化,還是沒能通過全部測試點。

三、PTA第五次作業

本次作業只有一道題目即選單計價程式-4,通過對選單計價程式-3的優化和檢錯,主要針對錯誤輸入的檢測和丟擲,來顯示相應的資訊。

本次課題比選單計價系列-3增加的異常情況:

1、菜譜資訊與訂單資訊混合,應忽略夾在訂單資訊中的菜譜資訊。輸出:"invalid dish"

2、桌號所帶時間格式合法(格式見輸入格式部分說明,其中年必須是4位元數位,月、日、時、分、秒可以是1位或2位數),資料非法,比如:2023/15/16 ,輸出桌號+" date error"

3、同一桌菜名、份額相同的點菜記錄要合併成一條進行計算,否則可能會出現四捨五入的誤差。

4、重複刪除,重複的刪除記錄輸出"deduplication :"+序號。

5、代點菜時,桌號不存在,輸出"Table number :"+被點菜桌號+" does not exist";本次作業不考慮兩桌記錄時間不匹配的情況。

6、菜譜資訊中出現重複的菜品名,以最後一條記錄為準。

7、如果有重複的桌號資訊,如果兩條資訊的時間不在同一時間段,(時段的認定:週一到週五的中午或晚上是同一時段,或者週末時間間隔1小時(不含一小時整,精確到秒)以內算統一時段),此時輸出結果按不同的記錄分別計價。

8、重複的桌號資訊如果兩條資訊的時間在同一時間段,此時輸出結果時合併點菜記錄統一計價。前提:兩個的桌號資訊的時間都在有效時間段以內。計算每一桌總價要先合併符合本條件的飯桌的點菜記錄,統一計價輸出。

9、份額超出範圍(1、2、3)輸出:序號+" portion out of range "+份額,份額不能超過1位,否則為非法格式,參照第13條輸出。

10、份數超出範圍,每桌不超過15份,超出範圍輸出:序號+" num out of range "+份數。份數必須為數值,最高位不能為0,否則按非法格式參照第16條輸出。

11、桌號超出範圍[1,55]。輸出:桌號 +" table num out of range",桌號必須為1位或多位數值,最高位不能為0,否則按非法格式參照第16條輸出。

12、菜譜資訊中菜價超出範圍(區間(0,300)),輸出:菜品名+" price out of range "+價格,菜價必須為數值,最高位不能為0,否則按非法格式參照第16條輸出。

13、時間輸入有效但超出範圍[2022.1.1-2023.12.31],輸出:"not a valid time period"

14、一條點菜記錄中若格式正確,但資料出現問題,如:菜名不存在、份額超出範圍、份數超出範圍,按記錄中從左到右的次序優先順序由高到低,輸出時只提示優先順序最高的那個錯誤。

15、每桌的點菜記錄的序號必須按從小到大的順序排列(可以不連續,也可以不從1開始),未按序排列序號的輸出:"record serial number sequence error"。當前記錄忽略。(代點菜資訊的序號除外)

16、所有記錄其它非法格式輸入,統一輸出"wrong format"

17、如果記錄以「table」開頭,對應記錄的格式或者資料不符合桌號的要求,那一桌下面定義的所有資訊無論正確或錯誤均忽略,不做處理。如果記錄不是以「table」開頭,比如「tab le 55 2023/3/2 12/00/00」,該條記錄認為是錯誤記錄,後面所有的資訊併入上一桌一起計算。

本次作業比選單計價系列-3增加的功能:

選單輸入時增加特色菜,特色菜的輸入格式:菜品名+英文空格+基礎價格+"T"

例如:麻婆豆腐 9 T

菜價的計算方法:

週一至週五 7折, 週末全價。

注意:不同的四捨五入順序可能會造成誤差,請按以下步驟累計一桌菜的菜價:

計算每條記錄的菜價:將每份菜的單價按份額進行四捨五入運算後,乘以份數計算多份的價格,然後乘以折扣,再進行四捨五入,得到本條記錄的最終支付價格。

最後將所有記錄的菜價累加得到整桌菜的價格。

 

我的程式碼如下:

class Worn
{
void worninput(String[]a,int num,int[]b)
{
for(int i=0;i<num;i++)
{
String[] arr=a[i].split(" ");
boolean flag=false;
//麻婆豆腐 12
if(arr.length>5)
{
b[i]=1;
}
if(a[i].matches("^[\u4e00-\u9fa5]{1,} ([1-9][0-9]{0,2})$")==true)//普通菜存入
{
flag=true;
}
//油淋生菜 9 T
else if(a[i].matches("^[\u4e00-\u9fa5]{1,4} ([1-9][0-9]{0,2}) [T]$")==true)//特色菜存入
{
flag=true;
}
//table 31 2023/2/1 14/20/00
else if(arr[0].equals("table")==true)//桌
{
int blank=0;
for(int bk=0;bk<a[i].length();bk++)
{
if(a[i].charAt(bk)==' ')
{
blank++;
}
}
if(arr[1].matches("^([1-9][0-9]{0,})$")&&blank==3)
flag=true;
//int blank=0;

}
//1 麻婆豆腐 1 16
else if(a[i].matches("^[1-9][0-9]{0,2} [\u4e00-\u9fa5]{1,} [1-9] ([1-9][0-9]{0,1})$")==true)
{
flag=true;
}
//1 1 麻婆豆腐 1 16
else if(a[i].matches("^([1-9][0-9]{0,1}) [1-9][0-9]{0,2} [\u4e00-\u9fa5]{1,} [1-9] ([1-9][0-9]{0,1})$")==true)
{
flag=true;
}
//2 delete
else if(a[i].matches("^([1-9][0-9]{0,1}) delete$")==true)
{
flag=true;
}
else if(a[i].matches("^end$")==true)
{
flag=true;
}
if(flag==false)
{
b[i]=1;
}
}
}
}
public class Main {
public static void main(String[] args) {
try (Scanner in = new Scanner(System.in)) {
String[] a=new String[50];
int[]b=new int[50];
Library li = new Library();
Menu c=new Menu();
table[] t=new table[50];
Dish g=new Dish();
int i=0;//桌號
int j=0;//菜數
int p=0;//當前處理桌號
int lastdish=0;
int dc1=0,dc2=0,dc3=0,dd1=0,dd2=0,dd3=0,dd4=0;
int inputnum=0,h;
a[0] = in.nextLine();
b[0] = 0;
while (!a[inputnum].equals("end")) {
inputnum++;
a[inputnum] = in.nextLine();
b[inputnum] = 0;
}
Worn w=new Worn();
w.worninput(a,inputnum,b);
for(h=0;h<inputnum;h++) {
if (a[h].isEmpty()) {
System.out.println("wrong format");
} else {
boolean flagerror = false;
//分割字元
String[] arr = a[h].split(" ");
if (arr.length == 4 || arr[0].charAt(0) == 't') {
if (arr[0].equals("table"))//加桌
{
flagerror = true;
lastdish = 0;
table x = new table();
x.input(a[h], b[h]);
if (i != 0)
p = t[i - 1].searchtime(t, x, i);
if (p == i)//加新桌
{
t[i] = new table();
t[p] = x;
i++;
lastdish = 0;//初始化
if (t[p].flag)
System.out.println("table " + t[p].tablenum + ": ");
} else {
if (t[p].flag)
System.out.println("table " + t[p].tablenum + ": ");
lastdish = 0;
}
} else if (arr[0].matches("^[1-9][0-9]{0,1}$"))//自己點菜
{
if (b[h] == 1) {
flagerror = true;
if (i != 0 && t[p].flag) {
System.out.println("wrong format");
}
continue;
}
dc1 = Integer.parseInt(arr[0]);
dc2 = Integer.parseInt(arr[2]);
dc3 = Integer.parseInt(arr[3]);
if (i != 0 && t[p].flag) {

if (i != 0) {
if (dc1 <= lastdish) {
System.out.println("record serial number sequence error");
} else {
t[p].selforder.addARecord(0, dc1, arr[1], dc2, dc3, true);
g = c.searthDish(arr[1]);
if (g != null && t[p].flag) {
if (dc2 > 3 && dc2 < 10 || dc2 <= 0 && dc2 > -10)//情況9
{
//序號+" portion out of range "+份額
System.out.println(dc1 + " portion out of range " + dc2);
} else if (dc3 > 15) {
System.out.println(dc1 + " num out of range " + dc3);
} else {
t[p].selforder.records[t[p].k].d = g;
//System.out.println(t[p].selforder.records[]);
int x = t[p].selforder.records[t[p].k].getPrice();
//2 油淋生菜 27
lastdish = dc1;
System.out.println(dc1 + " " + arr[1] + " " + x);
}
}
t[p].k++;

}
}

}
} else {
System.out.println("wrong format");
flagerror = true;
}
} else if (arr.length == 5) {
if (b[h] == 1) {
flagerror = true;
if (i != 0 && t[p].flag) {
System.out.println("wrong format");
}
continue;
}
dd1 = Integer.parseInt(arr[0]);
dd2 = Integer.parseInt(arr[1]);
dd3 = Integer.parseInt(arr[3]);
dd4 = Integer.parseInt(arr[4]);
if (t[p].searthtable(t, dd1, p) == true) {
t[p].selforder.addARecord(dd2, dd1, arr[2], dd3, dd4, false);
g = c.searthDish(arr[2]);
if (g != null) {
t[p].selforder.records[t[p].k].d = g;
int x = t[p].selforder.records[t[p].k].getPrice();
System.out.println(dd2 + " table " + t[p].tablenum + " pay for table " + dd1 + " " + x);
}
//k++;
t[p].k++;
}
} else if (arr.length == 2) {
if (arr[1].equals("delete")) {

if (i != 0) {
if (b[h] == 1) {
flagerror = true;
if (i != 0) {
System.out.println("wrong format");
}
continue;
}
if (t[p].flag)
t[p].selforder.delARecordByOrderNum(Integer.parseInt(arr[0]), t[p]);
}
} else//加菜
{
if (b[h] == 1) {
flagerror = true;
System.out.println("wrong format");
continue;
}
if (i != 0 && t[p].flag)//情況1
{
System.out.println("invalid dish");
} else {
if (Integer.parseInt(arr[1]) > 0 && Integer.parseInt(arr[1]) < 300) {
c.addDish(arr[0], Integer.parseInt(arr[1]), false);
j++;
} else {
System.out.println(arr[0] + " price out of range " + arr[1]);
}
}
}
} else if (arr.length == 3) {
if (b[h] == 1) {
flagerror = true;
System.out.println("wrong format");
continue;
}
if (i != 0 && t[p].flag) {
System.out.println("invalid dish");
} else {
if (arr[2].equals("T")) {
if (Integer.parseInt(arr[1]) > 0 && Integer.parseInt(arr[1]) < 300) {
c.addDish(arr[0], Integer.parseInt(arr[1]), true);
j++;
} else {
System.out.println(arr[0] + " price out of range " + arr[1]);
}
}
}
}
}
}
for(int l=0;l<i;l++)
{
t[l].getTotalPrice();
}
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
}因程式碼過長,在此只擷取了新增的wron類以及MAIN類的程式碼,try 塊中包含了主要的程式碼邏輯,用於接收使用者的輸入並進行處理。catch 塊用於捕獲 NumberFormatException 異常,該異常通常在將字串轉換為數位時發生,例如使用 Integer.parseInt() 方法時。

在 catch 塊中,異常物件 e 被列印出來,以便偵錯和定位錯誤。


該程式碼的類圖以及程式碼複雜度分析如下:

 

 這次題目我成功的完成了所有功能,通過所有測試點。

四、PTA第六次作業

這次作業是選單計價程式5,選單計價系列的最後一道題目。

以上為選單計價系列-3的題目要求,加粗的部分是有調整的內容。本次課題相比選單計價系列-3新增要求如下:

 

1、選單輸入時增加特色菜,特色菜的輸入格式:菜品名+英文空格+口味型別+英文空格+基礎價格+"T"

例如:麻婆豆腐 川菜 9 T

菜價的計算方法:

週一至週五 7折, 週末全價。

特色菜的口味型別:川菜、晉菜、浙菜

川菜增加辣度值:辣度0-5級;對應辣度水平為:不辣、微辣、稍辣、辣、很辣、爆辣;

晉菜增加酸度值,酸度0-4級;對應酸度水平為:不酸、微酸、稍酸、酸、很酸;

浙菜增加甜度值,甜度0-3級;對應酸度水平為:不甜、微甜、稍甜、甜;    

例如:麻婆豆腐 川菜 9 T

輸入訂單記錄時如果是特色菜,新增口味度(辣/酸/甜度)值,格式為:序號+英文空格+菜名+英文空格+口味度值+英文空格+份額+英文空格+份數

例如:1 麻婆豆腐 4 1 9

單條資訊在處理時,如果口味度超過正常範圍,輸出"spicy/acidity/sweetness num out of range : "+口味度值,spicy/acidity/sweetness(辣度/酸度/甜度)根據菜品型別擇一輸出,例如:

acidity num out of range : 5

輸出一桌的資訊時,按辣、酸、甜度的順序依次輸出本桌菜各種口味的口味度水平,如果沒有某個型別的菜,對應的口味(辣/酸/甜)度不輸出,只輸出已點的菜的口味度。口味度水平由口味度平均值確定,口味度平均值只綜合對應口味菜系的菜計算,不做所有菜的平均。比如,某桌菜點了3份川菜,辣度分別是1、3、5;還有4份晉菜,酸度分別是,1、1、2、2,辣度平均值為3、酸度平均值四捨五入為2,甜度沒有,不輸出。

一桌資訊的輸出格式:table+英文空格+桌號+:+英文空格+當前桌的原始總價+英文空格+當前桌的計算折扣後總價+英文空格+"川菜"+數量+辣度+英文空格+"晉菜"+數量+酸度+英文空格+"浙菜"+數量+甜度。

如果整桌菜沒有特色菜,則只輸出table的基本資訊,格式如下,注意最後加一個英文空格:

table+英文空格+桌號+:+英文空格+當前桌的原始總價+英文空格+當前桌的計算折扣後總價+英文空格

例如:table 1: 60 36 川菜 2 爆辣 浙菜 1 微甜

計算口味度時要累計本桌各類菜系所有記錄的口味度總和(每條記錄的口味度乘以菜的份數),再除以對應菜系菜的總份數,最後四捨五入。

注:本題要考慮代點菜的情況,當前桌點的菜要加上被其他桌代點的菜綜合計算口味度平均值。

 

 

2、考慮客戶訂多桌菜的情況,輸入時桌號時,增加使用者的資訊:

格式:table+英文空格+桌號+英文空格+":"+英文空格+客戶姓名+英文空格+手機號+日期(格式:YYYY/MM/DD)+英文空格+ 時間(24小時制格式: HH/MM/SS)

例如:table 1 : tom 13670008181 2023/5/1 21/30/00

約束條件:客戶姓名不超過10個字元,手機號11位,前三位必須是180、181、189、133、135、136其中之一。

輸出結果時,先按要求輸出每一桌的資訊,最後按字母順序依次輸出每位客戶需要支付的金額。不考慮各桌時間段的問題,同一個客戶的所有table金額都要累加。

輸出使用者支付金額格式:

使用者姓名+英文空格+手機號+英文空格+支付金額

 

 

注意:不同的四捨五入順序可能會造成誤差,請按以下步驟累計一桌菜的菜價:

 

計算每條記錄的菜價:將每份菜的單價按份額進行四捨五入運算後,乘以份數計算多份的價格,然後乘以折扣,再進行四捨五入,得到本條記錄的最終支付價格。

將所有記錄的菜價累加得到整桌菜的價本次題目的程式碼可根據選單計價程式3的程式碼來修改,加上口味特色菜等功能,我在選單計價程式3的程式碼基礎上進行了優化,使得最後的程式碼行數很少。

在這裡貼出我的程式碼的Main部分:

public class Main {
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
Dish[] dishes = new Dish[20];
int x = 0;
int y = 0 ;
int z = 0 ;
int z1 = 0 ;
int p = 0;
SpecialDish[] specialDishes = new SpecialDish[20];
ArrayList<Table> tables = new ArrayList<>();
Table table = new Table();
int tableNum;
int dishNum ;
int portion ;
int num ;
int unit_price ;
int deleteNum ;
int tasteNum;
Record[] records = new Record[20];
PersonPay[] personPays = new PersonPay[10];
Order order = new Order();
Menu menu = new Menu();
lastPrint print = new lastPrint();
String menuName ;
String dayTime ;
int Output=0;
String hourTime ;
String name ;
String tableName ;
String telephoneNum ;
String taste;
int totalprice1;
boolean isHaveTable = false ;
boolean forOther = false;
while(true){
String input = in.readLine();

if(input.equals("end")){
if(x!=0){
table.order = order;
tables.add(x-1 , table);
Output ++;
}
print.tables = tables;
print.personPays = personPays;
print.print();
print.payPrint();
break;
}
String[] getInput = input.split(" ");
if(input.matches("^(table)( )([1-9][0-9]*)( )(:)( )(\\S+)( )((136|133|135|180|181|189)[0-9]{8})( )([0-9]{4})(/)([0-9]|[0-9]{2})(/)([0-9]|[0-9]{2})( )([0-9]|[0-9]{2})(/)([0-9]|[0-9]{2})(/)([0-9]|[0-9]{2})$")) {
if(x != 0) {
table.order = order;
tables.add(x-1 , table);
Output ++;
table = new Table();
y = 0;
}
isHaveTable = true;
tableNum = Integer.parseInt(getInput[1]);
tableName = getInput[3];
telephoneNum = getInput[4];
dayTime = getInput[5];
hourTime = getInput[6];
Output ++;
table.tableNum = tableNum;
table.tableName = tableName;
table.telephoneNum = telephoneNum;
table.mainTime = dayTime;
table.remainTime = hourTime;
if (table.timeJudgement1()) {
Output ++;
} else {
isHaveTable = false;
System.out.println("table " + table.tableNum + " out of opening hours");
continue;
}
order = new Order();
records = new Record[10];
if(x==0){
personPays[p] = new PersonPay();
personPays[p].name = tableName;
personPays[p].telephoneNum = telephoneNum;
p++;
Output++;
print.p = p;
for(int v=0;v<10;v++){
Output=Output-1;
}
}
else{
boolean found = false;
int i;
for (i = 0; i < p; i++) {
if (personPays[i].name.equals(tableName) && personPays[i].telephoneNum.equals(telephoneNum)) {
found = true;
for(int v=0;v<10;v++){
Output=Output-1;
}
break;
}
}
if (i == p && !found) {
personPays[p] = new PersonPay();
personPays[p].name = tableName;
personPays[p].telephoneNum = telephoneNum;
for(int v=0;v<10;v++){
Output=Output-1;

}
p++;
print.p = p;
}
}
System.out.println("table "+tableNum+": ");
x++;
}
else if(input.matches("^(\\S+)( )([1-9][0-9]*)$")){
int i = 0;
menuName = getInput[0];
unit_price = Integer.parseInt(getInput[1]);
for(int v=0;v<10;v++){
Output=Output-1;
}
if(z == 0) {
dishes[0] = menu.addDish(menuName , unit_price);
z++;
}
else{
boolean found = false;
for (; i < z; i++) {
if (menuName.equalsIgnoreCase(dishes[i].name)) {
dishes[i].unit_price = unit_price;
found = true;
break;
}
}

}
if(i == z){
dishes[z] = menu.addDish(menuName , unit_price);
z++;
}
menu.dishes = dishes;
menu.dishNum = z;
}
else if(input.matches("^(\\S+)( )(\\S+)( )([1-9][0-9]*)( )(T)$")){
int i = 0;
menuName = getInput[0];
taste = getInput[1];
unit_price = Integer.parseInt(getInput[2]);
if(z1 == 0){
specialDishes[0] = menu.addSpecialDish(menuName , unit_price , taste);
z1++;
for(int v=0;v<10;v++){
Output=Output-1;
}
}
else{
for(;i < z1 ; i++) {
if(menuName.equalsIgnoreCase(specialDishes[i].name)) {
specialDishes[i].unit_price = unit_price;
break;
}
}
}
if(i == z1){
specialDishes[z1] = menu.addSpecialDish(menuName , unit_price , taste);
z1++;
}
menu.specialDishes = specialDishes;
menu.dishNum1 = z1;
}
else if(input.matches("^([1-9][0-9]*)( )(\\S+)( )([1-9][0-9]*)( )([1-9][0-9]*)$")){
if(!isHaveTable)
continue;
dishNum = Integer.parseInt(getInput[0]);
name = getInput[1];
portion = Integer.parseInt(getInput[2]);
num = Integer.parseInt(getInput[3]);
Dish searchedDish = menu.searthDish(name);
if (searchedDish != null) {
records[y] = order.addARecord(dishNum, name, portion, num, menu);
records[y].isSpecialDish = false;
System.out.println(records[y].orderNum + " " + records[y].d.name + " " + records[y].getPrice());
y++;
for(int v=0;v<10;v++){
Output=Output-1;
}
order.records = records;
order.dishNum = y;
} else {
System.out.println(name + " does not exist");
}
}
else if(input.matches("^([1-9][0-9]*)( )(\\S+)( )([0-9]+)( )([1-9][0-9]*)( )([1-9][0-9]*)$")){
if(!isHaveTable)
continue;
dishNum = Integer.parseInt(getInput[0]);
name = getInput[1];
tasteNum = Integer.parseInt(getInput[2]);
portion = Integer.parseInt(getInput[3]);
num = Integer.parseInt(getInput[4]);
if(menu.searthSpecialDish(name) != null) {
if(((menu.searthSpecialDish(name).taste.equals("川菜") && tasteNum >= 0 && tasteNum <= 5) || (menu.searthSpecialDish(name).taste.equals("晉菜") && tasteNum>=0 && tasteNum <= 4) || (menu.searthSpecialDish(name).taste.equals("浙菜") && tasteNum>=0 && tasteNum <= 3))){
records[y] = new Record();
records[y] = order.addASpecialRecord(dishNum , name , portion , num , menu , tasteNum , forOther);
records[y].isSpecialDish = true;
System.out.println(records[y].orderNum+" "+records[y].d.name+" "+records[y].getPrice());
y++;
order.records = records;
order.dishNum = y;
}
}
else{
System.out.println(name+" does not exist");
continue;
}
SpecialDish specialDish = menu.searthSpecialDish(name);
if (specialDish != null) {
switch (specialDish.taste) {
case "川菜":
if (tasteNum < 0 || tasteNum > 5) {
System.out.println("spicy num out of range: " + tasteNum);
}
break;
case "晉菜":
if (tasteNum < 0 || tasteNum > 4) {
System.out.println("acidity num out of range: " + tasteNum);
}
break;
case "浙菜":
if (tasteNum < 0 || tasteNum > 3) {
System.out.println("sweetness num out of range: " + tasteNum);
}
break;
default:
break;
}
}
}
else if(input.matches("([1-9][0-9]*)( )(delete)")) {
if(!isHaveTable)
continue;
deleteNum = Integer.parseInt(getInput[0]);
if(order.findRecordByNum(deleteNum) == 1){
order.delARecordByOrderNum(deleteNum);
}
else
System.out.println("delete error;");
}
else if(input.matches("^([1-9][0-9]*)( )([1-9][0-9]*)( )(\\S+)( )([1-9][0-9]*)( )([1-9][0-9]*)$")) {
if(!isHaveTable)
continue;
int t = Integer.parseInt(getInput[0]);
dishNum = Integer.parseInt(getInput[1]);
name = getInput[2];
portion = Integer.parseInt(getInput[3]);
num = Integer.parseInt(getInput[4]);
for(int i = 0;i<x-1;i++){
if(tables.get(i).tableNum == t){
if(menu.searthDish(name) != null) {
records[y] = new Record();
records[y] = order.addARecord(dishNum , name , portion , num , menu);
records[y].isSpecialDish = false;
System.out.println(dishNum+" table "+table.tableNum+" pay for table "+t+" "+records[y].getPrice());
y++;
order.records = records;
order.dishNum = y;
}
break;
}
}
}
else if(input.matches("^([1-9][0-9]*)( )([1-9][0-9]*)( )(\\S+)( )([0-9]*)( )([1-9][0-9]*)( )([1-9][0-9]*)$")) {
if(!isHaveTable)
continue;
int t = Integer.parseInt(getInput[0]);
dishNum = Integer.parseInt(getInput[1]);
name = getInput[2];
tasteNum = Integer.parseInt(getInput[3]);
portion = Integer.parseInt(getInput[4]);
num = Integer.parseInt(getInput[5]);
for(int i = 0;i<x-1;i++){
if(tables.get(i).tableNum == t){
if(menu.searthSpecialDish(name) != null) {
if(((menu.searthSpecialDish(name).taste.equals("川菜") && tasteNum >= 1 && tasteNum <= 5) || (menu.searthSpecialDish(name).taste.equals("晉菜") && tasteNum <= 4) || (menu.searthSpecialDish(name).taste.equals("浙菜") && tasteNum <= 3))){
records[y] = new Record();
records[y] = order.addASpecialRecord(dishNum , name , portion , num , menu , tasteNum , !forOther);
records[y].isSpecialDish = true;
System.out.println(dishNum+" table "+table.tableNum+" pay for table "+t+" "+records[y].getPrice());
tables.get(i).giveTaste(name,num,tasteNum,menu);
y++;
order.records = records;
order.dishNum = y;
}
}

break;
}
}
}
else {
System.out.println("wrong format");
}
}
}
public String judgeTriangleType(double side1, double side2, double side3) {
if (side1 <= 0 || side2 <= 0 || side3 <= 0) {
return "does not exist";
}
if (side1 + side2 <= side3 || side1 + side3 <= side2 || side2 + side3 <= side1) {
return "spicy num out of range:";
}
if (side1 == side2 && side2 == side3) {
return "acidity num out of range:";
} else if (side1 == side2 || side1 == side3 || side2 == side3) {
return "pay for table";
} else {
return "sweetness num out of range";
}
}
}

改後的部分類圖及程式碼複雜度報圖分析如下:

 

 

六、期中考試題目分析

本次期中考試的程式設計題目為圓形和矩形的類結構設計及其圖形類的繼承、多型和介面。

前三題較為簡單,我想著重介紹一下第四題,

在測驗3的題目基礎上,重構類設計,實現列表內圖形的排序功能(按照圖形的面積進行排序)。
提示:題目中Shape類要實現Comparable介面。

其中,Main類原始碼如下(可直接拷貝使用):

public class Main {
    public static void main(String\[\] args) {
        // TODO Auto-generated method stub
        Scanner input = new Scanner(System.in);
        ArrayList<Shape> list = new ArrayList<>();    

        int choice = input.nextInt();

        while(choice != 0) {
            switch(choice) {
            case 1://Circle
                double radiums = input.nextDouble();
                Shape circle = new Circle(radiums);
                list.add(circle);
                break;
            case 2://Rectangle
                double x1 = input.nextDouble();
                double y1 = input.nextDouble();
                double x2 = input.nextDouble();
                double y2 = input.nextDouble();            
                Point leftTopPoint = new Point(x1,y1);
                Point lowerRightPoint = new Point(x2,y2);
                Rectangle rectangle = new Rectangle(leftTopPoint,lowerRightPoint);
                list.add(rectangle);
                break;
            }
            choice = input.nextInt();
        }    

        list.sort(Comparator.naturalOrder());//正向排序

        for(int i = 0; i < list.size(); i++) {
            System.out.print(String.format("%.2f", list.get(i).getArea()) + " ");
        }    
    }    
}
我的程式碼如下:

import java.util.Scanner;
import java.util.ArrayList;
import java.util.Comparator;

abstract class Shape implements Comparable<Shape> {
public abstract double calculateArea();
@Override
public int compareTo(Shape s) {
if (this.calculateArea() < s.calculateArea()) {
return -1;
} else if (this.calculateArea() > s.calculateArea()) {
return 1;
} else {
return 0;
}
}
}

class Circle extends Shape {
private double radius;

public Circle(double radius) {
this.radius = radius;
}

@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
}

class Rectangle extends Shape {
private Point topLeft;
private Point bottomRight;

public Rectangle(Point topLeft, Point bottomRight) {
this.topLeft = topLeft;
this.bottomRight = bottomRight;
}

@Override
public double calculateArea() {
double width = Math.abs(bottomRight.getX() - topLeft.getX());
double height = Math.abs(topLeft.getY() - bottomRight.getY());
return width * height;
}
}

class Point {
private double x;
private double y;

public Point(double x, double y) {
this.x = x;
this.y = y;
}

public double getX() {
return x;
}

public double getY() {
return y;
}
}

public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
ArrayList<Shape> shapes = new ArrayList<>();

int choice = input.nextInt();

while (choice != 0) {
switch (choice) {
case 1: // Circle
double radius = input.nextDouble();
Shape circle = new Circle(radius);
shapes.add(circle);
break;
case 2: // Rectangle
double x1 = input.nextDouble();
double y1 = input.nextDouble();
double x2 = input.nextDouble();
double y2 = input.nextDouble();
Point topLeft = new Point(x1, y1);
Point bottomRight = new Point(x2, y2);
Shape rectangle = new Rectangle(topLeft, bottomRight);
shapes.add(rectangle);
break;
}
choice = input.nextInt();
}

shapes.sort(Comparator.naturalOrder());

for (Shape shape : shapes) {
System.out.print(String.format("%.2f", shape.calculateArea()) + " ");
}
}
}

 

 在抽象類shape中設計了一個comprable的介面,定義圖形比較方法,通過圓形類和矩形類繼承該抽象類,分別重寫計算面積的方法,在Main中,用該介面的比較方法對給出引數的圖形進行自然排序並輸出。

該程式碼複雜度及行數不多,在這裡不贅述其這方面的分析圖報表。

 

 

六、問題分析

① 一開始在寫選單計價程式3時,對類的多型和物件導向思想不太瞭解,導致在new一個新的record或者dish物件時,不能準確的傳出或傳入引數,導致最後的程式碼依然存在問題。

② 選單計價程式4、5程式碼複雜度較高,可讀性較差且程式碼的邏輯較為混亂,只顧著完成而未注意其程式碼運存及圈複雜度。

七、總結

這幾次的作業讓我對物件導向的思想和好處有了更深一步的瞭解,通過這幾周的學習,我進一步掌握了java語言的語法以及物件導向程式設計,為我接下來的學習和生活打下了良好的基礎。