一、增加程序逻辑的复杂性

  上一次课我们把一个21点扑克牌游戏的核心算法进行了实现,但是现在看来功能太简单了,我们可以把算法的逻辑复杂一些。我们增加这样的需求:

  1. 模拟发牌的过程,就像牌是洗过的一样。
  2. 玩家可以多次叫牌。
  3. 完善判断输赢逻辑,不仅是两家比大小,还要不能大于21点。
  4. 丰富输出信息,把玩家最后点数进行显示。

  为了实现以上需求,我们把原来代码的界面显示之前的部分进行修改。我们把原来的代码删掉,再敲如下的代码:

int a = 0; // 玩家的牌    int b = 15; // 电脑的牌        do{        a += (int)(Math.random() * 13 + 1);   // 使用随机函数模拟发牌    }while (a <= b);    // 简单叫牌逻辑,只要比电脑小就叫牌        String text = "你手里的牌是:" + a            + ",对家手里的牌是:" + b;    if(a > b && a <= 21){   // 赢的要求是玩家牌比电脑大并且不大于21点        text += "。你赢了!";    }else{        text += "。你输了!";    }

  这段代码把前面的需求就基本实现了,我们运行一下看看效果。

  我们看一下上面写的这段代码。前面的两个变量声明我们都知道了。接下来我们用到了一个do...while循环,前面说到3大语句就剩循环没讲,这里接触了。大括号括起来的代码块里用的Math.random是Java提供的一个工具,调用它可以产生一个随机数,数值范围是大于等于0小于1的,因为扑克牌除去大小猫之外最大的点数是13,也就是K,我们用随机数乘以13再加上1就能得到1到13中的一个数。这里用到了一个“类型转换”,因为随机数本身是浮点数进行运算后得出的依然是浮点数,而牌的点数肯定是整数,我们就需要把浮点数强制转换成整数。转换的方式是直接舍掉小数部分而不是四舍五入。叫牌逻辑现在为了实现的简单,就是只有小于给定的点数15就一直叫牌。这里同学们可以想到,如果手里的牌小于15,叫牌的动作就会反复进行,用术语的话,就叫做进入循环之中。

二、Java语言基础(二 )

1. 循环语句

  同学们,我们在上次课里知道了编程语言里有3大语句:赋值、选择与循环。这里就对循环语句进行一个介绍。每当代码需要多次重复时,就要用到循环语句。循环语句有3种形式:do...while循环、while循环和for循环。前两个形式很相似,我们在前面代码里用的就是do...while循环,我们再看一次这个代码。

do{        a += (int)(Math.random() * 13 + 1);   // 使用随机函数模拟发牌    }while (a <= b);    // 简单叫牌逻辑,只要比电脑小就叫牌

  这里 do 之后用大括号括起来的是循环体,这个循环体会先被执行一遍,执行的过程中对变量 a 的值进行了改变。循环体执行完了之后在while后比较运算对 a 的值进行判断,如果为true,则再次执行循环体,如果为false,则退出循环。while循环与之类似,上面一段代码改用while循环,则变成以下的样子:

a += (int)(Math.random() * 13 + 1);   // 使用随机函数模拟发牌    while( a <= b){        a += (int)(Math.random() * 13 + 1);   // 使用随机函数模拟发牌    }

  因为while循环是先判断再决定是否循环,所以我们在这里需要在前面先执行一遍。在这种情况下,自然用do...while循环比用while循环更简洁。【同学们在使用循环语句的时候一定要记住,在循环体里对要判断的变量进行值的改变,这样经过一定次数的重复之后,判断条件会变成false。否则一直是true的话,就是一直循环下去,程序就卡住不动了,俗称“爽死了”,也就是大家经常说的“死循环”。其实大家发现没有,随着计算机对社会的影响越来越大,很多行业术语也进入了人们的生活,被发展出很多的引申含义,像刚才说的“死循环”,还有内存、死机、重启、卸载、迭代,还有386、486啊。大家可以留心一下生活中出现的计算机术语,也可以讨论一下。】

  for循环与while循环类似,也是先进行条件的判断再决定是否进行循环,但for循环的条件判断部分要丰富很多,分为三个部分,包括循环判断变量的声明与初始化、循环条件判断、循环判断变量的改变。可参考如下示例:

for(int i = 0; i < 10; i++){    // Do something    }

  可以看到for后面的括号里用分号分开的3个部分,先是声明了一个整数变量 i ,将其初始化为0,执行循环的条件是满足 i < 10 的情况下,最后是在执行完循环体代码后,i 变量自增 1 再进行下一次比较。将它改写成while循环,则是如下形式:

int i = 0;    while(i < 10){        // Do something                i++;    }

  可以看到for循环要简洁得多,其实for循环可以理解成对while循环某种常用模式的简记法。大家也可以看到for循环特别方便实现指定次数的循环,像上面的代码就是执行10次循环。for循环的条件判断部分可以包含不止一个循环判断变量,比如下面这段代码:

for(int i = 0, int j = 10; i < j; i++, j--){        // Do something    }

  这段代码的循环判断部分就声明了两个变量,一个自增一个自减,当自增的变量等于或大于自减的变量时循环就会停止。要提醒同学们的是,在判断条件部分声明的变量,在循环体里是可以使用的。

  循环语句的3种形式有很多灵活的使用方法,这里就不一一列举了,有兴趣的同学可以自己找找相关资料拓展一下。

  在循环语句的循环体中可以使用两条特殊的语句改变循环的执行,那就是continue和break。break前面讲switch语句的时候我们接触过,switch的每个分支的最后加上break语句就会跳出switch语句的代码块,不再执行其后的剩余代码。在循环语句中使用break语句作用类似,会跳出整个循环语句的代码块,即使条件是符合的也不再进行循环。而continue语句则不同,它同样不会继续执行其后的代码,但是它会跳转到判断部分,如果符合循环条件则会进行下一次循环。break和coninue的使用可以大大丰富循环执行过程的能力,大家可以自己找找相关案例。这里只给大家提一下。

【大家一定要记住学编程不需要提前储备太多的理论知识,先把基本的知识点留个印象。最重要的是跟着多敲代码,如果课程里给的示例没理解就反复删掉多来几次。这就是个熟能生巧的事!】

2. 类型转换

  我们接着看循环体里的语句,我们把用random产生的随机数进行了强制类型转换,把它从浮点数转换成整数,这是因为random产生的数是浮点数。我们查一下JDK说明(https://docs.oracle.com/javase/8/docs/api/):


Android 循环请求数据过多 androidstudio循环语句_字符串


可以看到这里产生的是一个double类型的浮点数,而这个浮点数虽然后面与整数相乘相加,却不会自动变为整数,而是整数自动转换成浮点数再进行运算。在基本类型中整型、浮点型、字符型数据可以混合运算。运算中,不同类型的数据先转变为同一类型,然后进行运算,转换从低级到高级,这就是自动类型转换。Java语言基本类型自动类型转换从低到高的排序为:

低----------------------------------------------------------->高

byte, short, char --> int --> long --> float --> double

  大家可以看到浮点数在类型转换中的等级比整数要高。自动类型转换在代码上不需要体现出来,因为是编译系统自动进行的。但是如果要把高等级类型转换成低等级类型,比如我们代码中用到的将double类一型的结果赋给int类型的变量,就要在代码上体现出来了。写法就是前面加上括号括起来的要转换成的类型,这里是用(int)。在Android Studio中对强制类型转换现在做了兼容的处理,不再给出提示要求进行强制转换了,但是我们要还知道低级类型与高级类型的区别。

  类型转换还有一种重要的作用是用于“类”的类型转换,这种用法实现了所谓的“多态”性,我们现在不讲留到后面讲类的时候再讲解。

3. 字符串

  我们继续往下看代码。

String text = "你手里的牌是:" + a + ",对家手里的牌是:" + b;

这里的text是声明的一个字符串变量。前面在基本数据类型里,我们学习了字符类型,但是一个字符类型变量只能保存一个字符,如果要存储一句完整的话,就要用到字符串。同学们可以看到字符串是用双引号括起来的,这与字符类型的单引号是不同的。而且字符串可以 + 号把多个字符串连接起来成为一个字符串。而在我们这条语句里,细心的同学可能发现了a, b都是整数型变量,它也可以与字符串相连。这是因为在编译的时候,系统会自动将数字转成对应的字符表达形式。这里再多说一句,字符串类型看起来和基本数据类型的用法是一样的,像这里将整数型变量与字符串用 + 号连起来,看起来就像是一个混合类型运算的自动类型转换,其实底层的机制是完全不一样的,这是为了使用方便而提供的简写法。String实际上在Java中是以“类”的方式实现的,整数变量变成字符地串也是底层调用了对应的整型类的方法。关于类的知识我们会在后面讲解。

  在使用字符类型与字符串类型时有一个知识点大家要注意,就是转义符。因为我们使用单引号或双引号来括起字符,那么字符的值正好是单引号或者双引号该如何分别呢?这就是转义符的用处了。在Java语言中的转义符是“”反斜杠,转义符常用的有以下几种:

''' 用于char类型中表示单引号

""" 用于String类型中表示双引号

用于表示斜杠

用于表示换行

还有一些转义符的用法是表示退格、跳格、换页等的控件符和制表符的,这对于现在的编程来说已经没有什么实际意义了,有更方便的方法来规定字符串的格式。还有通过转义符加八进制、十六进制数来表示特殊字符的,实际中也很少用到。这里就不做介绍了。

【有的同学会有个疑问,怎么区分正斜杠和反斜杠啊?这里告诉大家一个小技巧:就是在键盘上,你的右手指容易够着的那个是正斜杠,它跟?号在一起。费点劲才能够着的是反斜杠,它在回车键的上面,跟竖杠在一起。大家看到这个竖杠想起了什么吧?对,就是布尔逻辑运算符的“或”。或是用的两条竖杠,那么一条竖杠是什么呢?它也是一个运算符,叫“按位或”,属于位运算符,是对变量的位即bit进行运算的。同样的一个连接符&,叫“按位与”。位运算大家接触到的可能性不大,我们就先不讲了。还有一种区分方法就是,Java里注释用的是正斜杠,转义符用的是反斜杠。】

4. 运算符优先级

if(a > b && a <= 21){   // 赢的要求是玩家牌比电脑大并且不大于21点        text += "。你赢了!";    }else{        text += "。你输了!";    }

  这段代码里的if语句的条件判断部分 a > b && a <= 21 显得比较复杂,其实把它加上括号就好理解了。(a >b) && (a <= 21)。就是判断a小于b与a小于等于21是否同时成立。为了省事就可以把括号简略,同学们练得多了也就会习惯了。这里其实有一个运算符优先级的原则,这个概念就是从数学里扩展来的,同学们应该还记得在算式里乘除法的优先级是高于加减法,而且为了避免混乱就可以加括号,Java里也是一样的,只是编程语言里的运算符更丰富。Java语言所有运算符优先级按序排列如下所示:

1) . , [] , () 9)&

2) ++ , -- , ! , ~ , instanceof 10)^

3) new (type) 11) |

4) * , / , % 12)&&

5) + , - 13)||

6) >> , >>> , << 14)?:

7) > , < , >= , <= 15)= , += , -= , *= , /= , %= , ^=

8) == , != 16)&= , |= , <<= , >>= , >>>=

  这里有很多运算符我们还没有学到,这没有关系后面陆续都会接触。同学们也不用刻意去记这个表,我们又不考试,用多了自然就熟了。而且实际编程中要考虑优先级的情况并不多,遇到了不记得我们可以现场查资料,实在不行我们还可以加括号啊!