敬初学者Python基础学完了,该怎么知道自己学的怎么样呢?十个经典实战小项目附源码

Posted 鬼鬼Kimi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了敬初学者Python基础学完了,该怎么知道自己学的怎么样呢?十个经典实战小项目附源码相关的知识,希望对你有一定的参考价值。

前言

初学者要想成功,一句话,大量的实操,大量的练,乍一看我的这个答案似乎有点敷衍,但是这确实是我接触Python以来,总结出的最有价值的经验,接下来分享我自己初学时用来练手的经典实战小项目,适合初学者敲的代码。

1.街霸游戏

1.1 KO街霸

游戏小剧场
特别调查员春丽突然收到了来自中尉查理的一封邮件,邮件里详细地说明了神月家族在美国唐人街举办的街霸挑战赛,挑战的终极boss正是街霸维加。春丽在很小的时候,父亲就被维加残忍地杀害,为报父仇,春丽毅然决然地买好了飞往唐人街的机票。

邪恶的维加正通过催眠术,控制着在擂台上饮败的格斗家们在世界各地执行暗杀计划。

隆远在印度修行,孤身一人的春丽能在擂台上挑战成功吗?

程序完整源码

这是一个针对Python初学者的练手小程序,简单地模拟春丽与维加的格斗过程。有一定开发经验的朋友可以对程序进行扩展,比如利用多进程来模拟春丽同时与多人进行格斗。

Python

# 导入random模块,执行random模块中的choice方法来随机获取列表中的元素
import random
import time


VEGA_STRATEGIES = ["原地蹲防", "失误", "回旋攻击", "失误", "伤害修正", "回血", "超必杀"]
CHUNLI_KUNFU = ["气功拳", "旋转踢", "百裂脚", "霸山天升脚"]


def countdown(seconds=3, message=""):
    """
    :param seconds: 倒数的秒数
    :param message:  倒计时结束后输出的提示信息
    :return:
    """
    for _ in range(seconds, 0, -1):
        _, _ = print(_), time.sleep(1)
    else:
        print(message)
        
        
def  generate_prompts(kunfu):
    """
    :param kunfu: 街霸格斗选手的格斗招数,为一个列表对象,例如["气功拳", "旋转踢"]
    :return: 返回用户指令输入的提示信息,为一个字符串对象
    """
    prompts = "\\n"
    for index, value in enumerate(kunfu):
        prompts += "<{}>{}".format(index, value)
    prompts += "\\n输入<>中的指令来挑战街霸:__\\b\\b"
    return prompts
    
    
    
def fight():
    # 定义整型变量fighter,用来保存街霸维加的血量
    vega = 100
    # 定义整型变量chunli,用来保存春丽的血量
    chunli = 100
    blood = 5
    prompts = generate_prompts(CHUNLI_KUNFU)
    countdown(message="Fight!")
    # 执行while循环,不断重复执行下面的代码
    while True:
        # 春丽或boss其中一人血量为0时就退出战斗
        if vega * chunli == 0:
            break
        # 执行input函数获得键盘的输入内容
        command = input(prompts)
        # 对输入的字符串类型转换为整型,读者在输入时必须输入有效的数字,否则会抛出异常
        try:
            command = int(command)
            _ = CHUNLI_KUNFU[command]
        except (ValueError, IndexError):
            print("春丽,这是在战斗,请输入正确的战斗指令!")
            continue
        print("春丽对街霸使出了{}".format(CHUNLI_KUNFU[command]))
        # 使用random模块中的choice函数,来随机选择列表里的值
        vega_strategy = random.choice(VEGA_STRATEGIES)
        if vega_strategy == "失误":
            print("街霸维加在对战中反击失误!")
        else:
            print("街霸维加在对战中对你使用了{}".format(vega_strategy))
        if vega_strategy in {"原地蹲防", "回血"}:
            if vega_strategy == "回血" and vega < 100:
                vega += blood
        elif vega_strategy == "失误":
            vega -= blood*2
        elif vega_strategy == "伤害修正":
            vega -= blood
        elif vega_strategy == "超必杀":
            chunli -= blood*2
        else:
            chunli -= blood
        chunli = 0 if chunli  <=0 else chunli
        vega = 0 if vega  <=0 else vega
        
        print("\\n-*- 春丽现在的血量:{}  维加现在的血量:{} -*-".format(chunli, vega))
        time.sleep(3)
    if chunli == 0:
        print("春丽,你战败了!")
    else:
        print("维加,我今天终于把你打败,父亲泉下有知,可以瞑目了!")
        
        
        
if __name__ == "__main__":
    fight()

程序的输出界面

1.2 春丽VS巴洛克


游戏小剧场
虽然美丽的春丽打败了维加,但邪恶的影罗组织并未就此覆灭。许多年以后,春丽站在A号街区,会突然想起打败神月卡琳后的那个下午。当时,身躯高大的巴洛克已将面具摘下,道场中的其他四名影子杀手,形如雕塑,酷似木偶…春丽经过这场残酷的战斗以后,在背部留下了一道很长的月牙形伤痕。

在本节程序实战中,通过多进程的方式来模拟春丽一人对抗影罗组织的五名邪恶杀手。

参考源码

通过多进程+队列来模拟春丽1VS5的街霸游戏挑战赛:

from multiprocessing import Process, Queue
import random



class Fighter:
    def __init__(self, name, blood = 100, justice = True, kungfu = None, enemies = 1):
        """
        :param name:  表示该fighter的姓名
        :param blood: 表示该fighter的血量
        :param justice: 布尔类型,表示该fighter是否代表正义的一方
        :param kungfu: 表示该fighter的格斗技能
        :param enemies: 表示该fighter对抗的敌人数
        """
        self.__name = name
        self.__blood = blood
        self.__justice = justice
        self.__kungfu = kungfu
        self.__enemies = enemies
        
        
        
    def  attack(self):
       kungfu, harm = None, 0
       if self.__blood > 0:
           kungfu = random.choice(list(self.__kungfu.keys()))
           harm = self.__kungfu[kungfu]
       return kungfu, harm
       
       
       
    @property
    def name(self):
        return self.__name
        
        
        
    @property
    def blood(self):
        return self.__blood
        
        
        
    @blood.setter
    def blood(self, value):
        self.__blood = value
        
        
        
    @property
    def enemies(self):
        return self.__enemies
        
        
        
    @enemies.setter
    def enemies(self, count):
        self.__enemies = count
        
        
        
    @property
    def justice(self):
        return self.__justice
        
        
        
def fight(fighter,  justice_attacks, injustice_attacks):
    """
    :param fighter: Fighter对象
    :param justice_attacks: 队列类型,表示春丽的攻击
    :param injustice_attacks: 队列类型,表示巴洛克等杀手的攻击
    :return:
    """
    while True:
        kungfu, harm = fighter.attack()
        attack = {"name": fighter.name, "kungfu": kungfu,
                  "harm": harm, "blood": fighter.blood}
        if fighter.justice:
            # 通过justice_attacks代表的队列,向以巴洛克为首的杀手们发起一个攻击
            justice_attacks.put(attack)
            if fighter.blood == 0:
                break
            # 从justice_attacks代表的消息队列中,接收对方的一个攻击
            attack = injustice_attacks.get()
            # 如果对方攻击时的blood值为0,表示对方已被击败
            if attack["blood"] == 0:
                # 减去敌人数
                fighter.enemies -= 1
                if fighter.enemies == 0:
                    # 敌人已全部被击败, 退出战斗!
                    break
                else:
                    continue
        else:
            # 通过justice_attacks代表的队列,向春丽发起一个攻击
            injustice_attacks.put(attack)
            if fighter.blood == 0:
                break
            # 从justice_attacks队列中接收春丽发起的攻击
            attack = justice_attacks.get()
            # 如果春丽攻击时的血量为0,说明春丽已经被击败
            if attack["blood"] == 0:
               """
               春丽已经战败,通过justice_attacks对列向己方的杀手们进行消息转发,
               同时退出战斗
               """
               justice_attacks.put({"blood": 0})
               break
               
        kungfu, harm = fighter.attack()
        """
        如果在回击的过程中反击的伤害大于对方的伤害值,
        则加上已有的血量值来实现回血的功能,否则将血量减去对应的伤害值
        """
        fighter.blood += harm - attack["harm"]
        if fighter.blood <= 0:
            fighter.blood = 0
        elif fighter.blood > 100:
            fighter.blood = 100
            
    if fighter.blood > 0:
        print("{} 获得了胜利!!!".format(fighter.name))
        
        
        
if __name__ == "__main__":
    # 定义chunli_kungfu来保存春丽的招式及对应的伤害值
    chunli_kungfu = {
        "失误": 0,
        "原地蹲防": 5,
        "龙星落": 10,
        "气功拳": 15,
        "旋转踢": 20,
        "百裂脚": 20,
        "霸山天升脚": 20,
        "超必杀-千翼气功掌": 25
    }
    # 定义baroque_kungfu来保存杀手巴洛克的招式及对应的伤害值
    baroque_kungfu = {
        "失误": 0,
        "伤疤之恨": 15,
        "闪光漩涡": 20,
        "飞翔巴塞罗那": 20,
        "红色冲击": 20
    }
    # 定义来shadow_kungfu保存影子杀手的攻击策略及对应的伤害值
    shadow_kungfu = {
        "失误": 0,
        "暗器": 10,
        "毒药": 15,
        "炸弹": 20
    }
    processes = []
    fighters = [
        Fighter(name="春丽", kungfu=chunli_kungfu, enemies=5),
        Fighter(name="巴洛克", kungfu=baroque_kungfu, justice=False),
        Fighter(name="影子杀手1", kungfu=shadow_kungfu, justice=False),
        Fighter(name="影子杀手2", kungfu=shadow_kungfu, justice=False),
        Fighter(name="影子杀手3", kungfu=shadow_kungfu, justice=False),
        Fighter(name="影子杀手4", kungfu=shadow_kungfu, justice=False)
    ]
    justice_attacks = Queue()
    injustice_attacks = Queue()
    for fighter in fighters:
        process = Process(target=fight, args=(fighter, justice_attacks, injustice_attacks))
        processes.append(process)
        
    [process.start() for process in processes]
    [process.join() for process in processes]

2.猜谜游戏

2.1简单的猜数字游戏

项目要求

实现一个简单的猜数字游戏:程序启动时获取一个随机值,根据用户的输入提示大了还是小了,如果用户输入的整数与随机值相等,则退出循环。

通过random模块randint方法获取一个随机值,通过input函数获取用户的输入。

代码示例:

# 导入random模块
import random
# 获取从1到100000之间的随机数
random_number = random.randint(1, 1000000)
# 执行input方法获取用户的输入,input的返回值为字符串类型,通过int()将其转换为整型
guess_number = int(input("Please enter the number:____\\b\\b\\b\\b"))

参考源码

import time
import random


def get_random_number(start=0, end=10**3):
    return random.randint(start, end)
    

def countdown(seconds=3, message=""):
    """
    :param seconds: 倒数的秒数
    :param message:  倒计时结束后输出的提示信息
    :return:
    """
    for _ in range(seconds, 0, -1):
        _, _ = print(_), time.sleep(1)
    else:
        print(message)
        
    
def serve_forever():
      
    random_number = get_random_number()
    countdown(message="猜数字游戏开始,Go!!!")
    
    while True:
        try:
            guess_number = int(input("请输入你猜的数字:"+"_"*4+"\\b"*4))
        except ValueError:
            print("请输入合法的数字!")
            continue
        if guess_number != random_number:
            _ = print("你输入的数字大了") if guess_number > random_number else print("你输入的数字小了")
            continue
        print("恭喜你猜对了!!!")
        if input("按键盘任意键继续玩猜数字游戏或输入quit退出游戏:____\\b\\b\\b\\b").lower() == "quit":
            break
        else:
            random_number = get_random_number()
    print("游戏已被终止,再见!!!")
    
    
    
if __name__ == "__main__":
    serve_forever()

程序的输出界面


2.2 进阶的猜姓名游戏

项目要求

定义一个人名集合,例如 {“王祖贤”, “李嘉欣”, “李嘉诚”, “刘德华”, “叶倩文”,“叶倩倩”, “王李丹妮”}。如果用户的输入前缀匹配第一个字,则提示"不错,有点接近了",前缀匹配前面两个字,则提示"厉害,比较接近了",完全匹配则提示"哇塞,你是个猜姓名天才,请收下我的膝盖"。

构造该Trie结构的算法逻辑很简单,以第一次构造为例:

将姓名中的第一个字作为键插入到指针指向的空字典中,键值为一个空字典,然后将指针指向键值所对应的空字典,接着将姓名中的第二个字作为键插入到指针指向的空字典中,键值为一个空字典,同样需要将指针指向键值所对应的空字典,不断重复这样的过程,直到遍历完姓名中的所有字符。

简化的代码实例:

name = "王八蛋"
trie = {}
trie[name[0]] =  {}
trie[name[0]][name[1]] =  {}
trie[name[0]][name[1]][name[2]] =  {}

这样在查找用户的输入是否包含某姓名的前缀时,只需要遍历用户输入的字符,然后在构造好的Trie结构中进行查找。

参考源码

import time

def countdown(seconds=3, message=""):
    """
    :param seconds: 倒数的秒数
    :param message:  倒计时结束后输出的提示信息
    :return:
    """
    for _ in range(seconds, 0, -1):
        _, _ = print(_), time.sleep(1)
    else:
        print(message)
        
        
        
def build_lookup_table(data):
    """
    :param data: a set of names, e.g: {"王祖贤", "李嘉欣"}
    :return: lookup table e.g:{'王': {'祖': {'贤': {}}}, '李': {'嘉': {'欣': {}}}}
    """
    lookup_table = {}
    for name in data:
        lookup_table_ = lookup_table
        for char in name:
            if char not in lookup_table_:
                lookup_table_[char] = {}
            lookup_table_ = lookup_table_[char]
    return lookup_table
    
    
    
def guess_name():
    stars = {"王祖贤", "李嘉欣", "李嘉诚", "刘德华", "叶倩文", "叶倩倩", "王李丹妮"}
    # 构造一个查找表
    lookup_table = build_lookup_table(stars)
    countdown(3, "猜姓名游戏开始,Go!!!")
    messages = {0: "不要瞎猜好吗?",  1: "不错,有点接近了",  2: "厉害,比较接近了",
                66: "哇塞,你是个猜姓名天才,请收下我的膝盖"}
    end = 2
    while True:
        name = input("请输入你要猜的姓名:____\\b\\b\\b\\b")
        if name in stars:
            print(messages[66])
            if input("按键盘任意键继续玩猜数字游戏或输入quit退出游戏:____\\b\\b\\b\\b").lower() == "quit":
                break
        else:
            lookup_table_ = lookup_table
            index = 0
            for word in name:
                if word in lookup_table_:
                    lookup_table_ = lookup_table_[word]
                    index = index+1 if index < end else index
                else:
                    break
            print(messages[index])
if __name__ == "__main__":
    guess_name()

程序的输出界面

2.3基于英文分词的猜单词游戏

项目要求

① 对某一篇英文文章进行分词,以获取一个英语词典
② 如果用户输入的单词在词典中,则提示"你是个猜单词天才,请收下我的膝盖"
③ 如果用户的输入前缀匹配第一个字母,则提示"不错,有点接近了",前缀匹配前面两个字母,则提示"厉害,比较接近了"

算法逻辑如下:

① 定义一个布尔类型的标记变量,初始情况下为True,表示已完成单词的拆分
② 遍历英文字符串,如果当前字符为分隔符且尚未切分,则开始分词:将起始位置的索引与分隔符位置之前的所有字符进行拆分

③ 如果当前字符不是分隔符且已拆分,则将标记变量更新为False, 同时更新拆分的起始位置

参考源码

import time

def cut(content, language=0):
    ""

以上是关于敬初学者Python基础学完了,该怎么知道自己学的怎么样呢?十个经典实战小项目附源码的主要内容,如果未能解决你的问题,请参考以下文章

转行零基础该如何学Python?

如何学好java语言啊?

Python该怎么入门?

0基础怎么学习Python?Python学习方法汇总!

为了验证计算机基础学的如何,硬肝了这份测试指南。

转行零基础该如何学Python?