一、前言
这三次菜单的更迭,基本每次都是在前一次的基础上增加部分功能,总体改动不是特别大,越到后期菜单系统越完善时功能修改的速度也更快。主要问题在于一开始的框架没有建好,输入信息后对信息的相关处理没有采取一个清晰地任务分割,而是堆砌在了主函数中,大量ifelse语句增加了很多时间复杂度,最近两次课上学习了工厂模式等相关模式设计的知识,希望能在下一次同类型的作业上运用上,避免这次出现的情况。
这三次作业,主要巩固了课上所讲的:类的封装设计、方法重载、类的继承以及正则表达式等相关知识。写的过程中也遇到了许多问题,主要是通过向同学请教以及搜寻了相关资料所习。
最后是关于期中考试,一开始编程题没按老师给的类图设计,结果自测是对的但就是通不过测试点,然后索性完全按老师的类图敲了一遍,就没啥问题了。但是关于接口的知识掌握的不太牢固(一开始不是说不考这些吗救),选择题很多概念性的东西,考的很细,平常还是得多看看书,多巩固基础理论
二、设计与分析
题目详情:
设计点菜计价程序,根据输入的信息,计算并输出总价格。
输入内容按先后顺序包括两部分:菜单、订单,最后以"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+英文空格+桌号+“:”+英文空格+当前桌的总价
本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。
代码:
import java.time.LocalDate; import java.time.LocalTime; import java.util.Scanner; import java.time.format.DateTimeFormatter; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); String message = null; String name = null; String date = null; String time = null; int unit_price = 0; int orderNum = 0; int k1 = 0,k2 = 0; int portion = 0; int num = 0; int tablenum = 0; int for_tableNum = 0; int xuhao = 0; Menu menu = new Menu(); Order[] orders = new Order[20]; for (int i = 0; i < 20; i++) { orders[i] = new Order(); } Table[] tables = new Table[20]; int order_idex = 0; int table_idex = 0; int i =0; O: while(true){ message = input.nextLine(); if(message.equals("end")) break O; //麻烦死了!! else if (message.matches("^table\\s\\d+\\s\\d{4}/\\d{1,2}/\\d{1,2}\\s\\d{1,2}/\\d{1,2}/\\d{1,2}$")) { //如果输入符合桌号订单模式 table_idex++; order_idex++; String[] parts = message.split(" "); tablenum = Integer.parseInt(parts[1]);//桌号 date = parts[2];//日期 time = parts[3];//时间 tables[table_idex] = new Table(tablenum,date,time,0);//创建当前这一桌 //tables[table_idex].sum_price = orders[order_idex].getTotalPrice(); System.out.println("table "+tables[table_idex].num + ": "); //创建当前这一桌的订单,注意,其中order[0]为空,从[1]开始装订单,table同理 } else if (message.matches("^\\d\\s\\d+\\s+[\\p{L}\\p{N}\\p{M}\\p{P}\\p{S}]+\\s+\\d+\\s+\\d+$")) { //如果输出符合代点菜信息 String[] parts = message.split(" "); for_tableNum = Integer.parseInt(parts[0]);//桌号 xuhao = Integer.parseInt(parts[1]);//序号 name = parts[2];//菜名 portion = Integer.parseInt(parts[3]);//份额 num = Integer.parseInt(parts[4]);//份数 //代点函数,输出代点信息,并更改当前桌的总金额 tables[table_idex].daidian(tables[table_idex].num,for_tableNum,xuhao,name,portion,num,menu); //添加一条订单 orders[order_idex].addARecord1(xuhao,name,menu,portion,num);//添加进订单记录 } else if(message.matches("^[\\p{L}\\p{N}\\p{M}\\p{P}\\p{S}]+\\s+\\d+$")){//若符合添加菜单 String[] parts = message.split(" "); name = parts[0]; unit_price = Integer.parseInt(parts[1]); menu.addDish(name,unit_price); }//若符合点菜信息 else if (message.matches("^\\d+\\s+[\\p{L}\\p{N}\\p{M}\\p{P}\\p{S}]+\\s+\\d+\\s+\\d+$")) { String[] parts = message.split(" "); orderNum = Integer.parseInt(parts[0]); name = parts[1]; portion = Integer.parseInt(parts[2]); num = Integer.parseInt(parts[3]); orders[order_idex].addARecord(orderNum,name,menu,portion,num);//添加进订单记录 }//若符合删除信息 else if (message.matches("\\d+\\s+delete+$")){ String[] parts = message.split(" "); orderNum = Integer.parseInt(parts[0]); if(orders[order_idex].findRecordByNum(orderNum)&&orders[order_idex].searchRecord(orderNum).num!=0){//如果在订单里找到了该序号且这个是第一次对这条订单记录进行删除 orders[order_idex].delARecordByOrderNum(orderNum);//机理是使该序号记录的最后份数置0。 }else{//没找到该序号 System.out.println("delete error;"); } }i++; } //算每一桌的钱咯(*^▽^*) for (int k = 1; k <=table_idex; k++) { tables[k].sum_price = orders[k].getTotalPrice(); tables[k].sum_price = tables[k].judge_discount(tables[k].dateString,tables[k].timeString,tables[k].sum_price); if(tables[k].sum_price >= 0) { System.out.println("table " + tables[k].num + ": " + tables[k].sum_price); } } } } //菜品类 class Dish{ String name;//菜品名称 int unit_price; //单价 public Dish(String name,int unit_price){ this.name = name; this.unit_price = unit_price; } public String getName() { return name; } public int getUnit_price() { return unit_price; } //计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) public int getPrice(int portion){ double price = 0; if(portion == 1) { price = Math.round(unit_price); } else if (portion == 2) { price = Math.round(unit_price*1.5); } else if (portion == 3) { price = Math.round(unit_price*2); }return (int)price; } } //菜单类 class Menu{ Dish[] dishes = new Dish[20] ;//动态菜品数组,保存所有菜品信息 int count1 = 0;//计算有多少道菜品 public Menu() { } //根据菜名在菜谱中查找菜品信息,返回Dish对象。 public Dish searchDish(String dishName){ for (int i = 0; i < count1; i++) { if(dishName.equals(dishes[i].name)){ return dishes[i]; } } return null; } //添加一道菜品信息 public void addDish(String dishName,int unit_price) { if (searchDish(dishName) == null) {//如果这道菜还未添加过,则添加 Dish newDish = new Dish(dishName, unit_price); dishes[count1] = newDish; count1++;//菜品数量加一 }else{ //若添加过,则更新这道菜的价格 searchDish(dishName).unit_price = unit_price; } } } //点菜记录类 class Record { int orderNum;//序号\ Dish dish;//菜品\ int portion;//份额(1/2/3代表小/中/大份) //计价,计算本条记录的价格\ int num;//份数 public Record(int orderNum,Dish dish,int portion,int num){ this.orderNum = orderNum; this.dish = dish; this.portion = portion; this.num = num; } public int getOrderNum() { return orderNum; } public int getPrice(){ int price = 0; price = Math.round(dish.getPrice(this.portion)*this.num); return price; } public void show(){//显示当前订单 System.out.print(orderNum + " " + dish.name + " " +getPrice()+"\n"); } } //订单类 class Order { Record[] records = new Record[20];//动态订单数组,保存订单上每一道的记录 int count2 = 0; public Order() { } //计算订单的总价 int getTotalPrice() { int price = 0; for (int i = 0; i < count2; i++) { if (records[i].dish != null) price += records[i].getPrice(); } return price; } //添加一条菜品信息到订单中 public void addARecord(int orderNum, String dishName, Menu menu, int portion, int num) { if (menu.searchDish(dishName) != null) {//如果点的菜在菜谱中能找到,添加进订单 Record newrecord = new Record(orderNum, menu.searchDish(dishName), portion, num); newrecord.show(); records[count2] = newrecord; count2++; } else {//如果点的菜在菜谱中找不到,输出该菜品不存在 System.out.println(dishName + " does not exist"); } } public void addARecord1(int orderNum, String dishName, Menu menu, int portion, int num) { if (menu.searchDish(dishName) != null) {//如果点的菜在菜谱中能找到,添加进订单 Record newrecord = new Record(orderNum, menu.searchDish(dishName), portion, num); records[count2] = newrecord; count2++; } else {//如果点的菜在菜谱中找不到,输出该菜品不存在 System.out.println(dishName + " does not exist"); } } //根据序号删除一条记录,机理将该记录的份数 = 0。 public void delARecordByOrderNum(int orderNum) { int price = 0; for (int i = 0; i < count2; i++) { if (records[i].orderNum == orderNum) { records[i].num = 0; break; } } } //根据序号找点菜记录,找到了则返回该条记录 public Record searchRecord(int orderNum) { for (int i = 0; i < count2; i++) { if (records[i].orderNum == orderNum) { return records[i]; } } return null; } //根据序号查找一条记录,查到了返回TRUE,没查到返回FALSE public boolean findRecordByNum(int orderNum) { boolean flag = false; for (int i = 0; i < count2; i++) { if (records[i].orderNum == orderNum) { flag = true; break; } } return flag; } } class Table{ int num; //桌号 String dateString; //日期字符串 String timeString; //时间字符串 int sum_price; //总价 //Order[] orders = new Order[20]; public Table(int num,String dateString,String timeString,int sum_price){ this.num = num; this.dateString = dateString; this.timeString = timeString; this.sum_price = sum_price; } public int judge_discount(String dateString,String timeString,int sum_price){ LocalDate date = parseDate(dateString); LocalTime time = parseTime(timeString); if(isWeekend(date)){//如果是周末 if(isBHWeekend(time)) {//如果是周末营业时间 sum_price = sum_price; //System.out.println("table " + num +" 333out of opening hours"); }else{//如果是周末但非营业时间 System.out.println("table " + num +" out of opening hours"); sum_price = -1; } }else{//如果是周一到周五的工作时间内 if(isNOTime(time)){//如果是中午的营业时间 sum_price = (int)Math.round(0.6*sum_price);//六折 } else if (isEDTime(time)) { sum_price = (int)Math.round(0.8*sum_price);//八折 } else{//如果是周一至周五的非工作时间内 System.out.println("table " + num +" out of opening hours"); sum_price = -1; } } return sum_price; } // 判断是否为周末 private static boolean isWeekend(LocalDate date) { return date.getDayOfWeek().getValue() >= 6; } // 判断是否在周末营业时间范围内 private static boolean isBHWeekend(LocalTime time) { LocalTime openingTime = LocalTime.parse("09:30:00"); LocalTime closingTime = LocalTime.parse("21:30:00"); if(time.isAfter(openingTime) && time.isBefore(closingTime)){ return true; } else if (time.equals(openingTime) || time.equals(closingTime)) { return true; }else{ return false; } } // 判断是否为周一至周五晚上折扣时间 private static boolean isEDTime(LocalTime time) { LocalTime eveningStartTime = LocalTime.parse("17:00:00"); LocalTime eveningEndTime = LocalTime.parse("20:30:00"); if(time.isAfter(eveningStartTime) && time.isBefore(eveningEndTime)){ return true; } else if (time.equals(eveningStartTime) || time.equals(eveningEndTime)) { return true; } else{ return false; } } // 判断是否为周一至周五中午折扣时间 private static boolean isNOTime(LocalTime time) { LocalTime noonStartTime = LocalTime.parse("10:30:00"); LocalTime noonEndTime = LocalTime.parse("14:30:00"); if(time.isAfter(noonStartTime) && time.isBefore(noonEndTime)) { return true; } else if (time.equals(noonStartTime) || time.equals(noonEndTime)) { return true; } else { return false; } } //如果遇到代点菜的,改变当前桌位的金额 public void daidian(int nowtablenum,int fortablenum,int xuhao,String name,int portion,int num,Menu menu){ System.out.println(xuhao+" table "+nowtablenum +" pay for table "+fortablenum + " " + (int)menu.searchDish(name).getPrice(portion)*num); //price = (int)menu.searchDish(name).getPrice(portion)*num; } private static LocalDate parseDate(String dateStr) { // 定义支持的日期格式数组 String[] patterns = {"yyyy/M/d", "yyyy/M/dd", "yyyy/MM/d", "yyyy/MM/dd"}; for (String pattern : patterns) { try { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); LocalDate date = LocalDate.parse(dateStr, formatter); return date; } catch (Exception e) { // 解析失败,继续尝试下一个日期格式 } } throw new IllegalArgumentException("无效的日期格式: " + dateStr); } private static LocalTime parseTime(String timeStr) { // 定义支持的日期格式数组 String[] patterns = {"HH/mm/ss", "H/mm/ss", "HH/m/ss", "HH/mm/s","H/m/ss","H/mm/s","HH/m/s","H/m/s"}; for (String pattern : patterns) { try { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); LocalTime time = LocalTime.parse(timeStr, formatter); return time; } catch (Exception e) { // 解析失败,继续尝试下一个日期格式 } } throw new IllegalArgumentException("无效的时间格式: " + timeStr); } }
题目:
本体大部分内容与菜单计价程序-3相同,增加的部分用加粗文字进行了标注。
设计点菜计价程序,根据输入的信息,计算并输出总价格。
输入内容按先后顺序包括两部分:菜单、订单,最后以"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)//根据序号查找一条记录
}
本次课题比菜单计价系列-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折, 周末全价。
注意:不同的四舍五入顺序可能会造成误差,请按以下步骤累计一桌菜的菜价:
计算每条记录的菜价:将每份菜的单价按份额进行四舍五入运算后,乘以份数计算多份的价格,然后乘以折扣,再进行四舍五入,得到本条记录的最终支付价格。
最后将所有记录的菜价累加得到整桌菜的价格。
输入格式:
桌号标识格式: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+英文空格+桌号+“:”+英文空格+当前桌的原始总价+英文空格+当前桌的计算折扣后总价
代码:
import java.time.Duration; import java.time.LocalDate; import java.time.LocalTime; import java.time.YearMonth; import java.time.format.DateTimeParseException; import java.util.Scanner; import java.time.format.DateTimeFormatter; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); String message = null; String name = null; String date = null; String time = null; int unit_price = 0; int orderNum = 0; int portion = 0; int num = 0; int tablenum = 0; int for_tableNum = 0; int xuhao = 0; Table tablejudge = new Table(0,"sd","sd",0); LocalDate Startdate = LocalDate.parse("2022-01-01"); LocalDate Enddate = LocalDate.parse("2023-12-31"); Menu menu = new Menu(); Order[] orders = new Order[20]; for (int i = 0; i < 20; i++) { orders[i] = new Order(); } Table[] tables = new Table[20]; for (int i = 0; i < 20; i++) { tables[i] = tablejudge; } int order_idex = 0; int table_idex = 0; int medium = 0; int compare = 0;//标记桌号,进行大小比较 int spot = 0; O: while(true){ message = input.nextLine(); if(message.equals("end")) break O; //麻烦死了!! else if(message.matches("^[\\p{L}\\p{N}\\p{M}\\p{P}\\p{S}]+\\s{1}[1-9][0-9]*+$")){ //若符合添加菜单 if(spot > 0){ //此时不作任何处理 } else if(table_idex>0){//菜谱信息与订单信息混合,应忽略夹在订单信息中的菜谱信息。输出:"invalid dish" System.out.println("invalid dish"); }else { String[] parts = message.split(" "); name = parts[0]; unit_price = Integer.parseInt(parts[1]); if(unit_price <1 || unit_price > 299){ System.out.println(name + " price out of range " + unit_price); }else{ menu.addDish(name, unit_price); menu.searchDish(name).setTejia(false);} } } else if (message.matches("^[\\p{L}\\p{N}\\p{M}\\p{P}\\p{S}]+\\s{1}[1-9][0-9]*+\\s+T$")) { //如果是特色菜 if(spot > 0){ //此时不作任何处理 }else if(table_idex>0){//菜谱信息与订单信息混合,应忽略夹在订单信息中的菜谱信息。输出:"invalid dish" System.out.println("invalid dish"); }else { String[] parts = message.split(" "); name = parts[0]; unit_price = Integer.parseInt(parts[1]); if(unit_price <1 || unit_price > 299){ System.out.println(name + " price out of range " + unit_price); }else{ menu.addDish(name, unit_price); menu.searchDish(name).setTejia(true);} } } else if (message.matches("^table\\s{1}[1-9][0-9]*+\\s{1}\\d{4}/\\d{1,2}/\\d{1,2}\\s{1}\\d{1,2}/\\d{1,2}/\\d{1,2}$")) { //如果输入符合桌号订单模式 if(medium > 0){ table_idex = medium; medium = 0; } spot = 0;//正确的table出现 compare = 0;//遇到新的一桌,则桌号又从0开始计算 table_idex++; order_idex++; String[] parts = message.split(" "); tablenum = Integer.parseInt(parts[1]);//桌号 date = parts[2];//日期 time = parts[3];//时间 //判断日期是否合法 LocalDate datejudge = tablejudge.parseDate(date); LocalTime timejudge = tablejudge.parseTime(time); if(datejudge == null || timejudge == null){//若日期时间不合法 table_idex--; order_idex--; spot = 1; System.out.println(tablenum + " date error"); } else if (datejudge.isBefore(Startdate) ||datejudge.isAfter(Enddate)) { table_idex--; order_idex--; spot = 1; System.out.println("not a valid time period"); } else if (tablenum < 1 || tablenum > 55) { table_idex--; order_idex--; spot = 1; System.out.println(tablenum + " table num out of range"); } else if (!tablejudge.judge(date,time)) { table_idex--; order_idex--; spot = 1; //如果不在营业时间内 System.out.println("table " + tablenum + " out of opening hours"); } else if(table_idex>1 && tablejudge.searchTable(tablenum,table_idex,tables)){ //如果在营业时间内且桌号重复出现,且不是第一桌 //不在同一时段内 if(!tablejudge.shiDuan(tablejudge.FindTable(tablenum,table_idex,tables),datejudge,timejudge)){ tables[table_idex] = new Table(tablenum, date, time, 0);//创建当前这一桌 System.out.println("table " + tables[table_idex].num + ": "); }else{ //在同一时段内 //找到先前序号那桌对应的table_idex,并将真实的table_idex先赋给medium table_idex--; order_idex--; medium = table_idex; table_idex = tablejudge.searchTable1(tablenum,medium,tables); System.out.println("table " + tables[table_idex].num + ": "); } }else{ tables[table_idex] = new Table(tablenum, date, time, 0);//创建当前这一桌 //tables[table_idex].sum_price = orders[order_idex].getTotalPrice(); System.out.println("table " + tables[table_idex].num + ": "); } //创建当前这一桌的订单,注意,其中order[0]为空,从[1]开始装订单,table同理 //如果输入符合以“table”开头,对应记录的格式或者数据不符合桌号的要求,那一桌下面定义的所有信息无论正确或错误均忽略,不做处理。 } else if (message.startsWith("table")) { System.out.println("wrong format"); spot = 1;//将spot标记,执行其他语句时都不处理,直到正确的table出现 } else if (message.matches("^\\d+\\s{1}\\d+\\s{1}[\\p{L}\\p{N}\\p{M}\\p{P}\\p{S}]+\\s{1}\\d+\\s{1}[1-9][0-9]*+$")) { //如果输出符合代点菜信息 String[] parts = message.split(" "); for_tableNum = Integer.parseInt(parts[0]);//桌号 xuhao = Integer.parseInt(parts[1]);//序号 name = parts[2];//菜名 portion = Integer.parseInt(parts[3]);//份额 num = Integer.parseInt(parts[4]);//份数 if(spot > 0){ //此时不作任何处理 }else if (table_idex == 0) { System.out.println("wrong format"); }else if(tables[table_idex].num == for_tableNum){ System.out.println("Table number :" + for_tableNum + " does not exist"); } else if(!tablejudge.searchTable(for_tableNum,table_idex,tables)){ System.out.println("Table number :" + for_tableNum + " does not exist"); } else if (menu.searchDish(name) == null) { //如果菜品不存在 System.out.println(name + " does not exist"); } else if (portion > 9) { System.out.println("wrong format"); } else if (portion < 10 && portion > 3) { System.out.println(xuhao + " portion out of range " + portion ); } else if (num > 15) { System.out.println(orderNum + " num out of range " + num); } else { //代点函数,输出代点信息,并更改当前桌的总金额 tables[table_idex].daidian(tables[table_idex].num, for_tableNum, xuhao, name, portion, num, menu); //添加一条订单 orders[order_idex].addARecord1(xuhao, name, menu, portion, num);//添加进订单记录 //tables[tablejudge.searchTable1(for_tableNum,table_idex,tables)].setSum(num);//计算当前桌的菜品份数 } }//若符合点菜信息 else if (message.matches("^[1-9][0-9]*+\\s+[\\p{L}\\p{N}\\p{M}\\p{P}\\p{S}]+\\s+\\d+\\s+[1-9][0-9]*+$")) { String[] parts = message.split(" "); orderNum = Integer.parseInt(parts[0]); name = parts[1]; portion = Integer.parseInt(parts[2]); num = Integer.parseInt(parts[3]); if(spot > 0){ //此时不作任何处理 }else if (table_idex == 0) { System.out.println("wrong format"); } else if(menu.searchDish(name) == null){ //如果菜品不存在 System.out.println(name + " does not exist"); } else if (portion > 9) { System.out.println("wrong format"); }else if (portion < 10 && portion > 3) { System.out.println(orderNum + " portion out of range " + portion); }else if (num > 15 ) { //如果份数大于15 System.out.println(orderNum + " num out of range " + num); }else if (orderNum <= compare) { System.out.println("record serial number sequence error"); } else { compare = orderNum; // tables[table_idex].setSum(num);//计算当前桌的菜品份数 orders[order_idex].addARecord(orderNum, name, menu, portion, num);//添加进订单记录 } }//若符合删除信息 else if (message.matches("\\d+\\s+delete+$")){ String[] parts = message.split(" "); orderNum = Integer.parseInt(parts[0]); if(spot > 0){ //此时不作任何处理 } else if(orders[order_idex].findRecordByNum(orderNum)&&orders[order_idex].searchRecord(orderNum).num!=0){//如果在订单里找到了该序号且这个是第一次对这条订单记录进行删除 orders[order_idex].delARecordByOrderNum(orderNum);//机理是使该序号记录的最后份数置0。 } else if (orders[order_idex].findRecordByNum(orderNum)&&orders[order_idex].searchRecord(orderNum).num==0) { //如果在订单里找到了该序号且这条订单记录的份数已经置0 System.out.println("deduplication " + orderNum); } else{//没找到该序号 System.out.println("delete error;"); } }else{ if(spot > 0){ //此时不作任何处理 }else System.out.println("wrong format"); } } //算每一桌的钱咯(*^▽^*) for (int k = 1; k <=table_idex; k++) { int price0 =0; int price1 = 0; int price2 = 0; //计算菜品的原价 price0 = orders[k].getTotalPrice(tables[k].dateString); //计算不是特色菜的总金额 price2 = orders[k].getTotalPrice2(tables[k].dateString); //再计算特色菜的总金额 price1 = orders[k].getTotalPrice1(tables[k].dateString); tables[k].sum_price = (int)Math.round(tables[k].judge_discount(tables[k].dateString,tables[k].timeString,price2)+price1); if(tables[k].sum_price >= 0) { System.out.println("table " + tables[k].num + ": " + price0 + " " +tables[k].sum_price); } } } } //菜品类 class Dish{ String name;//菜品名称 int unit_price; //单价 Boolean tejia;//特价菜标志 public Dish(String name,int unit_price){ this.name = name; this.unit_price = unit_price; } public String getName() { return name; } public void setTejia(boolean i){ this.tejia = i; } public Boolean getTejia(){ return tejia; } public int getUnit_price() { return unit_price; } //计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) public int getPrice(int portion){ double price = 0; if(portion == 1) { price = Math.round(unit_price); } else if (portion == 2) { price = Math.round(unit_price*1.5); } else if (portion == 3) { price = Math.round(unit_price*2); }return (int)price; } } //菜单类 class Menu{ Dish[] dishes = new Dish[20] ;//动态菜品数组,保存所有菜品信息 int count1 = 0;//计算有多少道菜品 public Menu() { } //根据菜名在菜谱中查找菜品信息,返回Dish对象。 public Dish searchDish(String dishName){ for (int i = 0; i < count1; i++) { if(dishName.equals(dishes[i].name)){ return dishes[i]; } } return null; } //添加一道菜品信息 public void addDish(String dishName,int unit_price) { if (searchDish(dishName) == null) {//如果这道菜还未添加过,则添加 Dish newDish = new Dish(dishName, unit_price); dishes[count1] = newDish; count1++;//菜品数量加一 }else{ //若添加过,则更新这道菜的价格 searchDish(dishName).unit_price = unit_price; } } } //点菜记录类 class Record { int orderNum;//序号\ Dish dish;//菜品\ int portion;//份额(1/2/3代表小/中/大份) //计价,计算本条记录的价格\ int num;//份数 public Record(int orderNum,Dish dish,int portion,int num){ this.orderNum = orderNum; this.dish = dish; this.portion = portion; this.num = num; } public int getOrderNum() { return orderNum; } public int getPrice(){ int price = 0; price = Math.round(dish.getPrice(this.portion)*this.num); return price; } public void show(){//显示当前订单 System.out.print(orderNum + " " + dish.name + " " +getPrice()+"\n"); } } //订单类 class Order { Record[] records = new Record[20];//动态订单数组,保存订单上每一道的记录 int count2 = 0; public Order() { } //计算订单的总价 int getTotalPrice(String datestring) { int price = 0; Table tablejudge = new Table(0,"sd","sd",0); for (int i = 0; i < count2; i++) { if (records[i].dish != null) { //菜品存在 price += records[i].getPrice(); } } return price; } int getTotalPrice1(String datestring) { int price = 0; double s = 0; Table tablejudge = new Table(0,"sd","sd",0); for (int i = 0; i < count2; i++) { if (records[i].dish != null && records[i].dish.getTejia().equals(true)&&!tablejudge.isWeekend(tablejudge.parseDate(datestring))) { //菜品存在的同时是特色菜,且日期为工作日 s += 0.7*records[i].getPrice();//七折 }else if(records[i].dish != null && records[i].dish.getTejia().equals(true)&&tablejudge.isWeekend(tablejudge.parseDate(datestring))){ //菜品存在的同时是特色菜,且日期为周末 s += records[i].getPrice();//不打折 } } price = (int)Math.round(s); return price; } int getTotalPrice2(String datestring) { int price = 0; Table tablejudge = new Table(0,"sd","sd",0); for (int i = 0; i < count2; i++) { if (records[i].dish != null && records[i].dish.getTejia().equals(false)) { //菜品存在的同时不是特色菜 price += records[i].getPrice(); } } return price; } //添加一条菜品信息到订单中 public void addARecord(int orderNum, String dishName, Menu menu, int portion, int num) { if (menu.searchDish(dishName) != null) {//如果点的菜在菜谱中能找到,添加进订单 Record newrecord = new Record(orderNum, menu.searchDish(dishName), portion, num); newrecord.show(); records[count2] = newrecord; count2++; } else {//如果点的菜在菜谱中找不到,输出该菜品不存在 System.out.println(dishName + " does not exist"); } } public void addARecord1(int orderNum, String dishName, Menu menu, int portion, int num) { if (menu.searchDish(dishName) != null) {//如果点的菜在菜谱中能找到,添加进订单 Record newrecord = new Record(orderNum, menu.searchDish(dishName), portion, num); records[count2] = newrecord; count2++; } else {//如果点的菜在菜谱中找不到,输出该菜品不存在 System.out.println(dishName + " does not exist"); } } //根据序号删除一条记录,机理将该记录的份数 = 0。 public void delARecordByOrderNum(int orderNum) { int price = 0; for (int i = 0; i < count2; i++) { if (records[i].orderNum == orderNum) { records[i].num = 0; break; } } } //根据序号找点菜记录,找到了则返回该条记录 public Record searchRecord(int orderNum) { for (int i = 0; i < count2; i++) { if (records[i].orderNum == orderNum) { return records[i]; } } return null; } //根据序号查找一条记录,查到了返回TRUE,没查到返回FALSE public boolean findRecordByNum(int orderNum) { boolean flag = false; for (int i = 0; i < count2; i++) { if (records[i].orderNum == orderNum) { flag = true; break; } } return flag; } } class Table{ int num; //桌号 String dateString; //日期字符串 String timeString; //时间字符串 int sum_price; //总价 int sum; //份数 //Order[] orders = new Order[20]; public Table(int num,String dateString,String timeString,int sum_price){ this.num = num; this.dateString = dateString; this.timeString = timeString; this.sum_price = sum_price; } public int judge_discount(String dateString,String timeString,int sum_price){ LocalDate date = parseDate(dateString); LocalTime time = parseTime(timeString); if(isWeekend(date)){//如果是周末 if(isBHWeekend(time)) {//如果是周末营业时间 sum_price = sum_price; //System.out.println("table " + num +" 333out of opening hours"); }else{//如果是周末但非营业时间 // System.out.println("table " + num +" out of opening hours"); sum_price = -1; } }else{//如果是周一到周五的工作时间内 if(isNOTime(time)){//如果是中午的营业时间 sum_price = (int)Math.round(0.6*sum_price);//六折 } else if (isEDTime(time)) { sum_price = (int)Math.round(0.8*sum_price);//八折 } else{//如果是周一至周五的非工作时间内 // System.out.println("table " + num +" out of opening hours"); sum_price = -1; } } return sum_price; } //判断是否在营业时间 public boolean judge(String dateString,String timeString){ LocalDate date = parseDate(dateString); LocalTime time = parseTime(timeString); if(isWeekend(date)){//如果是周末 if(isBHWeekend(time)) {//如果是周末营业时间 return true; }else{//如果是周末但非营业时间 return false; } }else{//如果是周一到周五的工作时间内 if(isNOTime(time)){//如果是中午的营业时间 return true; } else if (isEDTime(time)) { return true; } else{//如果是周一至周五的非工作时间内 return false; } } } // 判断是否为周末 public boolean isWeekend(LocalDate date) { return date.getDayOfWeek().getValue() >= 6; } // 判断是否在周末营业时间范围内 public boolean isBHWeekend(LocalTime time) { LocalTime openingTime = LocalTime.parse("09:30:00"); LocalTime closingTime = LocalTime.parse("21:30:00"); if(time.isAfter(openingTime) && time.isBefore(closingTime)){ return true; } else if (time.equals(openingTime) || time.equals(closingTime)) { return true; }else{ return false; } } // 判断是否为周一至周五晚上折扣时间 public boolean isEDTime(LocalTime time) { LocalTime eveningStartTime = LocalTime.parse("17:00:00"); LocalTime eveningEndTime = LocalTime.parse("20:30:00"); if(time.isAfter(eveningStartTime) && time.isBefore(eveningEndTime)){ return true; } else if (time.equals(eveningStartTime) || time.equals(eveningEndTime)) { return true; } else{ return false; } } // 判断是否为周一至周五中午折扣时间 public static boolean isNOTime(LocalTime time) { LocalTime noonStartTime = LocalTime.parse("10:30:00"); LocalTime noonEndTime = LocalTime.parse("14:30:00"); if(time.isAfter(noonStartTime) && time.isBefore(noonEndTime)) { return true; } else if (time.equals(noonStartTime) || time.equals(noonEndTime)) { return true; } else { return false; } } //如果遇到代点菜的,改变当前桌位的金额 public void daidian(int nowtablenum,int fortablenum,int xuhao,String name,int portion,int num,Menu menu){ System.out.println(xuhao+" table "+nowtablenum +" pay for table "+fortablenum + " " + (int)menu.searchDish(name).getPrice(portion)*num); //price = (int)menu.searchDish(name).getPrice(portion)*num; } // 判断一个日期是否合法 public boolean isValidDate(LocalDate date) { try { // 尝试将日期格式化为年月日 String dateStr = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); // 再将格式化后的日期解析为 LocalDate 对象,如果日期与原日期相等,说明该日期合法 return date.equals(LocalDate.parse(dateStr)); } catch (Exception e) { return false; } } public LocalDate parseDate(String dateStr) { // 定义支持的日期格式数组 String[] patterns = {"yyyy/M/d", "yyyy/M/dd", "yyyy/MM/d", "yyyy/MM/dd"}; LocalDate date = null; for (String pattern : patterns) { try { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); date = LocalDate.parse(dateStr, formatter); // 检查年月日的合法性 YearMonth yearMonth = YearMonth.of(date.getYear(), date.getMonth()); boolean isValidDate = yearMonth.isValidDay(date.getDayOfMonth()); if (!isValidDate || !dateStr.equals(date.format(formatter))) { return null; } return date; } catch (DateTimeParseException e) { // 解析失败,继续尝试下一个日期格式 e.printStackTrace(); } } return date; } public LocalTime parseTime(String timeStr) { // 定义支持的日期格式数组 String[] patterns = {"HH/mm/ss", "H/mm/ss", "HH/m/ss", "HH/mm/s","H/m/ss","H/mm/s","HH/m/s","H/m/s"}; LocalTime time = null; for (String pattern : patterns) { try { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); time = LocalTime.parse(timeStr, formatter); return time; } catch (DateTimeParseException e) { // 解析失败,继续尝试下一个日期格式 } } return time; } //根据桌号找桌号信息,找到了则返回true public boolean searchTable(int orderNum,int table_idex,Table[] table) { for (int i = 1; i <= table_idex; i++) { if ( table[i].num == orderNum) { return true; } } return false; } //根据桌号找桌号信息,找到了则返回该桌对应的table_idex public int searchTable1(int orderNum,int table_idex,Table[] table) { for (int i = 1; i <= table_idex; i++) { if ( table[i].num == orderNum) { return i; } } return -1; } //根据桌号找桌号信息,找到了则返回该桌 public Table FindTable(int orderNum,int table_idex,Table[] table) { for (int i = 1; i <= table_idex; i++) { if ( table[i].num == orderNum) { return table[i]; } } return null; } //判断重复序号的两桌是否在同一时间段内 public boolean shiDuan(Table table,LocalDate date,LocalTime time){ LocalDate date0 = parseDate(table.dateString); LocalTime time0 = parseTime(table.timeString); //如果是周末 if(isWeekend(date0)){ //如果两个日期是同一天 if(date0.isEqual(date)){ //且相差一小时以内 if(isWithinOneHour(time,time0)){ return true; }else { return false; } } }else{//如果是工作日 //如果两个日期是同一天 if(date0.isEqual(date)){ //如果都是中午的折扣时间 if(isNOTime(time)&&isNOTime(time0)){ return true; } else if (isEDTime(time)&&isEDTime(time0)) { //如果都是晚上的折扣时间 return true; }else{//同一天但不是同一时段 return false; } } } //不在同一天返回false return false; } public boolean isWithinOneHour(LocalTime time1, LocalTime time2) { Duration duration = Duration.between(time1, time2); long diffInMinutes = Math.abs(duration.toMinutes()); return diffInMinutes <= 60; } public int getSum() { return sum; } public void setSum(int m) { this.sum += m; } }
题目:
本题在菜单计价程序-3的基础上增加了部分内容,增加的内容用加粗字体标识。
注意不是菜单计价程序-4,本题和菜单计价程序-4同属菜单计价程序-3的两个不同迭代分支。
设计点菜计价程序,根据输入的信息,计算并输出总价格。
输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。
菜单由一条或多条菜品记录组成,每条记录一行
每条菜品记录包含:菜名、基础价格 三个信息。
订单分:桌号标识、点菜记录和删除信息、代点菜信息。每一类信息都可包含一条或多条记录,每条记录一行或多行。
桌号标识独占一行,包含两个信息:桌号、时间。
桌号以下的所有记录都是本桌的记录,直至下一个桌号标识。
点菜记录包含:序号、菜名、份额、份数。份额可选项包括:1、2、3,分别代表小、中、大份。
不同份额菜价的计算方法:小份菜的价格=菜品的基础价格。中份菜的价格=菜品的基础价格1.5。小份菜的价格=菜品的基础价格2。如果计算出现小数,按四舍五入的规则进行处理。
删除记录格式:序号 delete
标识删除对应序号的那条点菜记录。
如果序号不对,输出"delete error"
代点菜信息包含:桌号 序号 菜品名称 口味度 份额 份数
代点菜是当前桌为另外一桌点菜,信息中的桌号是另一桌的桌号,带点菜的价格计算在当前这一桌。
程序最后按输入的先后顺序依次输出每一桌的总价(注意:由于有代点菜的功能,总价不一定等于当前桌上的菜的价格之和)。
每桌的总价等于那一桌所有菜的价格之和乘以折扣。如存在小数,按四舍五入规则计算,保留整数。
折扣的计算方法(注:以下时间段均按闭区间计算):
周一至周五营业时间与折扣:晚上(17:00-20:30)8折,周一至周五中午(10:30--14:30)6折,其余时间不营业。
周末全价,营业时间:9:30-21:3
如下单时间不在营业范围内,输出"table " + t.tableNum + " out of opening hours"
参考以下类的模板进行设计:菜品类:对应菜谱上一道菜的信息
Dish {
String name;//菜品名称
int unit_price; //单价
int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) }
菜谱类:对应菜谱,包含饭店提供的所有菜的信息。
Menu {
Dish[] dishs ;//菜品数组,保存所有菜品信息
Dis 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+英文空格+桌号+“:”+英文空格+当前桌的总价
以上为菜单计价系列-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金额都要累加。
输出用户支付金额格式:
用户姓名+英文空格+手机号+英文空格+支付金额
注意:不同的四舍五入顺序可能会造成误差,请按以下步骤累计一桌菜的菜价:
计算每条记录的菜价:将每份菜的单价按份额进行四舍五入运算后,乘以份数计算多份的价格,然后乘以折扣,再进行四舍五入,得到本条记录的最终支付价格。
将所有记录的菜价累加得到整桌菜的价格。
输入格式:
桌号标识格式: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+英文空格+桌号+“:”+英文空格+当前桌的计算折扣后总价+英文空格+辣度平均值+英文空格+酸度平均值+英文空格+甜度平均值+英文空格
最后按拼音顺序输出每位客户(不考虑客户同名或拼音相同的情况)的支付金额,格式: 用户姓名+英文空格+手机号+英文空格+支付总金额,按输入顺序排列。
代码:
import java.time.Duration; import java.time.LocalDate; import java.time.LocalTime; import java.time.YearMonth; import java.time.format.DateTimeParseException; import java.util.*; import java.time.format.DateTimeFormatter; import java.util.Comparator; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); String message = null; String name = null; String date = null; String time = null; String dishType = null; String people = null; int unit_price = 0; int orderNum = 0; int portion = 0; int num = 0; int tablenum = 0; int for_tableNum = 0; int xuhao = 0; Table tablejudge = new Table(0,"sd","sd",0); LocalDate Startdate = LocalDate.parse("2022-01-01"); LocalDate Enddate = LocalDate.parse("2023-12-31"); Menu menu = new Menu(); Order[] orders = new Order[20]; for (int i = 0; i < 20; i++) { orders[i] = new Order(); } Table[] tables = new Table[20]; for (int i = 0; i < 20; i++) { tables[i] = tablejudge; } int order_idex = 0; int table_idex = 0; int medium = 0; int compare = 0;//标记桌号,进行大小比较 int spot = 0; int kouweidu = 0; int flag3 = 0; String telephone = null; O: while(true){ message = input.nextLine(); if(message.equals("end")) break O; //麻烦死了!! else if(message.matches("^[\\p{L}\\p{N}\\p{M}\\p{P}\\p{S}]+\\s{1}[1-9][0-9]*+$")){ //若符合添加菜单 if(spot > 0){ //此时不作任何处理 } else if(table_idex>0){//菜谱信息与订单信息混合,应忽略夹在订单信息中的菜谱信息。输出:"invalid dish" System.out.println("invalid dish"); }else { String[] parts = message.split(" "); name = parts[0]; unit_price = Integer.parseInt(parts[1]); if(unit_price <1 || unit_price > 299){ System.out.println(name + " price out of range " + unit_price); }else{ menu.addDish(name, unit_price); menu.searchDish(name).setTejia(false); menu.searchDish(name).setDishType(null);} } } else if (message.matches("^[\\p{L}\\p{N}\\p{M}\\p{P}\\p{S}]+\\s+[\\p{L}\\p{N}\\p{M}\\p{P}\\p{S}]+\\s{1}[1-9][0-9]*+\\s+T$")) { //如果是特色菜 if(spot > 0){ //此时不作任何处理 }else if(table_idex>0){//菜谱信息与订单信息混合,应忽略夹在订单信息中的菜谱信息。输出:"invalid dish" System.out.println("invalid dish"); }else { String[] parts = message.split(" "); name = parts[0]; dishType = parts[1]; unit_price = Integer.parseInt(parts[2]); if(unit_price <1 || unit_price > 299){ System.out.println(name + " price out of range " + unit_price); }else{ menu.addDish(name, unit_price); menu.searchDish(name).setDishType(dishType); menu.searchDish(name).setTejia(true);} } } else if (message.matches("^table\\s[1-9][0-9]*+\\s{1}:+\\s{1}\\w{1,10}+\\s{1}\\w{11}+\\s\\d{4}/\\d{1,2}/\\d{1,2}\\s\\d{1,2}/\\d{1,2}/\\d{1,2}$")) { //如果输入符合桌号订单模式 if(medium > 0){ table_idex = medium; medium = 0; } spot = 0;//正确的table出现 compare = 0;//遇到新的一桌,则桌号又从0开始计算 table_idex++; order_idex++; String[] parts = message.split(" "); tablenum = Integer.parseInt(parts[1]);//桌号 people = parts[3]; telephone = parts[4]; if(!(telephone.startsWith("180")||telephone.startsWith("181")||telephone.startsWith("189")||telephone.startsWith("133")||telephone.startsWith("135")||telephone.startsWith("136"))){ System.out.println("wrong format"); }else{ date = parts[5];//日期 time = parts[6];//时间 //判断日期是否合法 LocalDate datejudge = tablejudge.parseDate(date); LocalTime timejudge = tablejudge.parseTime(time); if(datejudge == null || timejudge == null){//若日期时间不合法 table_idex--; order_idex--; spot = 1; System.out.println(tablenum + " date error"); } else if (datejudge.isBefore(Startdate) ||datejudge.isAfter(Enddate)) { table_idex--; order_idex--; spot = 1; System.out.println("not a valid time period"); } else if (tablenum < 1 || tablenum > 55) { table_idex--; order_idex--; spot = 1; System.out.println(tablenum + " table num out of range"); } else if (!tablejudge.judge(date,time)) { table_idex--; order_idex--; spot = 1; //如果不在营业时间内 System.out.println("table " + tablenum + " out of opening hours"); }else{ tables[table_idex] = new Table(tablenum, date, time, 0);//创建当前这一桌 //tables[table_idex].sum_price = orders[order_idex].getTotalPrice(); System.out.println("table " + tables[table_idex].num + ": "); tables[table_idex].setTelephone(telephone); tables[table_idex].setPeople(people); } //创建当前这一桌的订单,注意,其中order[0]为空,从[1]开始装订单,table同理 //如果输入符合以“table”开头,对应记录的格式或者数据不符合桌号的要求,那一桌下面定义的所有信息无论正确或错误均忽略,不做处理。 }} else if (message.startsWith("table")) { System.out.println("wrong format"); spot = 1;//将spot标记,执行其他语句时都不处理,直到正确的table出现 } else if (message.matches("^\\d+\\s{1}\\d+\\s{1}[\\p{L}\\p{N}\\p{M}\\p{P}\\p{S}]+\\s{1}\\d+\\s{1}[1-9][0-9]*+$")) { //如果输出符合代点菜信息 String[] parts = message.split(" "); for_tableNum = Integer.parseInt(parts[0]);//桌号 xuhao = Integer.parseInt(parts[1]);//序号 name = parts[2];//菜名 portion = Integer.parseInt(parts[3]);//份额 num = Integer.parseInt(parts[4]);//份数 if(spot > 0){ //此时不作任何处理 }else if (table_idex == 0) { System.out.println("wrong format"); } else if(!tablejudge.searchTable(for_tableNum,table_idex,tables)){ System.out.println("Table number :" + for_tableNum + " does not exist"); } else if (menu.searchDish(name) == null) { //如果菜品不存在 System.out.println(name + " does not exist"); } else if (portion > 9) { System.out.println("wrong format"); } else if (portion < 10 && portion > 3) { System.out.println(xuhao + " portion out of range " + portion ); } else if (num > 15) { System.out.println(orderNum + " num out of range " + num); } else if(tables[table_idex].num == for_tableNum){ System.out.println("wrong format"); }else { //代点函数,输出代点信息,并更改当前桌的总金额 tables[table_idex].daidian(tables[table_idex].num, for_tableNum, xuhao, name, portion, num, menu); //添加一条订单 orders[order_idex].addARecord1(xuhao, name, menu, portion, num);//添加进订单记录 //tables[tablejudge.searchTable1(for_tableNum,table_idex,tables)].setSum(num);//计算当前桌的菜品份数 } }else if (message.matches("^\\d+\\s{1}\\d+\\s{1}[\\p{L}\\p{N}\\p{M}\\p{P}\\p{S}]+\\s{1}\\d+\\s{1}\\d+\\s{1}[1-9][0-9]*+$")) { //如果输出符合代点菜为特色菜的信息 String[] parts = message.split(" "); for_tableNum = Integer.parseInt(parts[0]);//桌号 xuhao = Integer.parseInt(parts[1]);//序号 name = parts[2];//菜名 kouweidu = Integer.parseInt(parts[3]); portion = Integer.parseInt(parts[4]);//份额 num = Integer.parseInt(parts[5]);//份数 if(spot > 0){ //此时不作任何处理 }else if (table_idex == 0) { System.out.println("wrong format"); } else if(!tablejudge.searchTable(for_tableNum,table_idex,tables)){ System.out.println("Table number :" + for_tableNum + " does not exist"); } else if (menu.searchDish(name) == null) { //如果菜品不存在 System.out.println(name + " does not exist"); } else if (portion > 9) { System.out.println("wrong format"); } else if (portion < 10 && portion > 3) { System.out.println(xuhao + " portion out of range " + portion ); } else if (num > 15) { System.out.println(orderNum + " num out of range " + num); }else if(tables[table_idex].num == for_tableNum){ System.out.println("wrong format"); }else { if(menu.searchDish(name).getDishType().equals("川菜")){ //如果是川菜,给该桌的辣味度加上口味度的值 //并且川菜数量更新 if(kouweidu < 0||kouweidu >5){ System.out.println("spicy num out of range :" + kouweidu); flag3 = 1; }else{ tables[tablejudge.searchTable1(for_tableNum,table_idex,tables)].setSpicy(kouweidu*num); tables[tablejudge.searchTable1(for_tableNum,table_idex,tables)].setSpicy_num(num);} } else if (menu.searchDish(name).getDishType().equals("晋菜")) { if(kouweidu < 0||kouweidu >4){ System.out.println("acidity num out of range :" + kouweidu); flag3 = 1; }else{ tables[tablejudge.searchTable1(for_tableNum,table_idex,tables)].setAcidity(kouweidu*num); tables[tablejudge.searchTable1(for_tableNum,table_idex,tables)].setAcidity_num(num);} } else if (menu.searchDish(name).getDishType().equals("浙菜")) { if(kouweidu < 0||kouweidu >3){ System.out.println("sweetness num out of range :" + kouweidu); flag3 = 1; }else{ tables[tablejudge.searchTable1(for_tableNum,table_idex,tables)].setSweetness(kouweidu*num); tables[tablejudge.searchTable1(for_tableNum,table_idex,tables)].setSweetness_num(num);} } //代点函数,输出代点信息,并更改当前桌的总金额 if(flag3 == 0){ tables[table_idex].daidian(tables[table_idex].num, for_tableNum, xuhao, name, portion, num, menu); //添加一条订单 orders[order_idex].addARecord1(xuhao, name, menu, portion, num);//添加进订单记录 if(menu.searchDish(name).getDishType().equals("川菜")) { orders[order_idex].searchRecord(xuhao).setDishType("川菜"); orders[order_idex].searchRecord(xuhao).setKouweidu(kouweidu); } if(menu.searchDish(name).getDishType().equals("晋菜")) { orders[order_idex].searchRecord(xuhao).setDishType("晋菜"); orders[order_idex].searchRecord(xuhao).setKouweidu(kouweidu); } if(menu.searchDish(name).getDishType().equals("浙菜")){ orders[order_idex].searchRecord(xuhao).setDishType("浙菜"); orders[order_idex].searchRecord(xuhao).setKouweidu(kouweidu); } } //tables[tablejudge.searchTable1(for_tableNum,table_idex,tables)].setSum(num);//计算当前桌的菜品份数 flag3 = 0; } }//若符合特色菜点菜信息 else if (message.matches("^[1-9][0-9]*+\\s{1}[\\p{L}\\p{N}\\p{M}\\p{P}\\p{S}]+\\s{1}\\d+\\s{1}\\d+\\s{1}[1-9][0-9]*+$")) { String[] parts = message.split(" "); orderNum = Integer.parseInt(parts[0]); name = parts[1]; kouweidu = Integer.parseInt(parts[2]); portion = Integer.parseInt(parts[3]); num = Integer.parseInt(parts[4]); if(spot > 0){ //此时不作任何处理 }else if (table_idex == 0) { System.out.println("wrong format"); } else if(menu.searchDish(name) == null){ //如果菜品不存在 System.out.println(name + " does not exist"); } else if (portion > 9) { System.out.println("wrong format"); }else if (portion < 10 && portion > 3) { System.out.println(orderNum + " portion out of range " + portion); }else if (num > 15 ) { //如果份数大于15 System.out.println(orderNum + " num out of range " + num); } else { if(menu.searchDish(name).getDishType().equals("川菜")){ //如果是川菜,给该桌的辣味度加上口味度的值 //并且川菜数量加一 if(kouweidu < 0||kouweidu >5){ System.out.println("spicy num out of range :" + kouweidu); flag3 = 1; }else{ tables[table_idex].setSpicy(kouweidu*num); tables[table_idex].setSpicy_num(num);} } else if (menu.searchDish(name).getDishType().equals("晋菜")) { if(kouweidu < 0||kouweidu >4){ System.out.println("acidity num out of range :" + kouweidu); flag3 = 1; }else{ tables[table_idex].setAcidity(kouweidu*num); tables[table_idex].setAcidity_num(num);} } else if (menu.searchDish(name).getDishType().equals("浙菜")) { if(kouweidu < 0||kouweidu >3){ System.out.println("sweetness num out of range :" + kouweidu); flag3 = 1; }else{ tables[table_idex].setSweetness(kouweidu*num); tables[table_idex].setSweetness_num(num);} } // tables[table_idex].setSum(num);//计算当前桌的菜品份数 if(flag3 == 0) { orders[order_idex].addARecord(orderNum, name, menu, portion, num);//添加进订单记录 if(menu.searchDish(name).getDishType().equals("川菜")) { orders[order_idex].searchRecord(orderNum).setDishType("川菜"); orders[order_idex].searchRecord(orderNum).setKouweidu(kouweidu); } if(menu.searchDish(name).getDishType().equals("晋菜")) { orders[order_idex].searchRecord(orderNum).setDishType("晋菜"); orders[order_idex].searchRecord(orderNum).setKouweidu(kouweidu); } if(menu.searchDish(name).getDishType().equals("浙菜")){ orders[order_idex].searchRecord(orderNum).setDishType("浙菜"); orders[order_idex].searchRecord(orderNum).setKouweidu(kouweidu); } }flag3 = 0; } }//若符合点菜信息 else if (message.matches("^[1-9][0-9]*+\\s{1}[\\p{L}\\p{N}\\p{M}\\p{P}\\p{S}]+\\s{1}\\d+\\s{1}[1-9][0-9]*+$")) { String[] parts = message.split(" "); orderNum = Integer.parseInt(parts[0]); name = parts[1]; portion = Integer.parseInt(parts[2]); num = Integer.parseInt(parts[3]); if(spot > 0){ //此时不作任何处理 }else if (table_idex == 0) { System.out.println("wrong format"); } else if(menu.searchDish(name) == null){ //如果菜品不存在 System.out.println(name + " does not exist"); } else if (portion > 9) { System.out.println("wrong format"); }else if (portion < 10 && portion > 3) { System.out.println(orderNum + " portion out of range " + portion); }else if (num > 15 ) { //如果份数大于15 System.out.println(orderNum + " num out of range " + num); }else { // tables[table_idex].setSum(num);//计算当前桌的菜品份数 orders[order_idex].addARecord(orderNum, name, menu, portion, num);//添加进订单记录 } }//若符合删除信息 else if (message.matches("\\d+\\s+delete+$")){ String[] parts = message.split(" "); orderNum = Integer.parseInt(parts[0]); if(spot > 0){ //此时不作任何处理 } else if(orders[order_idex].findRecordByNum(orderNum)&&orders[order_idex].searchRecord(orderNum).num!=0){//如果在订单里找到了该序号且这个是第一次对这条订单记录进行删除 if(orders[order_idex].searchRecord(orderNum).dishType.equals("川菜")){ tables[table_idex].setSpicy(-orders[order_idex].searchRecord(orderNum).getKouweidu()); tables[table_idex].setSpicy_num(-orders[order_idex].searchRecord(orderNum).num); } if(orders[order_idex].searchRecord(orderNum).dishType.equals("晋菜")){ tables[table_idex].setAcidity(-orders[order_idex].searchRecord(orderNum).getKouweidu()); tables[table_idex].setAcidity_num(-orders[order_idex].searchRecord(orderNum).num); } if(orders[order_idex].searchRecord(orderNum).dishType.equals("浙菜")){ tables[table_idex].setSweetness(-(orders[order_idex].searchRecord(orderNum).getKouweidu())); tables[table_idex].setSweetness_num(-orders[order_idex].searchRecord(orderNum).num); } orders[order_idex].delARecordByOrderNum(orderNum);//机理是使该序号记录的最后份数置0。 } else if (orders[order_idex].findRecordByNum(orderNum)&&orders[order_idex].searchRecord(orderNum).num==0) { //如果在订单里找到了该序号且这条订单记录的份数已经置0 System.out.println("deduplication " + orderNum); } else{//没找到该序号 System.out.println("delete error;"); } }else{ if(spot > 0){ //此时不作任何处理 }else System.out.println("wrong format"); } } List<Table> tabless = new ArrayList<>(); //算每一桌的钱咯(*^▽^*) for (int k = 1; k <=table_idex; k++) { int price0 =0; int price1 = 0; int price2 = 0; int average = 0; double ss = 0; //计算菜品的原价 price0 = orders[k].getTotalPrice(tables[k].dateString); //计算不是特色菜的总金额 price2 = orders[k].getTotalPrice2(tables[k].dateString); //再计算特色菜的总金额 price1 = orders[k].getTotalPrice1(tables[k].dateString); tables[k].sum_price = (int)Math.round(tables[k].judge_discount(tables[k].dateString,tables[k].timeString,price2)+price1); if(tables[k].sum_price >= 0) { tabless.add(tables[k]); if(tables[table_idex].getSweetness_num()<1 && tables[table_idex].getSpicy_num() < 1 && tables[table_idex].getAcidity_num() < 1) System.out.print("table " + tables[k].num + ": " + price0 + " " +tables[k].sum_price+" "); else System.out.print("table " + tables[k].num + ": " + price0 + " " +tables[k].sum_price); tables[k].setTotalPrice(tables[k].sum_price); if(tables[k].getSpicy_num() > 0){ ss = (double)tables[k].getSpicy()/tables[k].getSpicy_num(); average = (int) Math.round(ss); switch(average){ case 0: System.out.print(" 川菜 " + tables[k].getSpicy_num() + " 不辣"); break; case 1: System.out.print(" 川菜 " + tables[k].getSpicy_num() + " 微辣"); break; case 2: System.out.print(" 川菜 " + tables[k].getSpicy_num() + " 稍辣"); break; case 3: System.out.print(" 川菜 " + tables[k].getSpicy_num() + " 辣"); break; case 4: System.out.print(" 川菜 " + tables[k].getSpicy_num() + " 很辣"); break; case 5: System.out.print(" 川菜 " + tables[k].getSpicy_num() + " 爆辣"); break; } } if(tables[k].getAcidity_num() > 0){ ss = (double)tables[k].getAcidity()/tables[k].getAcidity_num(); average = (int) Math.round(ss); switch(average){ case 0: System.out.print(" 晋菜 " + tables[k].getAcidity_num() + " 不酸"); break; case 1: System.out.print(" 晋菜 " + tables[k].getAcidity_num() + " 微酸"); break; case 2: System.out.print(" 晋菜 " + tables[k].getAcidity_num() + " 稍酸"); break; case 3: System.out.print(" 晋菜 " + tables[k].getAcidity_num() + " 酸"); break; case 4: System.out.print(" 晋菜 " + tables[k].getAcidity_num() + " 很酸"); break; } }if(tables[k].getSweetness_num() > 0){ ss = (double)tables[k].getSweetness()/tables[k].getSweetness_num(); average = (int) Math.round(ss); switch(average){ case 0: System.out.print(" 浙菜 " + tables[k].getSweetness_num() + " 不甜"); break; case 1: System.out.print(" 浙菜 " + tables[k].getSweetness_num() + " 微甜"); break; case 2: System.out.print(" 浙菜 " + tables[k].getSweetness_num() + " 稍甜"); break; case 3: System.out.print(" 浙菜 " + tables[k].getSweetness_num() + " 甜"); break; } } System.out.println(); } } Map<String, Customer> nameTotalPriceMap = new TreeMap<>(Comparator.comparing(String::toLowerCase)); // 累加表格金额 for (Table table : tabless) { String name0 = table.getPeople(); int totalPrice = table.getTotalPrice(); String phone = table.getTelephone(); // 假设获取电话的方法名为getPhone() // 检查姓名是否已存在于map中,若存在则累加金额,否则添加新的键值对 if (nameTotalPriceMap.containsKey(name0)) { Customer currentCustomer = nameTotalPriceMap.get(name0); int currentTotalPrice = currentCustomer.getTotalPrice(); nameTotalPriceMap.put(name0, new Customer(currentTotalPrice + totalPrice, name0, phone)); } else { nameTotalPriceMap.put(name0, new Customer(totalPrice, name0, phone)); } } // 按拼音顺序输出每位客户的支付金额 for (Map.Entry<String, Customer> entry : nameTotalPriceMap.entrySet()) { System.out.println(entry.getValue().getPeople() + " " +entry.getValue().getPhone()+" "+ entry.getValue().getTotalPrice()); } } } class Customer { private int totalPrice; private String name; private String phone; public Customer(int totalPrice, String name, String phone) { this.totalPrice = totalPrice; this.name = name; this.phone = phone; } public int getTotalPrice() { return totalPrice; } public String getPeople() { return name; } public String getPhone() { return phone; } } //菜品类 class Dish{ String name;//菜品名称 int unit_price; //单价 String dishType; //菜品类型 Boolean tejia;//特价菜标志 public Dish(String name,int unit_price){ this.name = name; this.unit_price = unit_price; } public String getName() { return name; } public void setDishType(String i){ this.dishType = i; } public String getDishType(){ return dishType; } public void setTejia(boolean i){ this.tejia = i; } public Boolean getTejia(){ return tejia; } public int getUnit_price() { return unit_price; } //计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) public int getPrice(int portion){ double price = 0; if(portion == 1) { price = Math.round(unit_price); } else if (portion == 2) { price = Math.round(unit_price*1.5); } else if (portion == 3) { price = Math.round(unit_price*2); }return (int)price; } } //菜单类 class Menu{ Dish[] dishes = new Dish[20] ;//动态菜品数组,保存所有菜品信息 int count1 = 0;//计算有多少道菜品 public Menu() { } //根据菜名在菜谱中查找菜品信息,返回Dish对象。 public Dish searchDish(String dishName){ for (int i = 0; i < count1; i++) { if(dishName.equals(dishes[i].name)){ return dishes[i]; } } return null; } //添加一道菜品信息 public void addDish(String dishName,int unit_price) { if (searchDish(dishName) == null) {//如果这道菜还未添加过,则添加 Dish newDish = new Dish(dishName, unit_price); dishes[count1] = newDish; count1++;//菜品数量加一 }else{ //若添加过,则更新这道菜的价格 searchDish(dishName).unit_price = unit_price; } } } //点菜记录类 class Record { int orderNum;//序号\ Dish dish;//菜品\ int portion;//份额(1/2/3代表小/中/大份) //计价,计算本条记录的价格\ int num;//份数 String dishType = "putong";//该条点菜记录涉及的菜品类型 int kouweidu; public Record(int orderNum,Dish dish,int portion,int num){ this.orderNum = orderNum; this.dish = dish; this.portion = portion; this.num = num; } public void setDishType(String i){ this.dishType = i; } public String getDishType(){ return dishType; } public void setKouweidu(int k){ this.kouweidu = k; } public int getKouweidu(){ return kouweidu; } public int getOrderNum() { return orderNum; } public int getPrice(){ int price = 0; price = Math.round(dish.getPrice(this.portion))*this.num; return price; } public void show(){//显示当前订单 System.out.print(orderNum + " " + dish.name + " " +getPrice()+"\n"); } } //订单类 class Order { Record[] records = new Record[20];//动态订单数组,保存订单上每一道的记录 int count2 = 0; public Order() { } //计算订单的总价 int getTotalPrice(String datestring) { int price = 0; Table tablejudge = new Table(0,"sd","sd",0); for (int i = 0; i < count2; i++) { if (records[i].dish != null) { //菜品存在 price += records[i].getPrice(); } } return price; } int getTotalPrice1(String datestring) { int price = 0; double s = 0; Table tablejudge = new Table(0,"sd","sd",0); for (int i = 0; i < count2; i++) { if (records[i].dish != null && records[i].dish.getTejia().equals(true)&&!tablejudge.isWeekend(tablejudge.parseDate(datestring))) { //菜品存在的同时是特色菜,且日期为工作日 s += Math.round(0.7*records[i].getPrice());//七折 }else if(records[i].dish != null && records[i].dish.getTejia().equals(true)&&tablejudge.isWeekend(tablejudge.parseDate(datestring))){ //菜品存在的同时是特色菜,且日期为周末 s += records[i].getPrice();//不打折 } } price = (int)Math.round(s); return price; } int getTotalPrice2(String datestring) { int price = 0; Table tablejudge = new Table(0,"sd","sd",0); for (int i = 0; i < count2; i++) { if (records[i].dish != null && records[i].dish.getTejia().equals(false)) { //菜品存在的同时不是特色菜 price += records[i].getPrice(); } } return price; } //添加一条菜品信息到订单中 public void addARecord(int orderNum, String dishName, Menu menu, int portion, int num) { if (menu.searchDish(dishName) != null) {//如果点的菜在菜谱中能找到,添加进订单 Record newrecord = new Record(orderNum, menu.searchDish(dishName), portion, num); newrecord.show(); records[count2] = newrecord; count2++; } else {//如果点的菜在菜谱中找不到,输出该菜品不存在 System.out.println(dishName + " does not exist"); } } public void addARecord1(int orderNum, String dishName, Menu menu, int portion, int num) { if (menu.searchDish(dishName) != null) {//如果点的菜在菜谱中能找到,添加进订单 Record newrecord = new Record(orderNum, menu.searchDish(dishName), portion, num); records[count2] = newrecord; count2++; } else {//如果点的菜在菜谱中找不到,输出该菜品不存在 System.out.println(dishName + " does not exist"); } } //根据序号删除一条记录,机理将该记录的份数 = 0。 public void delARecordByOrderNum(int orderNum) { int price = 0; for (int i = 0; i < count2; i++) { if (records[i].orderNum == orderNum) { records[i].num = 0; break; } } } //根据序号找点菜记录,找到了则返回该条记录 public Record searchRecord(int orderNum) { for (int i = 0; i < count2; i++) { if (records[i].orderNum == orderNum) { return records[i]; } } return null; } //根据序号查找一条记录,查到了返回TRUE,没查到返回FALSE public boolean findRecordByNum(int orderNum) { boolean flag = false; for (int i = 0; i < count2; i++) { if (records[i].orderNum == orderNum) { flag = true; break; } } return flag; } } class Table{ int num; //桌号 String dateString; //日期字符串 String timeString; //时间字符串 int sum_price; //总价 String telephone;//电话号码 String people;//姓名 int totalPrice; int spicy ; //辣度 int spicy_num; //川菜数量 int acidity ;//酸度 int acidity_num ; int sweetness ;//甜度 int sweetness_num ; public void setSpicy(int i){ this.spicy += i; } public int getSpicy(){ return spicy; } public void setSpicy_num(int i){ this.spicy_num += i; } public int getSpicy_num(){ return spicy_num; } public void setAcidity(int i){ this.acidity += i; } public int getAcidity(){ return acidity; } public void setAcidity_num(int i){ this.acidity_num += i; } public int getAcidity_num(){ return acidity_num; } public void setSweetness(int i){ this.sweetness += i; } public int getSweetness(){ return sweetness; } public void setSweetness_num(int i){ this.sweetness_num += i; } public int getSweetness_num(){ return sweetness_num; } public void setPeople(String i){ this.people = i; } public String getPeople(){ return people; } public void setTelephone(String i){ this.telephone = i; } public String getTelephone(){ return telephone; } public void setTotalPrice(int i){ this.totalPrice = i; } public int getTotalPrice(){ return totalPrice; } int sum; //份数 //Order[] orders = new Order[20]; public Table(int num,String dateString,String timeString,int sum_price){ this.num = num; this.dateString = dateString; this.timeString = timeString; this.sum_price = sum_price; } public int judge_discount(String dateString,String timeString,int sum_price){ LocalDate date = parseDate(dateString); LocalTime time = parseTime(timeString); if(isWeekend(date)){//如果是周末 if(isBHWeekend(time)) {//如果是周末营业时间 sum_price = sum_price; //System.out.println("table " + num +" 333out of opening hours"); }else{//如果是周末但非营业时间 // System.out.println("table " + num +" out of opening hours"); sum_price = -1; } }else{//如果是周一到周五的工作时间内 if(isNOTime(time)){//如果是中午的营业时间 sum_price = (int)Math.round(0.6*sum_price);//六折 } else if (isEDTime(time)) { sum_price = (int)Math.round(0.8*sum_price);//八折 } else{//如果是周一至周五的非工作时间内 // System.out.println("table " + num +" out of opening hours"); sum_price = -1; } } return sum_price; } //判断是否在营业时间 public boolean judge(String dateString,String timeString){ LocalDate date = parseDate(dateString); LocalTime time = parseTime(timeString); if(isWeekend(date)){//如果是周末 if(isBHWeekend(time)) {//如果是周末营业时间 return true; }else{//如果是周末但非营业时间 return false; } }else{//如果是周一到周五的工作时间内 if(isNOTime(time)){//如果是中午的营业时间 return true; } else if (isEDTime(time)) { return true; } else{//如果是周一至周五的非工作时间内 return false; } } } // 判断是否为周末 public boolean isWeekend(LocalDate date) { return date.getDayOfWeek().getValue() >= 6; } // 判断是否在周末营业时间范围内 public boolean isBHWeekend(LocalTime time) { LocalTime openingTime = LocalTime.parse("09:30:00"); LocalTime closingTime = LocalTime.parse("21:30:00"); if(time.isAfter(openingTime) && time.isBefore(closingTime)){ return true; } else if (time.equals(openingTime) || time.equals(closingTime)) { return true; }else{ return false; } } // 判断是否为周一至周五晚上折扣时间 public boolean isEDTime(LocalTime time) { LocalTime eveningStartTime = LocalTime.parse("17:00:00"); LocalTime eveningEndTime = LocalTime.parse("20:30:00"); if(time.isAfter(eveningStartTime) && time.isBefore(eveningEndTime)){ return true; } else if (time.equals(eveningStartTime) || time.equals(eveningEndTime)) { return true; } else{ return false; } } // 判断是否为周一至周五中午折扣时间 public static boolean isNOTime(LocalTime time) { LocalTime noonStartTime = LocalTime.parse("10:30:00"); LocalTime noonEndTime = LocalTime.parse("14:30:00"); if(time.isAfter(noonStartTime) && time.isBefore(noonEndTime)) { return true; } else if (time.equals(noonStartTime) || time.equals(noonEndTime)) { return true; } else { return false; } } //如果遇到代点菜的,改变当前桌位的金额 public void daidian(int nowtablenum,int fortablenum,int xuhao,String name,int portion,int num,Menu menu){ System.out.println(xuhao+" table "+nowtablenum +" pay for table "+fortablenum + " " + (int)menu.searchDish(name).getPrice(portion)*num); //price = (int)menu.searchDish(name).getPrice(portion)*num; } // 判断一个日期是否合法 public boolean isValidDate(LocalDate date) { try { // 尝试将日期格式化为年月日 String dateStr = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); // 再将格式化后的日期解析为 LocalDate 对象,如果日期与原日期相等,说明该日期合法 return date.equals(LocalDate.parse(dateStr)); } catch (Exception e) { return false; } } public LocalDate parseDate(String dateStr) { // 定义支持的日期格式数组 String[] patterns = {"yyyy/M/d", "yyyy/M/dd", "yyyy/MM/d", "yyyy/MM/dd"}; LocalDate date = null; for (String pattern : patterns) { try { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); date = LocalDate.parse(dateStr, formatter); // 检查年月日的合法性 YearMonth yearMonth = YearMonth.of(date.getYear(), date.getMonth()); boolean isValidDate = yearMonth.isValidDay(date.getDayOfMonth()); if (!isValidDate || !dateStr.equals(date.format(formatter))) { return null; } return date; } catch (DateTimeParseException e) { // 解析失败,继续尝试下一个日期格式 e.printStackTrace(); } } return date; } public LocalTime parseTime(String timeStr) { // 定义支持的日期格式数组 String[] patterns = {"HH/mm/ss", "H/mm/ss", "HH/m/ss", "HH/mm/s","H/m/ss","H/mm/s","HH/m/s","H/m/s"}; LocalTime time = null; for (String pattern : patterns) { try { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); time = LocalTime.parse(timeStr, formatter); return time; } catch (DateTimeParseException e) { // 解析失败,继续尝试下一个日期格式 } } return time; } //根据桌号找桌号信息,找到了则返回true public boolean searchTable(int orderNum,int table_idex,Table[] table) { for (int i = 1; i <= table_idex; i++) { if ( table[i].num == orderNum) { return true; } } return false; } //根据桌号找桌号信息,找到了则返回该桌对应的table_idex public int searchTable1(int orderNum,int table_idex,Table[] table) { for (int i = 1; i <= table_idex; i++) { if ( table[i].num == orderNum) { return i; } } return -1; } //根据桌号找桌号信息,找到了则返回该桌 public Table FindTable(int orderNum,int table_idex,Table[] table) { for (int i = 1; i <= table_idex; i++) { if ( table[i].num == orderNum) { return table[i]; } } return null; } //判断重复序号的两桌是否在同一时间段内 public boolean shiDuan(Table table,LocalDate date,LocalTime time){ LocalDate date0 = parseDate(table.dateString); LocalTime time0 = parseTime(table.timeString); //如果是周末 if(isWeekend(date0)){ //如果两个日期是同一天 if(date0.isEqual(date)){ //且相差一小时以内 if(isWithinOneHour(time,time0)){ return true; }else { return false; } } }else{//如果是工作日 //如果两个日期是同一天 if(date0.isEqual(date)){ //如果都是中午的折扣时间 if(isNOTime(time)&&isNOTime(time0)){ return true; } else if (isEDTime(time)&&isEDTime(time0)) { //如果都是晚上的折扣时间 return true; }else{//同一天但不是同一时段 return false; } } } //不在同一天返回false return false; } public boolean isWithinOneHour(LocalTime time1, LocalTime time2) { Duration duration = Duration.between(time1, time2); long diffInMinutes = Math.abs(duration.toMinutes()); return diffInMinutes <= 60; } public int getSum() { return sum; } public void setSum(int m) { this.sum += m; } }
顺序图:

类图设计

三、踩坑心得
每次作业都会有个错误xx信息的点过不去,能想到是正则表达式有问题但是就是找不到在哪。最后通过询问了老师一个测试用例,发现我的正则表达式中,如果空格连续出现两次时,前一个空格会归并到前面的字符串中,所以唯一空格的表达为://s{1},这么一个小错误找了我好久好久
还有一个很踩坑的点就是,在代点菜的情况中,用户不可以给自己代点!这个情况并未在题目中给出,也是找了很久未果最后询问老师同学得知的
以及由于后面的功能要求,在部分类中又添加了一些属性,但是忘记将这些后续添加的属性方法进行封装了,导致主函数中一直在穿形参,功能要求完不成,下次要养成检查封装的好习惯
四、改进建议
菜单三的更迭中,对时间复杂度有限制,由于我使用的存储方式是普通数组而不是哈希表这些,导致我测试点因为超时原因随机通过不了,导致我提交了很多次终于有一次所有测试点都没超时。下次写代码要提前预测数据量和时间复杂度是不是很大,是的话存储方式也要有改进
还有就是在输入信息处理时,没有对各个板块进行良好的功能分割,导致代码很多代码堆砌在主函数中,下次可以运用最近学的工厂模式等设计模式,对该类情况进行改进
五、总结
这三次作业的菜单更迭中,我在开发过程中遇到了一些问题。首先,最初的代码框架没有建立清晰的任务分割,导致大量的if-else语句堆积在主函数中,造成了时间复杂度的增加。后来学习了工厂模式等设计模式的知识,希望在下次类似作业中能够应用,避免这种情况的发生。其次,我发现在处理输入信息时,没有良好地对各个板块进行功能分割,导致代码在主函数中堆积得很多。下次我打算运用最近学到的工厂模式等设计模式,对这种情况进行改进。此外,对于菜单三的更迭中,我没有考虑到时间复杂度的限制。由于我使用的存储方式是普通数组而不是哈希表等,导致某些测试点由于超时而无法通过。下次我会提前预测数据量和时间复杂度是否很大,并相应改进存储方式。
总的来说,这次作业让我巩固了类的封装设计、方法重载、类的继承以及正则表达式等相关知识。在写作业的过程中,我也踩过一些坑,但通过请教老师和同学以及查阅相关资料,我不断进步并从中获得了宝贵的经验。对于期中考试,我意识到自己在接口方面的理解还不够牢固,需要加强基础理论的学习与巩固。总的来说,我会继续努力改进,提升自己的编程能力。