• 5.编写程序 超强力方法


    5.1 创建战舰游戏

    创建一个类似战舰的游戏:攻击网站

    有一种棋盘类的战舰游戏,目标是要猜测对方战舰的坐标,然后轮流开炮攻击,命中数发就可以打沉对方的战舰。不过我们不喜欢战争,只要打垮这些达康公司就好(因为与商业行为有关,如此一来本书就可以归类在经营企管的费用上)。

    游戏目标:以最少的猜测次数打掉计算机所安排的达康公司(Dot Com)网站。计算机会根据你的表现来评分。

    初始设置:程序启动后,计算机会在虚拟的7×7方格上安排3个达康网站。安排完成后,游戏会要求你开始猜坐标。

    进行游戏:因为我们还没有学到图形接口的程序设计,所以这一版会在命令栏上进行。计算机会提示你输入所猜测的位(格子),你会输入“A3”或“C5”等。计算机会反馈给你命中“Hit”没中“Miss”或击沉“Sunk”等回应。当你清光所有的达康时,游戏会列出你的分数并结束。

    首先进行高层设计 

    游戏流程:

    1.玩家启动游戏

    A.计算机创建3个达康网站

    B.将此3个达康网站停在虚拟机战场上

    2.游戏开始

    重复下面的操作直到所有达康网站被歼灭为止

    A.提示玩家输入坐标

    B.检查是否击中、没中或击沉。若命中就删除格子,击沉就删除达康网站

    3.游戏结束

    根据猜测次数给分

    5.2 简单版

    攻击网站游戏 简单的开始

    1.游戏启动 创建单一的DotCom并指定3个各自在共7格的横列中的位置。相对于使用“A2"的表示法,现在的为止只需要数字就可以。

    2.开始游戏 提示玩家猜测,然后检查是否名中国DotCom的格子。若是,则递增numOfHits变量的值。

    3.游戏结束 3格都命中时游戏结束(当numOfHits的值递增到3),并告诉玩家他们花了多少次才干掉这个DotCom 

    看起来我们至少需要两个类;Game类和DotCom类。但在我们着手开发完整功能版之前,先从一个简单版本开始。简单版称为“Simple Dot Com Game”。这一章会创建出此版本,下一章会进行豪华版的开发工作。该版本的东西都比较简单。相对于二维方阵,我们只使用横列,并且只设定一家达康公司。然而游戏的目标仍然相同,因此游戏还是会需要做出DotCom的实例,将它指派在横列上,取得玩家的输入,并在所有的DotCom格子被命中时结束游戏。这个简单版能够作为豪华版的踏脚石。

    在这个简单版中,Game这个类没有实例变量,且所有的程序代码都在main()中。也就是说程序启动执行main()只会做出一个DotCom的实例,挑出一个位置来放3个连续的格子,要 求玩家猜测,检查是否命中,重复这些步骤直到3格都被命中为止。 

    要知道虚拟的横列是虚拟的。换言之,它并没有出现在程序中,只要玩家与计算机都知道有3个连续的格子会出现在7格的横列中就好,横列并不一定要表现在程序代码中。你也许会想要用有7个int的数组来代表横列,并用其中3个元素代表达康出现的位置,但其实不需这么做。我们只需要3个元素的数组来代表DotCom占据的位置。

    开发类

    身为一个程序员,你或许会有编写程序的方法论(methodology)/过程(process)/步骤(approach)。我们的顺序设计是先通过编写程序来帮助你了解和学习我们的想法,并不需要遵循我们实际上怎样写程序的方式。当然啦,实际工作时,你会遵循个人、项目或客户的规范。但我们完全是依照我们自己的想法去做的。当我们在创建Java的类以当作“学习经验”时,程序会像下面这样:
    口 找出类应该做的事情。
    口 列出实例变量和方法。
    口 编写方法的伪码(稍后说明)。
    口编写方法的测试用程序。
    口 实现类。
    口 测试方法。
    口 除错或重新设计。
    口 邀请辣妹参加庆功派对(没有成功过)

    我们会让每个类写出下列的事物:

    伪码:能帮助你专注于逻辑而不需要顾虑到程序语法

    测试码:测试用的程序代码

    真实码:实际设计出的真正Java程序代码

    5.3 编写伪码

    伪码是介于真正的Java程序与正常英语之间的语言,大致上包括3部分:实例变量的声明、方法的声明和方法的逻辑。其中最重要的是方法的逻辑,因为它会定义出会发生“什么事”

    编写方法的实现部分
    开始编写真正可用的方法程序代码

    在我们开始编写方法之前,让我们先退回一步来写出测试方法用的程序代码。没错,我们会在有东西可以测试前就先写出测试用的部分!
    先编写测试用程序代码的概念来自于极限编程(XP)方法论,这样做会让你能够更容易与更快地写出程序代码。我们并不强制采用极限编程XP,但觉得这个概念真的很不错,并且极限编程XP听起来也很酷。 

    5.4 测试

    为SimpleDotCom编写测试码

    我们需要写出能够创建SimpleDotCom对象并加以测试的程序代码。对SimpleDotCom这个类来说,我们真正在意的只有checkYourselft()方法,然而我们还要实现出setLocationCells()方法以便让checkYourself()方法能够正确地执行。
    先来看下面checkYourself()方法这个方法的伪码(setLocationCells()是个用手肘想也知道的setter,所以我们不用花太多时间去关心,但真正的应用程序会需要更稳固的setter,此时就会需要加以测试)。
    然后自问:如果checkYourself()方法已经写好的话,我要用什么样的测试码才能证明这个方法能够正确地运行?

    应该要测试的部分:
    (1) SimpleDotCom对象的初始化。
    (2)赋值位置(带有3个int的数组,像是{2,3,4})。
    (3)创建代表玩家猜设的字符串(“2”或“0”等)
    (4)传入伪造的玩家猜测来叫用checkYourself()方法。
    (5)列出结果以观察是否正确。

    5.5 编写程序

    SimpleDotCom的测试码

    1. public class SimpleDotComTestDrive {
    2. public static void main(String[] args) {
    3. SimpleDotCom dot = new SimpleDotCom();
    4. int[] locations = {2, 3, 4};
    5. dot.setLocationCells(locations);
    6. String userGuess = "2";
    7. String result = dot.checkYourself(userGuess);
    8. String testResult = "failed";
    9. if (result.euquals("hit")) {
    10. testResult = "psssed";
    11. }
    12. System.out.println(testResult);
    13. }
    14. }

    checkYourself()方法

    1. public String checkYourself(String stringGuess) {
    2. int guess = Integer.parseInt(stringGuess);
    3. String result = "miss";
    4. for (int cell : locationCells) {
    5. if (guess == cell) {
    6. result = "hit";
    7. numOfHits++;
    8. break;
    9. }
    10. }
    11. if (numOfHits == locationCells.length) {
    12. result = "kill";
    13. }
    14. System.out.println(result);
    15. return result;
    16. }

    5.6 完成版

    SimpleDotCom与SimpleDotComTester的最终版本

    1. public class SimpleDotComTestDrive {
    2. public static void main(String[] args) {
    3. SimpleDotCom dot = new SimpleDotCom();
    4. int[] locations = {2, 3, 4};
    5. dot.setLocationCells(locations);
    6. String userGuess = "2";
    7. String result = dot.checkYourself(userGuess);
    8. }
    9. }

    SimpleDotComGame类的伪码

    游戏的main()方法

    1. public static void main(String[] args) {
    2. int numOfGuesses = 0;
    3. GameHelper helper = new GameHelper();
    4. SimpleDotCom theDotCom = new SimpleDotCom();
    5. int randomNum = (int) (Math.random() * 5);
    6. int[] locations = {randomNum, randomNum+1, randomNum+2};
    7. theDotCom.setLocationCells(locations);
    8. boolean isAlive = true;
    9. while (isAlive == true) {
    10. String guess = helper.getUserInput("enter a number");
    11. String result = theDotCom.checkYourself(guess);
    12. numOfGuesses++;
    13. if (result.equals("kill")) {
    14. isAlive = false;
    15. System.out.println("You took " + numOfGuesses + " guesses");
    16. }
    17. }
    18. }
    19. }

    5.7 用Math.random()产生随机数

    radom()与getUserInput()

    1.产生随机数

    2.取得玩家输入

    5.8 预先输入好的程序

    最后一个类:GameHelper

    1. public class GameHelper {
    2. public String getUserInput(String prompt) {
    3. String inputLine = null;
    4. System.out.println(prompt + " ");
    5. try {
    6. BufferedReader is = new BufferedReader(
    7. new InputStreamReader(System.in));
    8. inputLine = is.readLine();
    9. if (inputLine.length() == 0) return null;
    10. } catch (IOException e) {
    11. System.out.println("IOException:" + e);
    12. }
    13. return inputLine;
    14. }
    15. }

    5.9 循环

    关于for循环

    基本(非加强版)的for循环

    第一段:初始化

    第二段:boolean测试(true或false)

    第三段:重复表达式 

    基本同C语言

    循环之旅

    前置与后置的递增/递减操作符:++ -- 同C语言

    while循环:同C语言

    加强版的for循环

    从Java 5.0(Tiger)开始,Java语言就有称为加强版的for循环,它能够很容易地逐个
    运行数组或其他集合(collection)的元素。(下一章会讨论其他类型的集合)。这
    是个很好的强化功能,因为这是for循环很常见的用途。我们会在讨论非数组的集合
    时再次看到加强版的for循环。

    上面这行程序以中文来说就是:“对nameArray中的每个元素执行一次”而编译器会这么认为:
    (1)创建名称为name的String变量。
    (2)将nameArray的第一个元素值赋给name。
    (3)执行重复的内容。
    (4)赋值给下一个元素name。
    (5)重复执行至所有元素都被运行为止。

    第一段:声明循环变量

    使用这个部分来声明与初始化用在循环内容的变量。循环过程中此变量所携带的值会有所不同。此变量的类型必须要与数组元素匹配。

    第二段:要运行的集合

    这必须是对数组或其他集合的引用

    5.10 类型转换

    转换primitive主数据类型

    我们在第3章讨论过各种primitive主数据类型的大小,以及小杯子无法装载大杯子的内容物的内容:
    long y = 42;
    int x = y; // 不能通过编译

    long比int大,且编译器无法确定long的内容是否可以截掉。若要强制编译器装,你可以使用cast运算符。
    long y = 42;
    int x = (int) y;
    前置的类型转换会告诉编译器要将y的值裁剪成int的大小来赋值给x,但这个值可能会很诡异(见附录B):
    long y = 40002;
    short x=(short) y;// x的值会是-25534!

    重点是这样可以通过编译程序。假如说你要取浮点数的整数值:
    float f = 3.14f;
    int x = (int) f; // x的值会是3 
     

    5.11 用Integer.parseInt()转换字符串

    若要解决这类问题,我们必须要把String的“2”转换成int的2。Java内置有Integer这个类,它有一个方法能够将String所表示的数字转换成实际的数目

  • 相关阅读:
    【c++】list详细讲解
    ubuntu 22.10安装vmware虚拟机报错Before you can run VMware解决方法
    自动化测试工具之Selenium IDE录制教程
    2022年湖北七大员发证单位是哪里?甘建二告诉你
    oracle数据库导出数据为csv包含clob数据
    5.23 BCC工具之drsnoop.py解读
    Vue + Element 表格拖拽排序、树形表格拖拽排序
    基于springboot实现应急救援物资管理系统项目【项目源码】计算机毕业设计
    Ansys Zemax | 大功率激光系统的STOP分析2:如何进行光机械设计准备
    GLTF编辑器:在线模型材质编辑工具
  • 原文地址:https://blog.csdn.net/weixin_64800741/article/details/133753357