22-用数组灵活处理成绩
原创2023年12月1日大约 11 分钟...约 3430 字
0. 目录
- 一个程序搞定成绩的各种处理需求
1. 一个程序搞定成绩的各种处理需求
- 求某年最好成绩
- 求某年的平均成绩
- 求所有年份最好成绩
- 求某门课历年最好成绩
- 自由发挥……
/**
* @ClassName: ScoreMaster
* @Description: TODO
* @Author: AI悦创
* @Date: 2022/10/9 19:24
* @Version: V1.0
* @Blog: https://www.bornforthis.cn
*/
import java.util.Scanner;
public class ScoreMaster {
public static void main(String[] args) {
// 声明六个变量, 分别代表六门科目的成绩
int YuWenIndex = 0;
int ShuXueIndex = 1;
int WaiYuIndex = 2;
int WuLiIndex = 3;
int HuaXueIndex = 4;
int ShengWuIndex = 5;
int totalScoreCount = 6;
// 每门课的名字
String[] names = new String[totalScoreCount];
names[YuWenIndex] = "语文";
names[ShuXueIndex] = "数学";
names[WaiYuIndex] = "外语";
names[WuLiIndex] = "物理";
names[HuaXueIndex] = "化学";
names[ShengWuIndex] = "生物";
Scanner scanner = new Scanner(System.in);
System.out.println("请输入共有多少年的成绩:");
int yearCount = scanner.nextInt();
double[][] scores = new double[yearCount][totalScoreCount]; // 看几年的数组
for (int i = 0; i < yearCount; i++) {
for (int j = 0; j < totalScoreCount; j++) {
scores[i][j] = 80 + Math.random() * 20;
System.out.println("第" + (i + 1) + "年" + names[j] + "成绩为:" + scores[i][j]);
}
}
boolean cont = true;
while (cont) {
System.out.println("请选择要进行的操作:");
System.out.println("1: 求某年最好成绩\n" +
"2: 求某年的平均成绩\n" +
"3: 求所有年份最好成绩\n" +
"4: 求某门课历年最好成绩");
int oprtId = scanner.nextInt();
int year = 0; // 在 switch 用一块代码块里,不能声明同一个变量,所以直接写在外面,方便。不然得想不同的变量名。
switch (oprtId) {
// 先编写 case
case 1:
// 让用户输入指定的年份
System.out.println("请输入要计算第几年的最好成绩");
year = scanner.nextInt();
if (year <= 0 || yearCount < year) {
System.out.println("非法的年份:" + year);
cont = false;
break;
}
year = year - 1;
// 指定年份的最好成绩的编号,开始假设是0
int bestOfYearScoreId = 0;
// 循环指定年份的成绩,找出最好的成绩
// TODO:如果有两门课的成绩一样,而且都是最高的,怎么办?
for (int i = 1; i < totalScoreCount; i++) {
if (scores[year][bestOfYearScoreId] < scores[year][i]) {
bestOfYearScoreId = i;
}
}
System.out.println("第" + (year + 1) + "年成绩最好的科目为" + names[bestOfYearScoreId] + ",成绩为" + scores[year][bestOfYearScoreId] + "。");
break;
case 2:
System.out.println("请输入要计算第几年的平均成绩");
year = scanner.nextInt();
if (year <= 0 || yearCount < year) {
System.out.println("非法的年份:" + year);
cont = false;
break;
}
year = year - 1;
double totalCountForAvg = 0;
for (int i = 0; i < totalScoreCount; i++) {
totalCountForAvg += scores[year][i];
}
double avgOfYear = totalCountForAvg / totalScoreCount;
System.out.println("第" + (year + 1) + "年的平均成绩为" + avgOfYear + "。");
break;
case 3:
int bestYear = 0;
int bestScore = 0;
for (int i = 0; i < yearCount; i++) {
for (int j = 0; j < totalScoreCount; j++) {
if (scores[bestYear][bestScore] < scores[i][j]) {
bestYear = i;
bestScore = j;
}
}
}
// 视频中代码有错误,应该是使用 bestYear 而不是 year, 鸣谢 @zZGod 帮忙揪出 bug 一只。
System.out.println("所有年度最好成绩为第" + (bestYear + 1) + "年的" + names[bestScore] + ",成绩为" + scores[bestYear][bestScore] + "。");
break;
case 4:
System.out.println("请输入科目编号");
int subjectId = scanner.nextInt();
if (subjectId <= 0 || totalScoreCount < subjectId) {
System.out.println("非法的科目编号:" + subjectId);
cont = false;
break;
}
subjectId = subjectId - 1;
year = 0;
for (int i = 1; i < yearCount; i++) {
if (scores[year][subjectId] < scores[i][subjectId]) {
year = i;
}
}
System.out.println("第" + (year + 1) + "年度" + names[subjectId] + "成绩最好,为" + scores[year][subjectId] + "。");
break;
default:
cont = false;
System.out.println("不支持:" + oprtId + ", 程序结束。");
}
}
}
}
2. 附加题
看到大家学得很积极,不少同学还有催更的意思。我仿佛看到自己大学时的样子,暗自奸笑:大家对已经学到的知识的力量还没有完全认识。我赶了一个附加题出来,催更的同学可以先做一下冷静冷静 (-:
题目是一个双人对战五子棋。完成这道题需要你活学活用循环分支和数组,还有各种变量的作用域,最重要的是还有对问题的:
- 理解;
- 分解;
- 代码设计和实现。
题目说明和源代码:
建议大家先看说明,然后尝试独立完成作业,最后再看源代码。
在开始之前我以为我可以半小时搞定,实际... 嗯... 连写带调试搞了有俩小时。程序员都是盲目的乐观派,你觉得你要用多久呢?欢迎留言分享~
3. 五子棋
3.1 五子棋盘
Code1
/**
* @ClassName: WuZiQiHuaQiPan
* @Description: TODO
* @Author: AI悦创
* @Date: 2022/10/11 11:38
* @Version: V1.0
* @Blog: https://www.bornforthis.cn
*/
public class WuZiQiHuaQiPan {
public static void main(String[] args) {
// 代表不同的角色
int black = 0;
int white = 1;
int empty = 2;
// 不同的角色的不同的棋子字符
char[] qizi = new char[3];
qizi[0] = '●';
qizi[1] = '○';
qizi[2] = ' ';
// 刚刚下好的棋子,用不一样的图形提示
// 这里使用了一种新的创建数组的语法,可以不显示的指定数组的大小,而是在一对打括号里按照顺序指定数组里的每个元素的值
// 这样数组的创建和赋值就合二为一了。当然这样创建的数组大小也是不可变的,结果没有不同。
char[] qiziJustMove = new char[]{'■', '□', ' '};
int size = 20;
int qipan[][] = new int[size][size];
int roleJustMove = 1;
int justMoveLine = size / 2;
int justMoveColumn = size / 2;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (i == justMoveLine && j == justMoveColumn) {
qipan[i][j] = black;
} else {
qipan[i][j] = (i + j) % qizi.length;
}
}
}
// String form = "└┘┌┐├┤│┬┴ ┼";
String header = "\t";
for (int j = 0; j < size; j++) {
header += (j + 1) + "\t";
}
System.out.println(header);
for (int i = 0; i < size; i++) {
String line = "" + (i + 1) + "\t";
for (int j = 0; j < size; j++) {
char[] arrayToUse =
// Java中的三元操作符,?前面是一个boolean表达式,
// 如果boolean表达式的值为true,则这个表达式的值为冒号前面的值,
// 如果boolean表达式的值为false,则这个表达式的值为冒号后面的值
(i == justMoveLine && j == justMoveColumn) ? qiziJustMove : qizi;
//这个表达式等价于
// char[] arrayToUse;
// if (i == justMoveLine && j == justMoveColumn) {
// arrayToUse = qiziJustMove;
// } else {
// arrayToUse = qizi;
// }
line += arrayToUse[qipan[i][j]] + "\t";
}
System.out.println(line + (i + 1));
}
System.out.println(header);
}
}
Code
/**
* @ClassName: WuZiQiHuaQiPan
* @Description: 五子棋画棋盘程序,主要实现棋盘的绘制
* @Author: AI悦创
* @Date: 2022/10/11 11:38
* @Version: V1.0
* @Blog: https://www.bornforthis.cn
*/
public class WuZiQiHuaQiPan {
public static void main(String[] args) {
// 定义三个角色,分别表示黑子、白子和空位置
int black = 0;
int white = 1;
int empty = 2;
// 定义一个字符数组,用于表示不同角色的棋子符号
char[] qizi = new char[3];
qizi[0] = '●'; // 黑棋用 ● 表示
qizi[1] = '○'; // 白棋用 ○ 表示
qizi[2] = ' '; // 空位置用 空格 表示
// 定义另一个字符数组,用于表示刚刚下好的棋子,用特殊符号表示
char[] qiziJustMove = new char[]{'■', '□', ' '}; // 黑棋、白棋和空位置分别对应不同的特殊符号
// 定义棋盘的大小,这里设为 20x20 的二维数组
int size = 20;
int qipan[][] = new int[size][size]; // 用二维数组表示棋盘
// 定义刚刚下棋的角色,1 表示白棋
int roleJustMove = 1;
// 定义刚刚下棋的行和列,初始值为棋盘中心位置
int justMoveLine = size / 2;
int justMoveColumn = size / 2;
// 初始化棋盘数据
for (int i = 0; i < size; i++) { // 遍历每一行
for (int j = 0; j < size; j++) { // 遍历每一列
// 如果当前格子是刚刚下棋的位置
if (i == justMoveLine && j == justMoveColumn) {
qipan[i][j] = black; // 放置黑棋
} else {
// 其他位置根据行列索引值的和对角色数取模,决定是黑棋、白棋还是空位
qipan[i][j] = (i + j) % qizi.length;
}
}
}
// 构造棋盘顶部的数字标题,表示列号
String header = "\t"; // 开头的制表符用于对齐
for (int j = 0; j < size; j++) {
header += (j + 1) + "\t"; // 将列号添加到标题中
}
System.out.println(header); // 打印标题行
// 打印棋盘的每一行
for (int i = 0; i < size; i++) {
// 行的开头部分,显示行号
String line = "" + (i + 1) + "\t";
for (int j = 0; j < size; j++) {
// 判断当前格子是否是刚刚下棋的位置,决定使用普通棋子符号还是特殊棋子符号
char[] arrayToUse =
(i == justMoveLine && j == justMoveColumn) ? qiziJustMove : qizi;
// 将对应符号添加到当前行
line += arrayToUse[qipan[i][j]] + "\t";
}
// 打印当前行,末尾再加上行号用于对齐
System.out.println(line + (i + 1));
}
// 再次打印顶部的数字标题,方便棋盘查看
System.out.println(header);
}
}
3.2 五子棋完整版
/**
* @ClassName: WuZiQi
* @Description: TODO
* @Author: AI悦创
* @Date: 2022/10/11 11:41
* @Version: V1.0
* @Blog: https://www.bornforthis.cn
*/
import java.util.Scanner;
public class WuZiQi {
public static void main(String[] args) {
System.out.println("********************************************************");
System.out.println(" 欢迎来到双人五子棋对战");
System.out.println("********************************************************");
Scanner in = new Scanner(System.in);
// 代表不同的角色
int black = 0;
int white = 1;
int empty = 2;
int[] result = new int[2];
// 不同的角色的不同的棋子字符
char[] qizi = new char[3];
qizi[0] = '●';
qizi[1] = '○';
qizi[2] = ' ';
int[][] checkConnectedDirection = new int[][]{{1, 0}, {0, 1}, {1, 1}, {1, -1}};
String[] direction = new String[]{"垂直", "水平", "斜向下", "斜向上"};
// 刚刚下好的棋子,用不一样的图形提示
// 这里使用了一种新的创建数组的语法,可以不显示的指定数组的大小,而是在一对打括号里按照顺序指定数组里的每个元素的值
// 这样数组的创建和赋值就合二为一了。当然这样创建的数组大小也是不可变的,结果没有不同。
char[] qiziJustMove = new char[]{'■', '□', ' '};
boolean play = true;
while (play) {
System.out.println("请输入棋盘大小,棋盘要大于5,小于100");
int size = in.nextInt();
if (size < 5 || size >= 100) {
System.out.println("qipandaxiaofeifa");
continue;
}
int[][] qipan = new int[size][size];
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
qipan[i][j] = empty;
}
}
String header = "\t";
for (int j = 0; j < size; j++) {
header += (j + 1) + "\t";
}
System.out.println("请输入黑方选手名字:");
String blackName = "黑方:" + in.next();
System.out.println("请输入白方选手名字:");
String whiteName = "白方:" + in.next();
String[] roleNames = new String[]{blackName, whiteName};
System.out.println("欢迎黑方选手" + roleNames[black] + "和白方选手" + roleNames[white] + "开始对战五子棋");
int currRole = black;
while (true) {
int justMoveLine;
int justMoveColumn;
while (true) {
int lineToMove;
int columnToMove;
System.out.println(roleNames[currRole] + "下子。");
System.out.println("请输入落子的行:");
lineToMove = in.nextInt();
System.out.println("请输入落子的列:");
columnToMove = in.nextInt();
justMoveLine = lineToMove - 1;
justMoveColumn = columnToMove - 1;
if (justMoveLine < 0 || justMoveLine > size - 1) {
System.out.println("行" + lineToMove + "超出了棋盘范围");
continue;
}
if (justMoveColumn < 0 || justMoveColumn > size - 1) {
System.out.println("列" + columnToMove + "超出了棋盘范围");
continue;
}
if (qipan[justMoveLine][justMoveColumn] != empty) {
System.out.println("行" + lineToMove + ",列" + columnToMove + "处有子了");
continue;
}
System.out.println(roleNames[currRole] + "落子在:行" + lineToMove + ",列" + columnToMove);
break;
}
qipan[justMoveLine][justMoveColumn] = currRole;
// 打印棋盘
System.out.println(header);
for (int i = 0; i < size; i++) {
String lineToPrint = "" + (i + 1) + "\t";
for (int j = 0; j < size; j++) {
char[] arrayToUse =
// Java中的三元操作符,?前面是一个boolean表达式,
// 如果boolean表达式的值为true,则这个表达式的值为冒号前面的值,
// 如果boolean表达式的值为false,则这个表达式的值为冒号后面的值
(i == justMoveLine && j == justMoveColumn) ? qiziJustMove : qizi;
lineToPrint += arrayToUse[qipan[i][j]] + "\t";
}
System.out.println(lineToPrint+ (i + 1));
}
System.out.println(header);
// 只要从刚刚下子的地方检查是不是有五连子就可以了
boolean outputDebug = false;
boolean hasWinner = false;
int currCheckCondition;
// 我们要检查四个方向,分别为横,竖,斜上,斜下。四个方向对应的每个方向的索引delta在数组里保存
for (int i = 0; i < checkConnectedDirection.length & (!hasWinner); i++) {
currCheckCondition = i;
if (outputDebug) {
System.out.println("检查方向为" + direction[i]);
}
int deltaLine = checkConnectedDirection[i][0];
int deltaColumn = checkConnectedDirection[i][1];
// 保存当前方向上有多少棋子相连
int totalConnected = 1;
// 对于每个方向,以当前落子点为起点,又有两个方向要检查。
// 以横着的方向为例子,横着要向前检查一次,如果遇到不是自己的子,或者到了棋盘边界,要再向后检查一次。
// 向前检查的时候,deltaLine为1,deltaColumn为0;
// 向后检查的时候,deltaLine为-1,deltaColumn为0;
for (int j = 0; j < 2 & (!hasWinner); j++) {
// 所以这里for循环两次,每次循环的时候,delta要乘以-1,代表变换检查的方向
// 比如水平方向,要检查两次,第一次是向左,第二次向右,两次的delta正好是*-1的关系
deltaLine *= -1;
deltaColumn *= -1;
// 把我们要检查的点恢复到刚刚下子的点
int lineToCheck = justMoveLine;
int columnToCheck = justMoveColumn;
if (outputDebug) {
System.out.println("line方向每次检查的变化为" + deltaLine);
System.out.println("column方向每次检查的变化为" + deltaColumn);
}
// 在个方向上,固定delta的情况下,查找有多少相连的子。
// 比如在水平方向,linedelta为1的情况下,检查有多少子相连
while (true) {
// 检查点根据delta进行变换
lineToCheck += deltaLine;
columnToCheck += deltaColumn;
boolean lineIndexOK = lineToCheck >= 0 && lineToCheck < size;
boolean columnIndexOK = columnToCheck >= 0 && columnToCheck < size;
if (outputDebug) {
System.out.println("line方向当前检查的位置为" + (lineToCheck + 1) + "。位置在棋盘内" + lineIndexOK);
System.out.println("column方向当前检查的位置为" + (columnToCheck + 1) + "。位置在棋盘内" + columnIndexOK);
}
if (lineIndexOK && columnIndexOK && qipan[lineToCheck][columnToCheck] == currRole) {
totalConnected++;
if (outputDebug) {
System.out.println("在此位置找到相连的子,当前相连的子的数量为" + totalConnected);
}
if (totalConnected >= 5) {
System.out.println(roleNames[currRole] + "胜出!五子相连方向为" + direction[currCheckCondition]);
result[currRole]++;
hasWinner = true;
break;
}
} else {
if (outputDebug) {
System.out.println("未找到相连的子,当前相连的子为" + totalConnected);
}
break;
}
}
}
}
if (hasWinner) {
break;
}
currRole = (currRole + 1) % 2;
}
System.out.println("********************************************************");
System.out.println(roleNames[0] + "胜出" + result[0] + "次," + roleNames[1] + "胜出" + result[1] + "次。");
System.out.println("********************************************************");
System.out.println("是否再来一盘?");
play = in.nextBoolean();
}
}
}
欢迎关注我公众号:AI悦创,有更多更好玩的等你发现!
公众号:AI悦创【二维码】
AI悦创·编程一对一
AI悦创·推出辅导班啦,包括「Python 语言辅导班、C++ 辅导班、java 辅导班、算法/数据结构辅导班、少儿编程、pygame 游戏开发」,全部都是一对一教学:一对一辅导 + 一对一答疑 + 布置作业 + 项目实践等。当然,还有线下线上摄影课程、Photoshop、Premiere 一对一教学、QQ、微信在线,随时响应!微信:Jiabcdefh
C++ 信息奥赛题解,长期更新!长期招收一对一中小学信息奥赛集训,莆田、厦门地区有机会线下上门,其他地区线上。微信:Jiabcdefh
方法一:QQ
方法二:微信:Jiabcdefh
你认为这篇文章怎么样?
- 0
- 0
- 0
- 0
- 0
- 0