python实战练习

一、图片转字符画

import math

from PIL import Image
import numpy as np

#定义字符映射,从最暗到最亮
chars = '@%#*+=-:.'

def img_to_ascii(image_path,new_width=100):
    #打开图片
    img = Image.open(image_path)
    #计算新的高度(保持图片的纵横比)  由于字符通常比高宽比1:1的像素稍微窄一些,调整高度可以补偿这种比例差异,从而使最终的字符画在视觉上更接近原图。
    aspect_ratio = img.height / img.width
    new_height = int(new_width * aspect_ratio)
    #调整图片大小
    img = img.resize((new_width, new_height))
    #转换为灰度图(将图像转换为灰度图是因为字符画只需要处理图像的亮度信息,而不关心颜色。灰度图将每个像素表示为一个亮度值(从黑到白),简化了图像的数据,使其更容易映射到字符集。这样可以根据像素的亮度选择合适的字符来表示图像的不同区域,实现更清晰的字符画效果。)
    img = img.convert('L')
    #获取像素数据映射到字符
    pixels = np.array(img)  #np.array  可以将不同格式的数据(例如:图像、列表、元组等)转换为numpy数组   在图像处理中通常使用numpy数组来表示图像数据
    #将像素数据映射到字符
    ascii_str = ''
    try:
        for row in pixels:
            for pixel in row:
                # ascii_str += chars[pixel // 25]  # 25是256/10  用于将每个灰度值映射到相应的字符。pixel 是图像中每个像素的灰度值(0到255之间),25 是将灰度值划分成10个字符区间的结果(因为256/10 ≈ 25)。所以 pixel // 25 将灰度值转化为0到9的索引,映射到 chars 字符集中对应的位置,从而生成ASCII艺术。
                ascii_str += chars[min(pixel // 25, len(chars) - 1)]   # 25 是 256/10  保证不超出字符串的范围
            ascii_str += '\n'
    except:
        print(pixel)
    return ascii_str

if __name__ == '__main__':
    # 使用示例
    ascii_art = img_to_ascii("./data/素材3.png", new_width=100)
    print(ascii_art)

二、200行代码实现2048

import random
import os
import sys
import time

#游戏配置
SIZE = 4
WIN_VALUE = 2048

#初始化游戏板
def init_board():
    board = [[0]*SIZE for _ in range(SIZE)]
    add_random(board)
    add_random(board)
    return board

#在板上添加一个随机值(2或4)
def add_random(board):
    empty_cells = [(r,c) for r in range(SIZE) for c in range(SIZE) if board[r][c] == 0]
    if empty_cells:
        r,c = random.choice(empty_cells)   #随机选择一个元素  r,c代表被选择的元素的行和列
        board[r][c] = 4 if random.random() < 0.1 else 2   #需要随机生成2或4

#打印游戏板
def print_board(board):
    #清屏
    '''
        os.system:这个函数用来在系统的命令行或终端中执行指定的命令。os.name:这是一个 Python 属性,用来返回当前操作系统的名称。
        os.name 的值可以是 'posix'、'nt'、'os2' 等。对于 Windows 操作系统,os.name 的值是 'nt';对于大多数 Unix-like 系统(如 Linux 和 macOS),os.name 的值是 'posix'。
        'cls' 和 'clear':
        'cls':这是 Windows 操作系统中的命令,用来清除命令提示符窗口中的内容。
        'clear':这是 Unix-like 操作系统(如 Linux 和 macOS)中的命令,用来清除终端窗口中的内容。
    '''
    os.system('cls' if os.name == 'nt' else 'clear')
    for row in board:
        print('\t'.join(str(cell) if cell != 0 else '.' for cell in row))
        print()

#合并行
def merge_line(line):
    non_zero = [i for i in line if i != 0]
    merged = []
    skip = False
    for i in range(len(non_zero)):
        if skip:
            skip = False
            continue
        if i < len(non_zero) - 1 and non_zero[i] == non_zero[i+1]:
            merged.append(non_zero[i] * 2)
            skip = True
        else:
            merged.append(non_zero[i])
    return merged + [0] * (SIZE - len(merged))

#旋转板
def rotate_board(board):
    '''
        zip 函数用于将多个可迭代对象(如列表、元组)中的元素按位置配对,生成一个元组的迭代器。每个元组包含来自每个输入可迭代对象的对应元素。
        a = [1, 2, 3]
        b = ['a', 'b', 'c']
        zipped = zip(a, b)
        print(list(zipped))  # 输出:[(1, 'a'), (2, 'b'), (3, 'c')]
        board[::-1]:
        这是一个切片操作,用于将 board 列表反转。[::-1] 表示将列表从最后一个元素到第一个元素倒序排列。
        对于这个board来讲是将行倒序
        * 操作符用于将 board[::-1] 的元素解包成独立的参数传递给 zip 函数。
    '''
    return [list(row) for row in zip(*board[::-1])]


# 移动和合并板
def move_left(board):
    for i in range(SIZE):
        board[i] = merge_line(board[i])
    return board

def move_right(board):
    for i in range(SIZE):
        board[i] = merge_line(board[i][::-1])[::-1]
    return board

def move_up(board):
    board = rotate_board(board)
    board = move_left(board)
    return rotate_board(board[::-1])

def move_down(board):
    board = rotate_board(board)
    board = move_right(board)
    return rotate_board(board[::-1])

# 检查是否还有可能移动的空格或合并
def can_move(board):
    for i in range(SIZE):
        for j in range(SIZE - 1):
            if board[i][j] == 0 or board[i][j] == board[i][j + 1]:
                return True
        for j in range(SIZE - 1):
            if board[j][i] == 0 or board[j][i] == board[j + 1][i]:
                return True
    return False

# 检查是否游戏胜利
def check_win(board):
    return any(cell == WIN_VALUE for row in board for cell in row)

# 主游戏循环
def main():
    board = init_board()
    while True:
        print_board(board)
        if check_win(board):
            print("Congratulations! You've reached 2048!")
            break
        if not can_move(board):
            print("Game Over! No moves left.")
            break
        move = input("Use 'W', 'A', 'S', 'D' to move or 'Q' to quit: ").upper()
        if move == 'Q':
            print("Quitting the game.")
            break
        if move == 'W':
            new_board = move_up(board)
        elif move == 'S':
            new_board = move_down(board)
        elif move == 'A':
            new_board = move_left(board)
        elif move == 'D':
            new_board = move_right(board)
        else:
            continue
        if board != new_board:
            board = new_board
            add_random(board)

if __name__ == "__main__":
    main()
开始
  |
  V
初始化游戏板
  |
  V
主游戏循环
  |
  V
打印游戏板
  |
  V
检查是否胜利
  |----> 是 ---> 打印胜利消息 --> 结束
  |
  V
检查是否可以移动
  |----> 否 ---> 打印游戏结束消息 --> 结束
  |
  V
读取用户输入
  |----> 'Q' --> 打印退出消息 --> 结束
  |----> 'W' --> 移动上 --> 更新游戏板
  |----> 'S' --> 移动下 --> 更新游戏板
  |----> 'A' --> 移动左 --> 更新游戏板
  |----> 'D' --> 移动右 --> 更新游戏板
  |
  V
添加随机数字
  |
  V
返回到主游戏循环


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值