面向对象设计应用——发牌游戏

北慕城南 提交于 2020-03-03 16:47:02

开发工具:Visual studio Code

1.游戏介绍

四名牌手打牌,电脑随机將52张牌(不合大、小王)发给四名牌手,并在屏幕上显示每位牌手的牌。

2.面向对象程序设计

定义和使用类

类定义

创建类时,用变量形式表示的对象属性称为数据成员或属性(成员变量),用函数形式表示的对象行为称为成员函数(成员方法),成员属性和成员方法统称为类的成员。

对象定义

对象是类的实例。如果人类是一个类的话,那么某个具体的人就是一个对象。只有定义了具体的对象,才可通过“对象名。成员”的方式来访问其中的数据成员或成员方法。

构造函数

类可以定义一个特殊的称为_init_()的方法(构造函数,以两个下画线“_”开头和结束)。一个类定义了_init_()方法以后,类实例化时就会自动为新生成的类实例调用_inil_()方法。构造函数一般用于完成对象数据成员设置初值或进行其他必要的初始化工作。如果未定义构造函数,Python将提供一个默认的构造函数。

析构函数

Python中类的析构函数是_del _,用来释放对象占用的资源,在Python收回对象空间之前自动执行。如果用户未定义析构函数,则Python会提供一个默认的析构函数进行必要的清理工作。

实例属性和类属性

属性(成员变量)有两种,一种是实例属性,另一种是类属性(类变量)。实例属性是在构造函数_ init_(以两个下画线“_”开头和结束)中定义的,定义时以self作为前缀;类属性是在类中方法之外定义的属性。在主程序中(在类的外部),实例属性属于实例(对象)只能通过对象名访问;类属性属于类,可通过类名进行访问,也可以通过对象名进行访问,为类的所有实例共享。

私有成员与公有成员

Python并没有对私有成员提供严格的访问保护机制。在定义类的属性时,如果属性名以两个下画线“_”开头,则表示其是私有属性,否则是公有属性。私有属性在类的外部不能直接访问,需要通过调用对象的公有成员方法来访问,或者通过Python支持的特殊方式来访问。Python提供了访问私有属性的特殊方式,可用于程序的测试和调试,对成员方法也具有同样的性质。方法如下:

对象名.类名+私有成员

私有属性是为了数据封装和保密而设置的属性,一般只能在类的成员方法(类的内部)中使用访问。虽然Python支持用户以一种特殊的方式从外部直接访问类的私有成员,但是并不推荐使用这种方法。公有属性是可以公开使用的,既可以在类的内部进行访问,也可以在外部程序中使用。

方法

在类中进行定义的方法可以分为三大类:公有方法、私有方法和静态方法。其中,公有方法、私有方法都属于对象,私有方法的名字以两个下画线“—”开始,每个对象都有自己的公有方法和私有方法,在这两类方法中可以访问属于类和对象的成员;公有方法通过对象名直接调用,私有方法不能通过对象名直接调用,只能在属于对象的方法中通过“self’调用或在外部通过Python支持的特殊方式来调用。如果通过类名来调用属于对象的公有方法,则需要显式地为该方法的“self"’参数传递一个对象名,用来明确指定访问哪个对象的数据成员。静态方法可以通过类名和对象名调用,但不能直接访问属于对象的成员,只能访问属于类的成员。

类的继承

继承是为代码复用和设计复用而设计的,是面向对象程序设计的重要特性之一。当我们设计一个新类时,如果可以继承一个已有的、设计良好的类,然后进行二次开发,无疑会大幅减少开发的工作量。

在继承关系中,已有的、设计好的类称为父类或基类,新设计的类称为子类或派生类。派生类可以继承父类的公有成员,但是不能继承其私有成员。

类继承语法:

class派生类名(基类名):  基类名写在括号里

派生类成员

在Python中,继承的一些特点如下。继承中,基类的构造函数(_init._()方法)不会被自动调用,它需要在其派生类的构造中专门调用。

如果需要在派生类中调用基类的方法时,可通过“基类名.方法名()”的方式来实现,需要加上基类的类名前缀,且需要带上self参数变量,区别于在类中调用普通函实现,需要加上基类的类名前缀,且需要带上self参数,也可以使用内置函数super()实现。

Python总是首先查找对应类型的方法,如果不能在派生类中找到对应的方法,它才会到基类中逐个查找(先在本类中查找调用的方法,找不到才去基类中找)。

方法重写必须出现在继承中。它是指当派生类继表了基类的方法之后,如果基类方法的功能不能满足需求,则需要对基类中的某些方法进行修改。可以在派生类重写基类的方法。

3.程序设计步骤

设计类

发牌程序设计出三个类: Card类、Hand类和Poke类。

Card类

Card类代表一张牌,其中,FaceNum字段指的是牌面数字1~13,Suit字段指的是花色,”梅”为梅花,”方”为方块,”红”为红桃,”黑”为黑桃。

其中:Card构造函数根据参数初始化封装的成员变量,实现牌面大小和花色的初始化,以及是否显示牌面,默认True为显示牌正面;_str_()方法用来输出牌面大小和花色;pic_order()方法获取牌的顺序号,牌面按梅花1~13,方块14- 26,红桃27-39,黑桃40- 52顺序编号(未洗牌之前),也就是说,梅花2顺序号为2,方块A顺序号为14,方块K顺序号为26(这个方法为图形化显示牌面预留的方法); flip()是翻牌方法,改变牌面是否显示的属性值。

Hand类

Hand类代表手牌(一个玩家手里拿的牌),可以认为是一位牌手手里的牌,其中,cards列表变量存储牌手手中的牌。可以增加牌、清空手里的牌、把一张牌给别的牌手等操作。

Poke类

Poke类代表一副牌,我们可以将一副牌看作是有52张牌的牌手,所以继承Hand类。由于其中cards列表变量要存储52张牌,而且要进行发牌、洗牌操作,所以增加如下的方法。

populate(self)生成存储了52张牌的一副牌,当然这些牌是按梅花1~13,方块14-  26,红桃27~39,黑桃40- 52的顺序(未洗牌之前)存储在cards列表变量。 shuffle(self)洗牌,使用Python的random模块shuffle()方法打乱牌的存储顺序即可。deal( self., hands,per_hand=13)可完成发牌动作,发给四个牌人默认13张牌。当然,若令per_hand=10,则给每个牌手发1 0张牌,只不过最后仍有牌没发完。

主程序

主程序比较简单,因为有四个牌手,所以生成players列表存储初始化的四位牌手。生成一副牌的对象实例poke1,调用populate()方法生成有52张牌的一副牌,调用huffle()方法洗牌打乱顺序,调用deal(players,13)方法分别给每位玩家发13张牌,最后示四位牌手所有的牌。

4.参考代码

5.运行结果

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!