25级第八次实验报告
| 2025010089 | 1 |
| 2025010090 | |
| 2025010091 | 1 |
| 2025010092 | |
| 2025010093 | 1 |
| 2025010094 | |
| 2025010095 | 1 |
| 2025010096 | |
| 2025010097 | 1 |
| 2025010098 | 1 |
| 2025010099 | |
| 2025010100 | |
| 2025010101 | 1 |
| 2025010102 | |
| 2025010103 | |
| 2025010104 | |
| 2025010105 | |
| 2025010106 | |
| 2025010107 | 1 |
| 2025010108 | |
| 2025010109 | |
| 2025010110 | |
| 2025010112 | |
| 2025010113 | |
| 2025010114 | |
| 2025010115 | 1 |
| 2025010117 | 1 |
| 2025010118 | |
| 2025010119 | 1 |
| 2025010120 | |
| 2025010121 | |
| 2025010122 | |
| 2025010124 | 1 |
| 2025010125 | 1 |
| 2025010126 | |
| 2025010127 | |
| 2025010128 | 1 |
| 2025010130 | 1 |
| 2025010131 | 1 |
| 2025010132 |
2025010089张静文
抛物线旋转面
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# 抛物线y=x²绕y轴旋转
t = np.linspace(-2, 2, 50)
th = np.linspace(0, 2*np.pi, 50)
T, TH = np.meshgrid(t, th)
X = T*np.cos(TH)
Z = T*np.sin(TH)
Y = T**2
ax.plot_surface(X,Y,Z)
plt.show()

2025010090殷慧湘
import wave
import simpleaudio as sa
import os
def play_wav_audio(wav_path):
if not os.path.exists(wav_path):
print(f"错误:音频文件【{wav_path}】不存在,请确认文件名和存放位置!")
return
try:
# 加载wav音频
wave_obj = sa.WaveObject.from_wave_file(wav_path)
# 播放音频
play_obj = wave_obj.play()
# 阻塞等待播放完成
play_obj.wait_done()
print("音频播放完毕!")
except Exception as e:
print(f"音频播放失败,异常信息:{e}")
if __name__ == "__main__":
# 方案1:同目录直接写文件名
audio_file = "20250821_151742_1.wav"
# 方案2:桌面绝对路径(取消下面注释使用)
# audio_file = r"C:\Users\30256\Desktop\20250821_151742_1.wav"
play_wav_audio(audio_file)

2025010091张译心
损耗
import pygame
# 初始化窗口
pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("全方位自由反弹小球|速度系数0.8")
# 颜色
WHITE = (255, 255, 255)
ORANGE = (255, 140, 0)
BLACK = (0, 0, 0)
GRAY = (160, 160, 160)
# 小球参数
radius = 20
x = WIDTH // 2
y = HEIGHT // 2
vx = 5.0 # X方向初速度
vy = 3.0 # Y方向初速度
e = 0.8 # 反弹速度衰减系数
# 动能统计
init_energy = vx**2 + vy**2
total_loss = 0.0
# 兼容字体,解决之前报错
try:
font = pygame.font.SysFont("Arial", 20)
except:
font = pygame.font.Font(None, 20)
clock = pygame.time.Clock()
FPS = 60
running = True
while running:
# 退出窗口事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# 小球移动
x += vx
y += vy
# 左右边界碰撞
if x <= radius or x >= WIDTH - radius:
old_e = vx**2 + vy**2
vx = -vx * e
new_e = vx**2 + vy**2
total_loss += old_e - new_e
# 上下边界碰撞
if y <= radius or y >= HEIGHT - radius:
old_e = vx**2 + vy**2
vy = -vy * e
new_e = vx**2 + vy**2
total_loss += old_e - new_e
# 绘制画面
screen.fill(WHITE)
# 四周墙体
pygame.draw.rect(screen, GRAY, (0, 0, WIDTH, 5))
pygame.draw.rect(screen, GRAY, (0, HEIGHT-5, WIDTH, 5))
pygame.draw.rect(screen, GRAY, (0, 0, 5, HEIGHT))
pygame.draw.rect(screen, GRAY, (WIDTH-5, 0, 5, HEIGHT))
# 绘制小球
pygame.draw.circle(screen, ORANGE, (int(x), int(y)), radius)
# 文字信息
loss_rate = total_loss / init_energy
text = f"Speed X:{abs(vx):.2f} Y:{abs(vy):.2f} | Total Energy Loss: {loss_rate:.2%}"
text_surface = font.render(text, True, BLACK)
screen.blit(text_surface, (10, 10))
pygame.display.update()
clock.tick(FPS)
pygame.quit()

2025010093惠盾
音乐加载播放
import pygame
import sys
# 初始化pygame和音频模块
pygame.init()
pygame.mixer.init()
# 窗口设置
WIDTH, HEIGHT = 400, 200
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("音乐播放器")
# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
# 加载音乐文件(替换成你的音乐路径,支持 mp3 / wav)
music_path = "111.mp3"
try:
pygame.mixer.music.load(music_path)
except Exception as e:
print("音乐文件加载失败,请检查路径!", e)
sys.exit()
# 播放状态标记
is_playing = False
font = pygame.font.SysFont("SimHei", 24) # 中文支持
# 主循环
clock = pygame.time.Clock()
while True:
screen.fill(WHITE)
# 事件监听
for event in pygame.event.get():
# 关闭窗口
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# 键盘按键控制
if event.type == pygame.KEYDOWN:
# 空格键:播放/暂停
if event.key == pygame.K_SPACE:
if is_playing:
pygame.mixer.music.pause()
is_playing = False
else:
pygame.mixer.music.unpause()
pygame.mixer.music.play(-1) # -1 代表循环播放
is_playing = True
# S键:停止音乐
if event.key == pygame.K_s:
pygame.mixer.music.stop()
is_playing = False
# 绘制文字提示
if is_playing:
text = font.render("播放中 | 空格暂停 | S停止", True, BLACK)
else:
text = font.render("已暂停 | 空格播放 | S停止", True, BLACK)
screen.blit(text, (30, 80))
pygame.display.flip()
clock.tick(60)

2025010095徐雨轩
卷积操作
import numpy as np
def conv2d_manual(input_img, kernel, stride=1, padding=0):
"""
手动实现二维卷积
:param input_img: 输入矩阵 (H, W)
:param kernel: 卷积核 (kh, kw)
:param stride: 步长
:param padding: 边缘填充0
:return: 卷积输出特征图
"""
# 1. 获取尺寸
h_in, w_in = input_img.shape
kh, kw = kernel.shape
# 2. 填充
pad_h = padding
pad_w = padding
pad_img = np.pad(input_img, ((pad_h, pad_h), (pad_w, pad_w)), mode='constant', constant_values=0)
# 3. 计算输出尺寸
h_out = (h_in + 2 * padding - kh) // stride + 1
w_out = (w_in + 2 * padding - kw) // stride + 1
# 4. 初始化输出
output = np.zeros((h_out, w_out))
# 5. 滑动窗口卷积计算
for i in range(h_out):
for j in range(w_out):
# 截取窗口
window = pad_img[i * stride: i * stride + kh, j * stride: j * stride + kw]
# 点乘求和
output[i, j] = np.sum(window * kernel)
return output
if __name__ == "__main__":
# 输入图像 5x5矩阵
image = np.array([
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25]
])
# 3x3卷积核(边缘检测核)
conv_kernel = np.array([
[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]
])
# 执行卷积 stride=1, padding=1
result = conv2d_manual(image, conv_kernel, stride=1, padding=1)
print("原始输入图像:")
print(image)
print("\n卷积核:")
print(conv_kernel)
print("\n卷积输出结果:")
print(result)

2025010097马浩
飞机大战小游戏
import pygame
import sys
import random
from pygame.locals import *
# 初始化窗口
pygame.init()
SCREEN_WIDTH = 480
SCREEN_HEIGHT = 700
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("飞机大战")
clock = pygame.time.Clock()
FPS = 60
# -------------------------- 精简版精灵基类(移除图集逻辑,不会报subsurface错误) --------------------------
class MySprite(pygame.sprite.Sprite):
def __init__(self, target):
super().__init__()
self.target_surface = target
self.image = None
self.rect = None
# 纯色精灵不需要帧动画,update空实现,不操作master_image
def update(self, current_time):
pass
# -------------------------- 玩家飞机 --------------------------
class Player(MySprite):
def __init__(self, target):
super().__init__(target)
self.speed = 8
# 蓝色方块
self.image = pygame.Surface((60, 80), pygame.SRCALPHA)
pygame.draw.rect(self.image, (0, 200, 255), self.image.get_rect())
self.rect = self.image.get_rect()
self.rect.centerx = SCREEN_WIDTH // 2
self.rect.bottom = SCREEN_HEIGHT - 20
def move(self, key_state):
if key_state[K_LEFT] and self.rect.left > 0:
self.rect.x -= self.speed
if key_state[K_RIGHT] and self.rect.right < SCREEN_WIDTH:
self.rect.x += self.speed
if key_state[K_UP] and self.rect.top > 0:
self.rect.y -= self.speed
if key_state[K_DOWN] and self.rect.bottom < SCREEN_HEIGHT:
self.rect.y += self.speed
# -------------------------- 子弹类 --------------------------
class Bullet(MySprite):
def __init__(self, target, x, y):
super().__init__(target)
self.speed = 12
# 黄色长条
self.image = pygame.Surface((8, 20), pygame.SRCALPHA)
pygame.draw.rect(self.image, (255, 255, 0), self.image.get_rect())
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.bottom = y
def update(self, current_time):
self.rect.y -= self.speed
if self.rect.bottom < 0:
self.kill()
# -------------------------- 敌机类 --------------------------
class Enemy(MySprite):
def __init__(self, target):
super().__init__(target)
self.speed = random.randint(3, 6)
# 红色方块
self.image = pygame.Surface((50, 60), pygame.SRCALPHA)
pygame.draw.rect(self.image, (255, 50, 50), self.image.get_rect())
self.rect = self.image.get_rect()
self.rect.x = random.randint(0, SCREEN_WIDTH - self.rect.width)
self.rect.y = random.randint(-120, -60)
def update(self, current_time):
self.rect.y += self.speed
if self.rect.top > SCREEN_HEIGHT:
self.kill()
# -------------------------- 精灵组初始化 --------------------------
player_group = pygame.sprite.Group()
player = Player(screen)
player_group.add(player)
bullet_group = pygame.sprite.Group()
enemy_group = pygame.sprite.Group()
enemy_spawn_timer = 0
bullet_fire_timer = 0
# -------------------------- 主循环 --------------------------
while True:
ticks = pygame.time.get_ticks()
screen.fill((0, 0, 30))
# 退出事件
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# 玩家移动控制
key_state = pygame.key.get_pressed()
player.move(key_state)
# 自动发射子弹
if ticks - bullet_fire_timer > 150:
bullet = Bullet(screen, player.rect.centerx, player.rect.top)
bullet_group.add(bullet)
bullet_fire_timer = ticks
# 生成敌机
if ticks - enemy_spawn_timer > 800:
enemy = Enemy(screen)
enemy_group.add(enemy)
enemy_spawn_timer = ticks
# 更新所有精灵
player_group.update(ticks)
bullet_group.update(ticks)
enemy_group.update(ticks)
# 子弹碰撞敌机
hit_dict = pygame.sprite.groupcollide(bullet_group, enemy_group, True, True)
if hit_dict:
print("击中敌机")
# 玩家碰撞敌机(像素碰撞)
crash = pygame.sprite.spritecollide(player, enemy_group, True, pygame.sprite.collide_mask)
if crash:
print("游戏结束!")
pygame.quit()
sys.exit()
# 绘制画面
player_group.draw(screen)
bullet_group.draw(screen)
enemy_group.draw(screen)
pygame.display.update()
clock.tick(FPS)

2025010098韩晓媛
小球加减速度
import pygame
import math
# 初始化pygame
pygame.init()
WIDTH, HEIGHT = 600, 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("上下变速运动小球")
clock = pygame.time.Clock()
# 小球参数
ball_r = 20
ball_x = WIDTH // 2 # 水平固定居中
center_y = HEIGHT // 2 # 运动中心
amplitude = 160 # 【加大幅度】上下运动范围更大,变速更明显
time_count = 0 # 时间计数器,控制运动相位
# 颜色
WHITE = (255, 255, 255)
RED = (220, 30, 30)
BLACK = (0, 0, 0)
GRAY = (120, 120, 120)
running = True
while running:
# 事件监听
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# 变速核心:正弦函数模拟简谐运动,两端速度慢,中间速度快
time_count += 0.04 # 【增大步长】整体摆动变快,快慢切换更频繁
offset = amplitude * math.sin(time_count)
ball_y = center_y + offset
# 绘制背景
screen.fill(WHITE)
# 绘制中心参考线
pygame.draw.line(screen, BLACK, (0, center_y), (WIDTH, center_y), 1)
# 绘制上下极限边界线,直观看到小球运动两端
pygame.draw.line(screen, GRAY, (0, center_y + amplitude), (WIDTH, center_y + amplitude), 1)
pygame.draw.line(screen, GRAY, (0, center_y - amplitude), (WIDTH, center_y - amplitude), 1)
# 绘制小球
pygame.draw.circle(screen, RED, (ball_x, int(ball_y)), ball_r)
pygame.display.flip()
clock.tick(60)
pygame.quit()

2025010100霍延萌
叠加
from PIL import Image
import os
# 必须保留这个函数定义,放在文件最上方
def blend_two_pic(bg_path, front_path, output_name, alpha=0.5):
# 判断文件是否存在
if not os.path.exists(bg_path):
print(f"错误:背景图 {bg_path} 不存在!")
return
if not os.path.exists(front_path):
print(f"错误:前景图 {front_path} 不存在!")
return
# 打开底层背景图、上层叠加图
bg_img = Image.open(bg_path).convert("RGB")
front_img = Image.open(front_path).convert("RGB")
# 统一尺寸为背景图大小
front_img = front_img.resize(bg_img.size)
# alpha=0.5 上层50%透明度融合
result = Image.blend(bg_img, front_img, alpha=0.5)
# 保存合成图片
result.save(output_name)
print(f"图片叠加完成,已保存为:{output_name}")
# 主运行代码(你截图里这段)
if __name__ == "__main__":
# 方案1:图片和py代码同一文件夹(已注释,不生效)
# background = "第一张夜景.jpg"
# foreground = "第二张夜景.jpg"
# save_file = "夜景叠加效果图.jpg"
# 方案2:图片在桌面,使用绝对路径(取消#启用)
background = r"C:\Users\30256\Desktop\第一张夜景.jpg"
foreground = r"C:\Users\30256\Desktop\第二张夜景.jpg"
save_file = "夜景叠加效果图.jpg"
blend_two_pic(background, foreground, save_file, alpha=0.5)

2025010101袁泉
A*寻路
import heapq
import matplotlib.pyplot as plt
# 四方向移动:上下左右
DIRS = [(-1, 0), (1, 0), (0, -1), (0, 1)]
class Node:
def __init__(self, x, y):
self.x = x
self.y = y
self.g = 0 # 起点到当前节点的实际代价
self.h = 0 # 当前节点到终点的预估代价
self.f = 0 # 总代价 f = g + h
self.parent = None
# 重载比较运算符,用于优先队列排序
def __lt__(self, other):
return self.f < other.f
def manhattan_h(x1, y1, x2, y2):
"""曼哈顿距离 启发函数"""
return abs(x1 - x2) + abs(y1 - y2)
def a_star(grid, start, end):
rows = len(grid)
cols = len(grid[0])
start_x, start_y = start
end_x, end_y = end
# 边界/障碍物判断
if grid[start_x][start_y] == 1 or grid[end_x][end_y] == 1:
return None
open_heap = []
closed = set()
node_map = {} # 坐标 -> 节点
start_node = Node(start_x, start_y)
start_node.h = manhattan_h(start_x, start_y, end_x, end_y)
start_node.f = start_node.g + start_node.h
heapq.heappush(open_heap, start_node)
node_map[(start_x, start_y)] = start_node
while open_heap:
# 取出f值最小的节点
cur_node = heapq.heappop(open_heap)
cur_x, cur_y = cur_node.x, cur_node.y
# 到达终点,回溯路径
if (cur_x, cur_y) == (end_x, end_y):
path = []
while cur_node:
path.append((cur_node.x, cur_node.y))
cur_node = cur_node.parent
return path[::-1] # 反转得到起点到终点路径
closed.add((cur_x, cur_y))
# 遍历四个方向邻居
for dx, dy in DIRS:
nx = cur_x + dx
ny = cur_y + dy
# 越界判断
if 0 <= nx < rows and 0 <= ny < cols:
# 障碍物 或 已探索,跳过
if grid[nx][ny] == 1 or (nx, ny) in closed:
continue
# 新建/获取邻居节点
if (nx, ny) not in node_map:
neighbor = Node(nx, ny)
node_map[(nx, ny)] = neighbor
else:
neighbor = node_map[(nx, ny)]
# 计算新g值(每步代价为1)
new_g = cur_node.g + 1
# 新路径更优则更新
if new_g < neighbor.g or (nx, ny) not in [n for n in open_heap]:
neighbor.parent = cur_node
neighbor.g = new_g
neighbor.h = manhattan_h(nx, ny, end_x, end_y)
neighbor.f = neighbor.g + neighbor.h
heapq.heappush(open_heap, neighbor)
# 无可通行路径
return None
def visualize_path(grid, path, start, end):
"""用matplotlib可视化地图和路径"""
plt.figure(figsize=(6, 6))
rows = len(grid)
cols = len(grid[0])
# 绘制地图
for i in range(rows):
for j in range(cols):
if grid[i][j] == 1:
plt.fill_between([j, j+1], i, i+1, color='black') # 障碍物
else:
plt.fill_between([j, j+1], i, i+1, color='white', edgecolor='gray') # 空地
# 绘制路径
if path:
path_x = [p[1] + 0.5 for p in path]
path_y = [p[0] + 0.5 for p in path]
plt.plot(path_x, path_y, color='blue', linewidth=3, label='Path')
# 标记起点和终点
plt.scatter(start[1]+0.5, start[0]+0.5, color='green', s=200, marker='o', label='Start')
plt.scatter(end[1]+0.5, end[0]+0.5, color='red', s=200, marker='s', label='End')
plt.gca().invert_yaxis() # 让y轴从上到下
plt.xticks(range(cols))
plt.yticks(range(rows))
plt.grid(True)
plt.legend()
plt.title("A* Pathfinding Visualization")
plt.show()
# ===================== 测试运行 =====================
if __name__ == "__main__":
# 地图:0=可通行 1=障碍物
maze = [
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 1, 0],
[1, 1, 0, 0, 0],
[0, 0, 0, 1, 0]
]
start_pos = (0, 0) # 起点坐标
end_pos = (4, 4) # 终点坐标
result_path = a_star(maze, start_pos, end_pos)
print("寻路路径坐标:", result_path)
print("\n地图可视化:")
visualize_path(maze, result_path, start_pos, end_pos)

2025010107孙瑞妍
# -*- coding: utf-8 -*-
"""
Python聚类分析综合示例(教材风格)
算法:K-Means 聚类
"""
# 1. 导入所需库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score
# 设置中文显示(可选,解决图中中文乱码)
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False
# 2. 构造/读取数据集(模拟教材常用二维样本数据)
data = {
'特征1': [2.0, 1.8, 3.2, 8.0, 7.5, 9.1, 4.0, 4.2, 3.8, 6.5, 6.8, 7.2],
'特征2': [1.5, 1.2, 1.8, 7.0, 6.8, 7.3, 2.1, 2.3, 2.0, 5.5, 5.8, 6.1]
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
# 3. 数据标准化(聚类必须做,消除量纲影响)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(df)
# 4. 肘部法则选择最佳聚类数(教材必讲)
inertia_list = []
k_list = range(1, 7)
for k in k_list:
kmeans = KMeans(n_clusters=k, random_state=0)
kmeans.fit(X_scaled)
inertia_list.append(kmeans.inertia_)
# 绘制肘部图
plt.figure(figsize=(6, 4))
plt.plot(k_list, inertia_list, marker='o')
plt.xlabel("聚类数量 k")
plt.ylabel("簇内误差平方和")
plt.title("肘部法则确定最佳k值")
plt.show()
# 5. 执行K-Means聚类(假设选k=3,可根据肘部图修改)
k = 3
kmeans_model = KMeans(n_clusters=k, random_state=0)
df['聚类标签'] = kmeans_model.fit_predict(X_scaled)
# 6. 输出聚类结果
print("\n聚类后数据:")
print(df)
print("\n聚类中心:")
print(kmeans_model.cluster_centers_)
# 7. 轮廓系数评估聚类效果(教材评价指标)
sil_score = silhouette_score(X_scaled, df['聚类标签'])
print(f"\n轮廓系数(越接近1效果越好):{sil_score:.4f}")
# 8. 聚类结果可视化
plt.figure(figsize=(6, 5))
plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=df['聚类标签'], cmap='rainbow', s=60)
plt.scatter(kmeans_model.cluster_centers_[:,0],
kmeans_model.cluster_centers_[:,1],
c='black', marker='X', s=150, label='聚类中心')
plt.xlabel("特征1(标准化)")
plt.ylabel("特征2(标准化)")
plt.title("K-Means聚类结果")
plt.legend()
plt.show()

2025010115 康静茹
制作一个Windows屏保(动态)
import pygame
import sys
import random
# 初始化
pygame.init()
screen_info = pygame.display.Info()
W, H = screen_info.current_w, screen_info.current_h
screen = pygame.display.set_mode((W, H), pygame.FULLSCREEN)
pygame.mouse.set_visible(False)
clock = pygame.time.Clock()
# 粉色系 + 透明度 (R,G,B,Alpha)
PINK_COLOR = (255, 150, 200, 120)
class Bubble:
def __init__(self):
self.r = random.randint(18, 50)
self.x = random.randint(self.r, W - self.r)
self.y = random.randint(self.r, H - self.r)
self.vx = random.uniform(-1.8, 1.8)
self.vy = random.uniform(-1.8, 1.8)
def update(self):
self.x += self.vx
self.y += self.vy
# 边界反弹
if self.x - self.r < 0 or self.x + self.r > W:
self.vx *= -1
if self.y - self.r < 0 or self.y + self.r > H:
self.vy *= -1
def draw(self, surf):
# 透明画布绘制气泡
buf = pygame.Surface((self.r*2, self.r*2), pygame.SRCALPHA)
pygame.draw.circle(buf, PINK_COLOR, (self.r, self.r), self.r)
surf.blit(buf, (int(self.x - self.r), int(self.y - self.r)))
# 气泡碰撞逻辑
def collide(bub_list):
for i in range(len(bub_list)):
for j in range(i + 1, len(bub_list)):
b1, b2 = bub_list[i], bub_list[j]
dx = b1.x - b2.x
dy = b1.y - b2.y
dist = (dx**2 + dy**2) ** 0.5
min_d = b1.r + b2.r
if dist < min_d:
# 交换速度实现弹性碰撞
b1.vx, b2.vx = b2.vx, b1.vx
b1.vy, b2.vy = b2.vy, b1.vy
# 分离防止粘连
if dist != 0:
offset = min_d - dist
b1.x += dx / dist * offset / 2
b1.y += dy / dist * offset / 2
b2.x -= dx / dist * offset / 2
b2.y -= dy / dist * offset / 2
# 创建气泡,数量可自行修改
bubble_num = 15
bubbles = [Bubble() for _ in range(bubble_num)]
running = True
while running:
# 退出监听
for e in pygame.event.get():
if e.type in (pygame.QUIT, pygame.KEYDOWN, pygame.MOUSEBUTTONDOWN):
running = False
if e.type == pygame.MOUSEMOTION:
if abs(e.rel[0]) > 8 or abs(e.rel[1]) > 8:
running = False
# 深色背景衬托粉色透明气泡
screen.fill((5, 5, 15))
# 更新、碰撞、绘制
for b in bubbles:
b.update()
collide(bubbles)
for b in bubbles:
b.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
sys.exit()


2025010117 李欣栎
消消乐
import pygame
import random
# 基础配置常量
pygame.init()
BLOCK_SIZE = 60
MAP_SIZE = 8
WIN_WIDTH = BLOCK_SIZE * MAP_SIZE
WIN_HEIGHT = BLOCK_SIZE * MAP_SIZE
screen = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT))
pygame.display.set_caption("简易消消乐")
clock = pygame.time.Clock()
FPS = 60
# 方块颜色列表
BLOCK_COLORS = [
(255, 70, 70),
(70, 255, 70),
(70, 70, 255),
(255, 255, 70),
(255, 70, 255)
]
# 生成空白棋盘
def create_board():
board = []
for r in range(MAP_SIZE):
row = []
for c in range(MAP_SIZE):
row.append(random.randint(0, len(BLOCK_COLORS)-1))
board.append(row)
return board
# 绘制界面
def render_board(board, selected=None):
# 填充背景(必须是三元组,不能少括号)
screen.fill((20, 20, 20))
for r in range(MAP_SIZE):
for c in range(MAP_SIZE):
x = c * BLOCK_SIZE
y = r * BLOCK_SIZE
color_idx = board[r][c]
# 绘制方块
pygame.draw.rect(
screen,
BLOCK_COLORS[color_idx],
(x + 2, y + 2, BLOCK_SIZE - 4, BLOCK_SIZE - 4)
)
# 选中白框
if selected is not None and selected[0] == r and selected[1] == c:
pygame.draw.rect(
screen,
(255, 255, 255),
(x, y, BLOCK_SIZE, BLOCK_SIZE),
3
)
# 刷新画面
pygame.display.flip()
# 查找所有可消除方块坐标
def find_all_matches(board):
match_pos = set()
# 横向三消检测
for r in range(MAP_SIZE):
c = 0
while c <= MAP_SIZE - 3:
val = board[r][c]
if val == board[r][c+1] and val == board[r][c+2]:
match_pos.add((r, c))
match_pos.add((r, c+1))
match_pos.add((r, c+2))
c += 1
# 纵向三消检测
for c in range(MAP_SIZE):
r = 0
while r <= MAP_SIZE - 3:
val = board[r][c]
if val == board[r+1][c] and val == board[r+2][c]:
match_pos.add((r, c))
match_pos.add((r+1, c))
match_pos.add((r+2, c))
r += 1
return match_pos
# 消除方块+下落填充
def remove_and_drop(board, match_set):
# 标记消除位置
for (r, c) in match_set:
board[r][c] = None
# 逐列处理下落
for c in range(MAP_SIZE):
col_data = []
# 收集本列未消除方块
for r in range(MAP_SIZE):
if board[r][c] is not None:
col_data.append(board[r][c])
# 上方生成新方块
new_blocks = [random.randint(0, 4) for _ in range(MAP_SIZE - len(col_data))]
full_col = new_blocks + col_data
# 写回棋盘
for r in range(MAP_SIZE):
board[r][c] = full_col[r]
# 交换两个格子
def swap_block(board, r1, c1, r2, c2):
board[r1][c1], board[r2][c2] = board[r2][c2], board[r1][c1]
# 鼠标坐标转棋盘行列
def mouse_to_cell(mx, my):
c = mx // BLOCK_SIZE
r = my // BLOCK_SIZE
if 0 <= r < MAP_SIZE and 0 <= c < MAP_SIZE:
return (r, c)
return None
def main_game():
game_board = create_board()
selected_cell = None
running = True
while running:
# 事件优先处理,防止窗口卡死
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# 鼠标点击交换逻辑
if event.type == pygame.MOUSEBUTTONDOWN:
cell = mouse_to_cell(*pygame.mouse.get_pos())
if cell is None:
continue
if selected_cell is None:
selected_cell = cell
else:
r1, c1 = selected_cell
r2, c2 = cell
# 判断是否相邻
if abs(r1 - r2) + abs(c1 - c2) == 1:
swap_block(game_board, r1, c1, r2, c2)
# 交换后无消除则还原
matches = find_all_matches(game_board)
if len(matches) == 0:
swap_block(game_board, r1, c1, r2, c2)
selected_cell = None
# 连锁消除(加画面刷新,不会卡死)
matches = find_all_matches(game_board)
while len(matches) > 0:
remove_and_drop(game_board, matches)
render_board(game_board, selected_cell)
pygame.time.delay(100) # 消除停顿,避免死循环卡死
matches = find_all_matches(game_board)
# 绘制当前棋盘
render_board(game_board, selected_cell)
clock.tick(FPS)
pygame.quit()
if __name__ == "__main__":
main_game()


2025010119 淡郑雪
两张图拼接
from PIL import Image
def merge_two_img(img1_path, img2_path, save_path, direction="horizontal"):
"""
拼接两张图片
:param img1_path: 第一张图路径
:param img2_path: 第二张图路径
:param save_path: 输出保存路径
:param direction: horizontal左右拼接 / vertical上下拼接
"""
# 打开图片
img1 = Image.open(img1_path)
img2 = Image.open(img2_path)
# 统一高度(左右拼接)/统一宽度(上下拼接)
if direction == "horizontal":
# 左右拼接:高度取两张图最大值
target_h = max(img1.height, img2.height)
# 等比例缩放两张图
img1 = img1.resize((img1.width, target_h), Image.Resampling.LANCZOS)
img2 = img2.resize((img2.width, target_h), Image.Resampling.LANCZOS)
# 新建画布
new_w = img1.width + img2.width
new_h = target_h
new_img = Image.new("RGB", (new_w, new_h))
# 粘贴图片
new_img.paste(img1, (0, 0))
new_img.paste(img2, (img1.width, 0))
elif direction == "vertical":
# 上下拼接:宽度取两张图最大值
target_w = max(img1.width, img2.width)
img1 = img1.resize((target_w, img1.height), Image.Resampling.LANCZOS)
img2 = img2.resize((target_w, img2.height), Image.Resampling.LANCZOS)
new_w = target_w
new_h = img1.height + img2.height
new_img = Image.new("RGB", (new_w, new_h))
new_img.paste(img1, (0, 0))
new_img.paste(img2, (0, img1.height))
# 保存结果
new_img.save(save_path)
print(f"图片拼接完成,保存至:{save_path}")
return new_img
# ========== 使用示例 ==========
if __name__ == "__main__":
# 替换成你的两张图片路径
pic1 = "1.jpg"
pic2 = "2.jpg"
output = "merge_result.jpg"
# 左右拼接
merge_two_img(pic1, pic2, output, direction="horizontal")
# 上下拼接取消注释运行
# merge_two_img(pic1, pic2, "vertical_merge.jpg", direction="vertical")

2025010124 胡鑫
加载图片
import cv2
# 替换成你的图片路径,相对/绝对路径都可以
img_path = "test.jpg"
# 读取图片
img = cv2.imread(img_path)
# 判断是否读取成功
if img is None:
print("图片读取失败,请检查路径是否正确")
else:
# 弹出窗口显示图片
cv2.imshow("Picture", img)
# 等待按键,任意键关闭窗口
cv2.waitKey(0)
# 释放所有窗口
cv2.destroyAllWindows()

2025010125 刘芮孜
聚类分析图
import requests
import pandas as pd
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
}
def get_forbes_data():
try:
url = "https://forbes400.herokuapp.com/api/forbes400/getAllForbes400"
res = requests.get(url, headers=headers, timeout=10)
data = res.json()
df = pd.DataFrame(data)
df = df[['name', 'netWorth', 'source', 'industry']]
df['netWorth'] = pd.to_numeric(df['netWorth'], errors='coerce')
return df.dropna()
except Exception as e:
print(f"线上榜单接口无法访问,加载模拟富豪数据集:{e}")
mock_data = [
{"name":"Elon Musk","netWorth":219,"source":"Tesla/SpaceX","industry":"高端制造/航天"},
{"name":"Jeff Bezos","netWorth":171,"source":"Amazon","industry":"电商零售"},
{"name":"Bernard Arnault","netWorth":158,"source":"LVMH","industry":"奢侈品制造"},
{"name":"Bill Gates","netWorth":129,"source":"Microsoft","industry":"软件信息技术"},
{"name":"Warren Buffett","netWorth":118,"source":"Berkshire","industry":"金融投资"},
{"name":"Larry Page","netWorth":111,"source":"Google","industry":"互联网科技"},
{"name":"Sergey Brin","netWorth":107,"source":"Google","industry":"互联网科技"},
{"name":"Steve Ballmer","netWorth":91,"source":"Microsoft","industry":"软件信息技术"},
{"name":"Larry Ellison","netWorth":106,"source":"Oracle","industry":"软件信息技术"},
{"name":"Gautam Adani","netWorth":90,"source":"基建能源","industry":"能源上游"},
{"name":"Mukesh Ambani","netWorth":83,"source":"石化","industry":"化工上游"},
{"name":"Zhang Yiming","netWorth":50,"source":"TikTok","industry":"互联网平台"},
{"name":"Zhong Shanshan","netWorth":68,"source":"农夫山泉","industry":"消费品下游"},
{"name":"Li Ka-shing","netWorth":32,"source":"地产港口","industry":"地产基建下游"},
{"name":"Cathy Wood","netWorth":1.5,"source":"基金","industry":"金融服务下游"}
]
return pd.DataFrame(mock_data)
def classify_chain(industry):
upstream = {"能源上游","化工上游","高端制造/航天","矿产","芯片原料","重工原材料"}
downstream = {"电商零售","奢侈品制造","消费品下游","地产基建下游"}
neutral = {"互联网科技","软件信息技术","金融投资","互联网平台","金融服务下游"}
if industry in upstream:
return "上游产业"
elif industry in downstream:
return "下游产业"
elif industry in neutral:
return "中性服务业"
else:
return "其他行业"
df = get_forbes_data()
df['产业链分类'] = df['industry'].apply(classify_chain)
# 统计占比表格
chain_count = df['产业链分类'].value_counts()
person_ratio = round(chain_count / len(df) * 100, 2)
total_wealth = df.groupby('产业链分类')['netWorth'].sum()
wealth_ratio = round(total_wealth / df['netWorth'].sum() * 100, 2)
stat_table = pd.DataFrame({
"富豪人数": chain_count,
"人数占比(%)": person_ratio,
"总财富(百亿美元)": total_wealth,
"财富占比(%)": wealth_ratio
})
# 控制台打印结果
print("="*65)
print("福布斯富豪榜 上下游产业统计分析表")
print("="*65)
print(stat_table)
# 绘制图表
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15,6))
ax1.pie(stat_table['富豪人数'], labels=stat_table.index, autopct='%1.2f%%', startangle=90)
ax1.set_title('各产业链富豪人数分布占比')
ax2.bar(stat_table.index, stat_table['总财富(百亿美元)'])
ax2.set_title('各产业链总财富规模(单位:百亿美元)')
ax2.set_ylabel("财富总值")
plt.tight_layout()
plt.show()
# 导出Excel文件
with pd.ExcelWriter('福布斯富豪产业分析结果.xlsx') as writer:
df.to_excel(writer, sheet_name='富豪原始明细', index=False)
stat_table.to_excel(writer, sheet_name='产业链占比统计')
print("\n✅ 分析完成,Excel文件已生成:福布斯富豪产业分析结果.xlsx")

2025010127 刘杨龙
from PIL import Image
# 加载图片
img = Image.open("123.png")
# 查看属性
print("图片尺寸:", img.size) # (宽, 高)
print("图片模式:", img.mode) # RGB/RGBA/L等
# 显示图片
img.show()
# 保存图片
img.save("output.png")

2025010128 贾姝慧
视频追踪
# 导入opencv库,用来画图、显示画面、识别红点
import cv2
# 导入numpy库,用来处理数组、颜色阈值这些数据
import numpy as np
# 设置生成画面的宽度 800像素
WIDTH = 600
# 设置生成画面的高度 600像素
HEIGHT = 400
# 红点最开始出现的横坐标
x, y = 100, 100
# 红点水平移动的速度
speed_x = 3
# 红点竖直移动的速度
speed_y = 2e5
# 绘制的红色圆点半径大小
dot_r = 12
# HSV空间里红色下限,用来筛选画面里的红色区域
lower_red = np.array([0, 120, 70])
# HSV空间里红色上限,配合下限框出红色范围
upper_red = np.array([10, 255, 255])
# 定义窗口名字,后面显示画面要用
win_name = "自建视频-红点实时追踪"
# 死循环,不断生成每一帧画面,模拟连续视频
while True:
# 创建一张纯黑色画布,对应视频的一帧画面
frame = np.zeros((HEIGHT, WIDTH, 3), dtype=np.uint8)
# 在画布上绘制红色实心圆点,BGR(0,0,255)是红色,-1代表填充内部
cv2.circle(frame, (int(x), int(y)), dot_r, (0, 0, 255), -1)
# 横坐标加上速度,让红点左右移动
x += speed_x
# 纵坐标加上速度,让红点上下移动
y += speed_y
# 碰到左右边界时,水平速度反向,实现左右反弹
if x <= dot_r or x >= WIDTH - dot_r:
speed_x = -speed_x
# 碰到上下边界时,竖直速度反向,实现上下反弹
if y <= dot_r or y >= HEIGHT - dot_r:
speed_y = -speed_y
# 把RGB画面转换成HSV色彩空间,方便更好的识别颜色
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 根据设置的红色阈值,生成掩码,只保留红色区域,其余地方变黑
mask = cv2.inRange(hsv, lower_red, upper_red)
# 创建3*3的卷积核,用于图像降噪
kernel = np.ones((3, 3), np.uint8)
# 闭运算,去除小噪点,让红色区域更完整
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
# 在掩码图里查找所有轮廓,也就是找到红色区域的边缘
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 遍历每一个找到的轮廓
for cnt in contours:
# 计算当前轮廓的面积
area = cv2.contourArea(cnt)
# 面积太小的噪点直接跳过,不做追踪
if area < 10:
continue
# 给轮廓包裹最小外接圆,获取圆心坐标和圆半径
(cx, cy), r = cv2.minEnclosingCircle(cnt)
# 把浮点型的圆心转成整数像素坐标
center = (int(cx), int(cy))
# 用绿色圆圈框住识别到的红点
cv2.circle(frame, center, int(r), (0, 255, 0), 2)
# 在红点中心画一个蓝色小点标记追踪中心
cv2.circle(frame, center, 4, (255, 0, 0), -1)
# 在控制台实时打印识别出来的红点XY坐标
print(f"追踪到红点坐标 X:{cx:.2f} Y:{cy:.2f}")
# 弹出窗口,展示当前这一帧画面
cv2.imshow(win_name, frame)
# 等待20毫秒,监听键盘按键
key = cv2.waitKey(20) & 0xFF
# 如果按下ESC键,跳出循环结束程序
if key == 27:
break
# 如果手动点击窗口右上角×关闭窗口,也跳出循环
if cv2.getWindowProperty(win_name, cv2.WND_PROP_VISIBLE) < 1:
break
# 循环结束,关闭所有opencv打开的窗口,释放资源
cv2.destroyAllWindows()

2025010130任鸿杰
from PIL import Image
# 打开图片
img = Image.open("123.jpg")
# 放大2倍,双线性插值
new_size = (img.width * 2, img.height * 2)
resized_img = img.resize(new_size, Image.BILINEAR)
# 保存
resized_img.save("big_img.jpg")
resized_img.show()

2025010131 董玥卓
加载音频
from playsound import playsound
import os
# 获取当前脚本目录
current_path = os.path.dirname(__file__)
audio_file = os.path.join(current_path, "audio.mp3")
# 直接播放mp3
playsound(audio_file)


浙公网安备 33010602011771号