鱼C论坛

 找回密码
 立即注册
查看: 1378|回复: 1

[学习笔记] 第37讲中的思考

[复制链接]
发表于 2020-3-5 02:15:24 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
       问题来源于python课后作业的  第037讲:类和对象:面向对象
还是再上一下图(文章最下方):

题中给的指示是:“当乌龟和鱼坐标重叠,乌龟吃掉鱼,乌龟体力增加20
这样我们就可以理解为,不论任何时候,只要乌龟和鱼碰面,就会发生鱼被吃掉这种情况

大家做过这个题的相信已经看过答案了,我就不再把全部的代码放上,只放部分答案了:
turtle = Turtle()
fish = []
for i in range(10):
    new_fish = Fish()
    fish.append(new_fish)

while True:
    if not len(fish):
        print("鱼儿都吃完了,游戏结束!")
        break
    if not turtle.power:
        print("乌龟体力耗尽,挂掉了!")
        break

    pos = turtle.move()
    # 在迭代器中删除列表元素是非常危险的,经常会出现意想不到的问题,因为迭代器是直接引用列表的数据进行引用
    # 这里我们把列表拷贝给迭代器,然后对原列表进行删除操作就不会有问题了^_^
    for each_fish in fish[:]:
        if each_fish.move() == pos:
            # 鱼儿被吃掉了
            turtle.eat()
            fish.remove(each_fish)
            print("有一条鱼儿被吃掉了...")


       首先,我要说的是,“# 在迭代器中删除列表元素是非常危险的,经常会出现意想不到的问题,因为迭代器是直接引用列表的数据进行引用,# 这里我们把列表拷贝给迭代器,然后对原列表进行删除操作就不会有问题了^_^”,这两句话是宝藏,还有这个处理的方法:for each_fish in fish[:]:,一定要拿小本本记下来。

       回到正题,我想说这段标准答案的代码实际上是有个漏洞在里面:

           我们先跟着代码的顺序理一下思路,生成实例对象turtle之后,用for循环生成10个Fish类的实例对象,存放在列表fish中。while循环中先判断了跳出条件,紧接着“ pos = turtle.move()”,小乌龟迈出了它的第一步,再进入for循环中,小鱼儿们也开始move,判断如果坐标重合,就被吃掉,这看起来没有什么问题。但是我突然就想到一个问题,万一小鱼儿落地成盒怎么办??小鱼儿和乌龟的生成位置都是随机的,十条小鱼儿一出生就和刚刚出生的小乌龟碰上也是有可能的!
          想到这里,我们再来看这段代码,实际上已经忽略了这个问题。小鱼儿落地金身,没有被直接吃掉,而是走了一步之后再被看看是不是还这么倒霉。所以,我认为严谨地来讲,确实应该考虑到小鱼儿“落地成盒”的问题(毕竟是吃鸡常有的事=_=)


         我的答案是在看标准答案之前写的,所以考虑进了这一点,也顺利的解决了,代码奉上:
import random as r 
legal_x = [0, 10]
legal_y = [0, 10]

class Turtle():
    def __init__(self):
        self.hp = 100                                              #乌龟的生命值
        self.x = r.randint(legal_x[0], legal_x[1])      #随机初始位置
        self.y = r.randint(legal_x[0], legal_x[1])

        
    def move(self):
        self.hp -= 1                                                #乌龟移动消耗体力
        up_down = r.randint(-1, 1)
        left_right = r.randint(-1, 1)
        step = r.randint(1,2)
        self.x += left_right * step                            #上下左右移动
        self.y += up_down * step
                                                    
        if self.x < legal_x[0]:                                     #判断是否越界
            self.x = -self.x
        if self.x > legal_x[1]:
            self.x = 2*legal_x[1] - self.x

        if self.y < legal_y[0]:
            self.y = -self.y
        if self.y > legal_y[1]:
            self.y = 2*legal_y[1] - self.y
##        print('我是小乌龟,我现在的位置是',(self.x, self.y))
##        print('='*80)
        return (self.x, self.y)


    def eat(self):                                                      #乌龟进食
        self.hp += 20
        
        if self.hp >= 100:
            self.hp = 100
        print('❤'*30)
        print('hahaha,我吃到鱼了,我现在的体力是【%d】:'%self.hp)
        return self.hp



class Fish():
    def __init__(self):
        self.x = r.randint(legal_x[0], legal_x[1])      #随机初始位置
        self.y = r.randint(legal_x[0], legal_x[1])


    def move(self):
        up_down = r.randint(-1, 1)
        left_right = r.randint(-1, 1)
      
        self.x += left_right                                      #上下左右移动
        self.y += up_down 
                                                    
        if self.x < legal_x[0]:                                     #判断是否越界
            self.x = -self.x
        if self.x > legal_x[1]:
            self.x = 2*legal_x[1] - self.x

        if self.y < legal_y[0]:
            self.y = -self.y
        if self.y > legal_y[1]:
            self.y = 2*legal_y[1] - self.y

##        print('我是小鱼儿,我现在的位置是',(self.x, self.y))
##        print('='*80)
        return (self.x, self.y)
    



turtle = Turtle()                                                   #创造鱼和乌龟
fishes = [] 
for i in range(10):                                      
    fish = Fish()
    
    fishes.append(fish)

while True:
    turtle_site = (turtle.x, turtle.y)                          #乌龟的位置
    fishes_site = []                                                #鱼群的位置
    
    for each in fishes:                                             #更新鱼群位置
        fishes_site.append((each.x, each.y))

    times = fishes_site.count(turtle_site)              #搜集一次吃掉几条鱼
    if times > 0:
        for i in range(times):
            kill = fishes_site.index(turtle_site)
            fishes_site.pop(kill)                                   #鱼被吃掉后,更新对象列表和鱼群位置
            fishes.pop(kill)

            turtle.hp = turtle.eat()
            print('现在还有【%d】条小鱼儿,我要把它们都吃光!'%len(fishes))
    
    turtle.move()
    for each in fishes:
        each.move()

    if turtle.hp <= 0:
        print('-'*80)
        print('小乌龟被累死了!')
        print('游戏结束!')
        break

    if len(fishes) == 0:
        print('-'*80)
        print('小乌龟把鱼都吃光了!')
        print('游戏结束!')
        break

       在我的代码中,我用了两个列表,一个(fishes)存放Fish类的实例对象,另一个(fishes_site)存放每一个实例对象的x,y坐标组成的元组,当然他们的索引值也是一一对应,便于操作。我考虑到,万一小乌龟中大奖了,十条小鱼同时落地成盒,那岂不是美哉!所以先用了count()方法,判断一次能吃到几条鱼,然后以这个次数(times),当做for循环的条件。我的判断是否能吃掉鱼放在了小乌龟和小鱼儿move之前,所以如果落地成盒发生,则第一时间就能发现并且执行。但这样做同样我也用了比较笨的方法,用index()方法找到被吃的那条小鱼,然后用这个下标在两个列表中都把它删除。如果大佬们能更简单地解决,请在下面留言,我将非常欢迎!

      最后,我想问问大家,为什么我用自己的代码和答案跑了好多次,一直都是小乌龟被累死,这也太惨了,不知道你们是不是和我一样的情况。最后欢迎大家和我交流,如果哪位鱼油能指出我的代码的纰漏或者不足,我将万分感谢!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-11-13 16:58:00 | 显示全部楼层
我也是一直累死,都是不超过五次
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-10 21:41

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表