zoukankan      html  css  js  c++  java
  • IIPP迷你项目(一)“Rock-paper-scissor-lizard-Spock”

    0 前言——关于IIPP

    本系列博客的内容均来自《An Introduction to Interactive Programming in Python (Part 1)》(在此我简称为“IIPP”)。

    这是Coursera上的一门课程,以做游戏为导向讲解python交互式编程,非常有意思。它总共有8周的课程,每周都会有一个迷你项目(mini-project),由易到难,不过即使是容易完成的内容也能在某一个小点引人思考——比方说第一周的内容仅仅是猜拳,但老师所提出的关于“模数”的想法是异常精妙的,如果没有这方面的提示当然也是可以用一种傻瓜式编程编写出来,但是将列写出全部5*5=25种可能性(程序显得憨憨傻傻),然而一旦引入了“模数”的概念,则会将程序简化又简化,会让人由衷地感慨:“这就是数学之美!”

    因此我将把每一次的作业编写结果都用博客的方式记录下来,并且与此同时也整理一下我从这一次作业中得到了什么。

    1 作业内容

    本周的作业内容是基于“剪刀石头布”的一种扩展,在“剪刀”“石头”“布”这三张牌的基础上又增加了两种牌——“蜥蜴”和“斯波克”(虽然我并不知道斯波克是什么东西……),于是由原先的剪刀石头布“一物降一物”变成了“两物降两物”,什么意思呢?我拿一张图进行解释:

     如图,箭头的两端连接的是克制者与被克制者,被箭头指的是被克制的那一方。比如绿色的球与红色的球,通过查看箭头指向,可以发现是绿色克制红色。

    国产的游戏里经常出现五行相生相克这种东西(当然还有一些游戏基于五行相生相克搞出来更复杂的相生相克关系,比如《赛尔号》),所以我觉得这样理解起来不难吧?画上面那图的时候我还用的是五行中的五种颜色呢~

    总而言之,五张牌中任意一张牌,会克制其中两张牌,同时被其中另外两张牌克制,这样很公平。

    2 判断胜出函数compare_player_comp”的实现

    2-1 方法一

    现在题目来了:让玩家出任意一张牌,然后计算机再出一张牌,比较一下看谁赢。是不是感觉简单得不得了?其实最简单的方法就是把全部的可能性都列写出来,也就是共有5*5=25种可能性。

    但是在前言中也说了这种方法有点憨,Joe老师给出一个提示就是:给这五张牌按0~4进行编号,然后比较大小。编号是这样的:

    • 0 — rock
    • 1 — Spock
    • 2 — paper
    • 3 — lizard
    • 4 — scissors

    这种方法识别起来很直观,比如0<1,所以Spock赢了rock;0<2,所以paper赢了rock……

    不过要注意,当给定的两个数字的差值大于2开始,就不能这样直白地比较大小了。比如0和3比较,这里0应该转为5(0和5对5的余数都是5,就像时钟里0点=12点一样,0和12对12的余数都是12),是5>3因此是rock胜。同理,0和4比较,因为|0-4|=4>2,所以要把0转为5再进行比较,是5>4所以rock胜出。

    因此当给定两个数的时候,我们必须先搞清楚这两个数的差值是否大于2。分为以下三种情况:

    (1)-2≤num1-num2≤2:直接令num1与num2进行比较,谁大谁赢;

    (2)num1-num2<-2:让num1加5,然后再与num2比较,谁大谁赢;

    (3)num1-num2>2:让num1减5,然后再与num2比较,谁大谁赢。

    写成代码就是这样的:

     1 def compare_player_comp_m1(player_number,comp_number):
     2     diff = player_number - comp_number
     3     if (diff>2):
     4         player_number -= 5
     5     elif (diff<-2):
     6         player_number += 5
     7     if player_number>comp_number:
     8         winner="player"
     9     elif player_number<comp_number:
    10         winner="computer"
    11     else:
    12         winner="nobody"
    13     print winner + " wins!"

    其中传递进来的两个参数分别为“玩家出的牌对应的数字”和“计算机出的牌对应的数字”。

    2-2 方法二

    这种方法不得不承认我一开始是没有想到的,它是在课程的《Code Clinic Tips》页面下给出的一个提示。

    如图所示,是将这全部5*5=25种情况列些出来的一个表格,表格中每个单元格的左上角是“player_number - comp_number”的差值,而右下角则是该差值对5取模所得。

    通过这样一个表格,我们可以很直观地观察到当右下角的值为1或2时,是玩家胜出(蓝色字体标明是玩家胜出),当右下角的值为3或4时,是计算机胜出(红色字体标明是计算机胜出),右下角的值为0时,没有人胜出(黄色字体标明打平手)。

    这样一来程序就更好写了:

     1 def compare_player_comp_m2(player_number,comp_number):
     2     diff = player_number - comp_number
     3     diff_module = diff % 5
     4     if (diff_module==1) or (diff_module==2):
     5         winner="player"
     6     elif (diff_module==3) or (diff_module==4):
     7         winner="computer"
     8     else:
     9         winner="nobody"
    10     print winner + " wins!"

    3 其余helper函数以及主函数的实现

    1、本程序的helper函数有以下三个:

    (1)name_to_number(name):将牌名转为对应的数字0~4。

     1 def name_to_number(name):
     2     number=-1 #init
     3     if name=="rock": #convert
     4         number=0
     5     elif name=="Spock":
     6         number=1
     7     elif name=="paper":
     8         number=2
     9     elif name=="lizard":
    10         number=3
    11     elif name=="scissors":
    12         number=4
    13     if number==-1: #return
    14         err="no choice named "+ """ +name + ""."
    15         return err
    16     else:
    17         return number

    (2)number_to_name(number):将数字转为对应的牌名“rock”~“scissors”。

     1 def number_to_name(number):
     2     name="none" #init
     3     if number==0: #convert
     4         name="rock"
     5     elif number==1:
     6         name="Spock"
     7     elif number==2:
     8         name="paper"
     9     elif number==3:
    10         name="lizard"
    11     elif number==4:
    12         name="scissors"
    13     if name=="none": #return
    14         err="the number ""+ str(number) + "" is not a valid input."
    15         return err
    16     else:
    17         return name

    (3)compare_player_comp(player_number,comp_number):即上一节中实现的函数,我给出了两种实现方法,用m1和m2区分。

    2、主函数rpsls(player_choice):在rpsls函数中,除过完成让电脑出拳这一步之外,它还负责将上面这些helper函数串在一起以实现猜拳功能。

     1 import random    
     2     
     3 def rpsls(player_choice):
     4     print "Player chooses " + player_choice # rpsls part1
     5     player_number=name_to_number(player_choice)
     6     if str(player_number).isdigit()==True: #只有player_number是数字,才能说明输入无误,方可往下继续走
     7         comp_number= random.randrange(0,5,1) # rpsls part2
     8         comp_choice=number_to_name(comp_number)
     9         print "Computer chooses " + comp_choice
    10         compare_player_comp_m2(player_number,comp_number) #rpsls part3
    11         print " "
    12     else:
    13         print player_number

    4 全部程序清单

     1 ### helper function ###
     2 def name_to_number(name):
     3     number=-1 #init
     4     if name=="rock": #convert
     5         number=0
     6     elif name=="Spock":
     7         number=1
     8     elif name=="paper":
     9         number=2
    10     elif name=="lizard":
    11         number=3
    12     elif name=="scissors":
    13         number=4
    14     if number==-1: #return
    15         err="no choice named "+ """ +name + ""."
    16         return err
    17     else:
    18         return number
    19     
    20 def number_to_name(number):
    21     name="none" #init
    22     if number==0: #convert
    23         name="rock"
    24     elif number==1:
    25         name="Spock"
    26     elif number==2:
    27         name="paper"
    28     elif number==3:
    29         name="lizard"
    30     elif number==4:
    31         name="scissors"
    32     if name=="none": #return
    33         err="the number ""+ str(number) + "" is not a valid input."
    34         return err
    35     else:
    36         return name
    37     
    38 def compare_player_comp_m1(player_number,comp_number):
    39     diff = player_number - comp_number
    40     if (diff>2):
    41         player_number -= 5
    42     elif (diff<-2):
    43         player_number += 5
    44     if player_number>comp_number:
    45         winner="player"
    46     elif player_number<comp_number:
    47         winner="computer"
    48     else:
    49         winner="nobody"
    50     print winner + " wins!"
    51         
    52 def compare_player_comp_m2(player_number,comp_number):
    53     diff = player_number - comp_number
    54     diff_module = diff % 5
    55     if (diff_module==1) or (diff_module==2):
    56         winner="player"
    57     elif (diff_module==3) or (diff_module==4):
    58         winner="computer"
    59     else:
    60         winner="nobody"
    61     print winner + " wins!"
    62     
    63 ### main function ###
    64 import random    
    65     
    66 def rpsls(player_choice):
    67     print "Player chooses " + player_choice # rpsls part1
    68     player_number=name_to_number(player_choice)
    69     if str(player_number).isdigit()==True: #只有player_number是数字,才能说明输入无误,方可往下继续走
    70         comp_number= random.randrange(0,5,1) # rpsls part2
    71         comp_choice=number_to_name(comp_number)
    72         print "Computer chooses " + comp_choice
    73         compare_player_comp_m2(player_number,comp_number) #rpsls part3
    74         print " "
    75     else:
    76         print player_number
    77     
    78 ### display ###
    79 rpsls("rock")

    2016.5.29

    by 悠望南山

  • 相关阅读:
    面试题总结
    h5c3新特性
    redis常用命令大全
    windows下挂载linux的nfs网络硬盘
    mysql之char、varchar、text对比
    Lua与C的交互
    通信模型socket
    程序编译流程
    区块链共识机制(POW、POS、DPOS等)的优缺点
    .net c#获取自定义Attribute
  • 原文地址:https://www.cnblogs.com/NanShan2016/p/5539164.html
Copyright © 2011-2022 走看看