前不久有个学生做课程设计跑来问我老师说要做三个有趣的实验进制转换、猜数字、调色板听起来都很简单但设计思路怎么写才不会被批太水我一看这三个题目其实特别适合练手每个都藏着一个值得想清楚的核心问题进制转换考的是数学逻辑怎么用代码表达猜数字考的是交互循环怎么设计才顺手调色板考的是模型映射和界面联动。这篇文章就把我实际做的设计思路和踩过的坑一并说清楚给正在做类似题目或想回顾基础的朋友做个参照。1. 进制转换别急着写代码先把位权这件事想透1.1 核心原理短除法与位权展开进制转换看着简单但很多人在设计思路上栽跟头原因是上来就在查有没有现成函数。Java里确实有Integer.toBinaryString()、toHexString()但实验要求披露的往往是用短除法手工实现——这才是出题人真正想让你练的东西。短除法的本质是一个十进制数N转成base进制就是不断用N / base取余数作为当前位的值再对商继续操作直到商为 0最后把余数序列倒过来。倒过来这一步是新手最容易漏的。举一个具体的例子把十进制 26 转成二进制。26 / 2 13 余 0 13 / 2 6 余 1 6 / 2 3 余 0 3 / 2 1 余 1 1 / 2 0 余 1余数从下往上读是 11010所以26的二进制是11010。这个过程的每一步都在用位权二进制每一位的权重是 2 的幂短除法实际是在反向拆解 最多有几个 4、几个 2、几个 1。我在设计这个实验时习惯先手写一张位权表进制位权示例转换原理二进制2^416, 2^38, 2^24, 2^12, 2^01每位只能是 0/1八进制8^3512, 8^264, 8^18每位可以是 0~7十六进制16^2256, 16^116, 16^01每位可以是 0~1510~15 用 A~F 表示这一步做完代码其实就是短除法的翻译。1.2 代码设计的三个层次我建议把整个实验拆成三个方法而不是全塞进main里。这样老师看你的设计思路会觉得是个会写代码的人而不是一个只会堆砌逻辑的新手。第一个层次是输入校验。你需要判断用户传进来的字符串是不是合法数字、是不是在允许的进制范围内。比如转成 20 进制这种需求如果你支持就要定义 10~19 用什么字符表示如果不支持就明确抛异常。第二个层次是转换核心。用短除法处理正整数部分注意0这个数字直接返回0否则循环条件while (n 0)会直接跳过输出空字符串。这是我见过最容易被忽略的边界条件。第三个层次是反向输出。2 到 10 进制的余数可以直接拼成字符超过 10 进制就要做字符映射。十六进制里 10 对应 A11 对应 B一直到 15 对应 F。可以用一个小数组char[] digits 0123456789ABCDEF.toCharArray()来查表比if/else判断清爽得多。1.3 一个完整的 Java 参考实现下面这段是我实际用来做演示的版本去掉了一些冗长的注释保留了核心结构你可以对照着理解设计思路。public class BaseConverter { private static final char[] DIGITS 0123456789ABCDEF.toCharArray(); public static String toBase(int number, int base) { if (base 2 || base 16) { throw new IllegalArgumentException(base must be in [2, 16]); } if (number 0) { return 0; } boolean negative number 0; int n Math.abs(number); StringBuilder sb new StringBuilder(); while (n 0) { sb.append(DIGITS[n % base]); n / base; } if (negative) { sb.append(-); } return sb.reverse().toString(); } public static void main(String[] args) { System.out.println(toBase(26, 2)); // 11010 System.out.println(toBase(26, 16)); // 1A System.out.println(toBase(0, 8)); // 0 } }StringBuilder.reverse()是我个人比较偏好的写法比用一个栈再逐个 pop 更直观。如果你用 C 或 Python思路也一样只是容器换一下而已。1.4 边界条件与常见的坑我在反复测试里发现这几个问题如果你在设计文档里能主动写出来说明你真的理解了负数怎么处理我是取绝对值转换后加上负号。如果把负数直接传给%运算Java 的余数可能是负数要小心。number 0要单独判断原因上面提过。进制基数的合法性要在转换前校验不然传一个base 1进去程序会死循环。如果进制超过 16比如 20 进制字符映射就不够了。你可以扩展DIGITS数组但要做个约定比如 10 用 A11 用 B一直到 35 用 Z。这种做法在真实场景中是存在的比如 Base36 编码。我建议在实验报告里加一个小节专门写边界条件设计把0、负数、超大数、非法进制这四类情况都列出来说明你的处理策略。这一小节就能让整个设计思路的完整度上一个台阶。2. 猜数字重点不是猜是交互循环的设计2.1 从需求还原游戏规则猜数字的经典版本是程序在 1 到 100 之间随机一个整数用户输入猜测值程序告诉大了还是小了直到猜中为止。听起来特别简单但它其实是状态机 循环 输入输出的一个微型综合体。出题人的考察点通常有两个一个是你能不能正确使用随机数和比较逻辑另一个是你能不能把循环写得不死、不跳、不漏。很多学生拿不到高分就是因为把看家逻辑写进一个while里按钮和窗口都没有交上去就是一个纯控制台程序功能倒是能跑但设计感几乎没有。我在做这个实验时第一件事不是写代码而是画了一个用户行为流程开始 - 生成随机数 - 进入循环 循环内读取输入 - 比较大小 - 大了/小了 - 继续循环 猜中 - 记录次数 - 询问是否再来一局这个流程确定下来后代码结构自然就清晰了。循环条件不再是while (true)这种没有自我保护意识的写法而是用一个boolean状态变量来控制比如boolean guessed false; while (!guessed)。2.2 设计一个有层次的反馈机制好的猜数字游戏不是简单输出大了或小了而是应该给用户足够的上下文。我实现过一个增强版反馈信息里带上当前区间比如用户猜 50程序说大了范围缩小到 [1, 49] 用户猜 25程序说小了范围缩小到 [26, 49]这其实就是在引导用户使用二分法。你可以在设计报告里专门提一句这个反馈机制本质上是区间收敛每一次反馈都是把搜索空间缩小一半最坏情况下只需要log2(100) ≈ 7次就能猜中。这个点一旦点在报告里整个实验的层次就不一样了。次数统计也很重要。我习惯用一个attempts变量每次进入循环体就attempts最后猜中时输出。还可以做一个简单的评价体系猜中次数评价1 次欧皇附体2~7 次逻辑型选手8~14 次运气还行15 次以上纯靠缘分这种游戏化的设计能显著提升实验的完成度而且实现成本非常低一个if/else链而已。2.3 随机数的使用要点避免走入每次都重新随机的误区随机数的种子要放在循环外面。如果你把Random对象放进循环里每次 new 一个很多语言在很短的调用间隔内会用当前时间做种子导致同一秒内生成的结果相同游戏一开始就露馅了。正确的做法Random random new Random(); int target random.nextInt(100) 1; // [1, 100]注意nextInt(100)生成的是 0 到 99想要 1 到 100 就得1。这一步我在指导别人的时候几乎每次都会看到有人写错。范围设置不对游戏玩起来会非常诡异比如永远猜不到 100。另外如果做一个再来一局功能记得在游戏结束之后重新调用random.nextInt()而不是复用上一次的target。初学者容易把target定义为final然后在同一局里反复玩程序会一直说猜对了——这属于设计逻辑错误。2.4 我在测试中发现的一个隐藏 bug有一个很搞笑的 bug 值得写出来提醒你我在第一次实现时判断逻辑写成了下面的顺序if (guess target) { System.out.println(大了); } else if (guess target) { System.out.println(小了); } else { System.out.println(恭喜猜中了); }这段代码本身没毛病。但我想加一个猜中时显示你总共猜了 N 次的功能结果把attempts放在了guess target的分支里导致用户猜大了计一次数猜小时不计最终次数永远是错的。这类逻辑位置错误在小型实验里极难通过跑一遍发现因为你不会去刻意数次数。建议养成一个习惯在测试时手动打印中间变量比如临时把attempts和target输出到控制台确认数据流动符合预期后再移除调试代码。3. 调色板从 RGB 到界面联动的可视化实验3.1 RGB 到底在表达什么第三个实验调色板和前两个不同前两个是纯逻辑运算这个涉及 UI 设计和界面联动。调色板的核心概念是 RGB 颜色模型红Red、绿Green、蓝Blue三原色每种颜色分量通常用 0 到 255 表示三色叠加就能呈现出几乎所有常见颜色。调色本质上就是同时对三个分量进行变化并实时预览结果。我在设计时做了这样的拆解用户操作三个滑块分别控制 R、G、B数据变化滑块值 → 颜色值映射预览区一个带背景色的面板背景颜色 当前 RGB 值数值展示同时显示 RGB 和对应的 HEX 字符串3.2 设计思路单向数据流这个实验用到了一个值得学习的编程思想单向数据流。你的界面永远是对状态的一种渲染用户的每个操作都只是修改状态然后触发界面刷新而不是用户直接去改颜色。用 Swing 来举例实际逻辑如下int r redSlider.getValue(); int g greenSlider.getValue(); int b blueSlider.getValue(); Color color new Color(r, g, b); previewPanel.setBackground(color); hexLabel.setText(String.format(#%02X%02X%02X, r, g, b));%02X表示十六进制两位数不足两位补零。这个格式化小技巧很多人不知道会用Integer.toHexString写一堆判断来补零实际上String.format一行搞定。单向数据流的优势是你永远不会出现滑块动了但颜色没变或标签显示的和预览不一致这类问题因为 UI 只依赖当前状态状态一变所有关联控件统一刷新。3.3 滑块的联动细节在实际界面实现中最容易踩的坑是多个滑块彼此不关联。你动了红色滑块绿色和蓝色区域的颜色也要实时变化而不是只更新红色分量对应的部分。实现时我给三个滑块添加同一个ChangeListener监听器内部只做一件事读取三个滑块的最新值刷新预览区和标签。关键点在于不要在每个滑块的监听器里分别写刷新逻辑否则代码重复维护起来很痛苦。ChangeListener listener e - { Color c new Color(rSlider.getValue(), gSlider.getValue(), bSlider.getValue()); preview.setBackground(c); infoLabel.setText(toHex(c)); }; rSlider.addChangeListener(listener); gSlider.addChangeListener(listener); bSlider.addChangeListener(listener);这样一个监听器统一处理所有滑块逻辑很集中也方便后期扩展比如加一个透明度 Alpha 分量只需要再加一个滑块然后监听器里多读一个值。3.4 从调色板延伸到拾色器调色板实验做完后可以顺手加一个反向功能在预览区写一个输入框支持用户直接输入 HEX 颜色值比如#FF8800然后反向解析出 RGB 三个分量并设置滑块位置。这样正向调色、反向输入都能通整个实验的闭环感会更强。正向和反向转换的幂等性也是一个值得在报告里写清楚的点RGB(255, 136, 0) - #FF8800这个转换是双向的解析时注意去掉开头的#并且对非法输入如#GGGGGG要做异常捕获或返回默认颜色。我在实现时用了一个try/catch包裹Color.decode()防止用户输入垃圾内容导致界面崩溃。4. 三个实验的编排逻辑与课程设计复盘4.1 为什么 设计思路 比 能跑 更重要很多做课程设计的朋友容易陷入一个误区就是代码能跑就算完事。实际上对实验类的作业来说阅卷人最想看到的是你为什么这么做。三个实验恰好对应三种不同的设计思维进制转换数学逻辑的程序化表达猜数字状态循环与交互反馈调色板UI 状态与数据映射的联动放在一起做刚好覆盖了编程入门阶段最核心的三个能力算法逻辑、控制流、界面交互。这也是出题人喜欢把这几个题目绑在一起的原因。学生如果能在整理设计思路时把这三者的差异点说清楚比堆砌一千行代码更有说服力。4.2 调试顺序与线上考试提交的建议我个人的建议是按照进制转换 → 猜数字 → 调色板的顺序来做难度是渐进的。先解决纯逻辑、没有界面依赖的实验再引入交互循环最后挑战带 UI 的调色板。这样即使进度卡住前面的成果也是完整可提交的。现在很多实验要通过线上考试系统提交提交前记得做两件事一是确认入口类的包名和类名是否和题目要求一致比如要求Main类就绝不能写Test二是去系统里跑一遍示例用例。我见过太多人本地main方法跑得飞起一上传就编译错误原因往往是类名不匹配或者环境编码问题。4.3 扩展方向一个实验变成一个小工具箱如果你做完这三个还有余力我强烈建议把它们整合到一个小工具箱里。做一次菜单化的整合选项一进制转换工具选项二猜数字游戏选项三调色板 拾色器用一个主菜单做分支选择再用一个循环让用户退出后能返回菜单。这样原本三个孤立的小实验就变成一个完整的控制台应用设计思路的深度完全不一样。我后面做的随机练习题生成器也是从这种整合思路延展来的。个人实践中的几点体会这三个实验是我见过最经典也最容易被低估的入门组合。真正做下来之后我最大的体会是设计思路不是写一堆我用了 for 循环、setBackground这种流水账而是把每个实验的核心问题清晰地讲明白。进制转换的核心是短除法与字符映射猜数字的核心是循环与反馈控制调色板的核心是滑块到颜色状态的单向数据流。把这三个问题用文字讲清楚再配上精心整理的边界条件和测试用例这份报告的可信度就很高了。最后再分享一个小技巧提交之前把你的实验过程录一段屏或者至少截几个关键状态的图——比如进制转换的 0 测试、猜数字的二分法最快路径、调色板的#FF8800输入——放在文档末尾作为测试截图。这比写一百句已测试都管用也是我这些年评审各类作品时最认的东西。