
自从装了希沃白板电视屏,发现它可以触屏后,我想设计更多"人机"互动的学习材料
问Deepseek


还是决定先做一个"水果练练看"套用狮虎旗里面的头尾(Python封装)





python
'''
01水果连连看6*6 多个关卡,难度一样
Deepseek,阿夏
202060325
'''
def calculate_gold_profit():
"""
积存金买卖计算器
支持自定义买入价、卖出价、克数、手续费率
计算利息、实际收益和收益率百分比
"""
print("=" * 50)
print("💰 积存金买卖计算器")
print("=" * 50)
# 获取用户输入
try:
buy_price = float(input("请输入买入价(元/克):"))
sell_price = float(input("请输入卖出价(元/克):"))
grams = float(input("请输入购买克数:"))
fee_rate = float(input("请输入手续费率(%):"))
print("\n" + "=" * 50)
print("📊 计算中...")
print("=" * 50)
# 计算买入总金额
buy_total = buy_price * grams
# 计算卖出总金额(未扣除手续费)
sell_total_before_fee = sell_price * grams
# 计算手续费
fee = sell_total_before_fee * (fee_rate / 100)
# 实际到手金额(扣除手续费后)
sell_total_after_fee = sell_total_before_fee - fee
# 计算账面收益(未扣除手续费)
paper_profit = sell_total_before_fee - buy_total
paper_profit_percent = (paper_profit / buy_total) * 100 if buy_total > 0 else 0
# 计算实际收益(扣除手续费后)
actual_profit = sell_total_after_fee - buy_total
actual_profit_percent = (actual_profit / buy_total) * 100 if buy_total > 0 else 0
# 计算利息(实际收益)
interest = actual_profit
# 输出结果
print(f"\n📈 交易明细:")
print(f" • 买入总金额:{buy_total:.2f} 元")
print(f" • 卖出总金额(未扣费):{sell_total_before_fee:.2f} 元")
print(f" • 手续费({fee_rate}%):{fee:.2f} 元")
print(f" • 实际到手金额:{sell_total_after_fee:.2f} 元")
print(f"\n💰 收益分析:")
print(f" • 账面收益:{paper_profit:+.2f} 元")
print(f" • 账面收益率:{paper_profit_percent:+.2f}%")
print(f" • 实际收益(利息):{actual_profit:+.2f} 元")
print(f" • 实际收益率:{actual_profit_percent:+.2f}%")
# 额外输出示例数据验证
if buy_price == 1000 and sell_price == 1010 and grams == 1 and fee_rate == 0.4:
print(f"\n✨ 验证示例(1000买入,1010卖出,1克,0.4%手续费):")
print(f" • 买入:{buy_total:.2f} 元")
print(f" • 卖出未扣费:{sell_total_before_fee:.2f} 元")
print(f" • 手续费:{fee:.2f} 元")
print(f" • 实际收益:{actual_profit:.2f} 元")
print(f" • 实际收益率:{actual_profit_percent:.2f}%")
# 判断盈亏
if actual_profit > 0:
print(f"\n🎉 恭喜!本次交易盈利 {actual_profit:.2f} 元!")
elif actual_profit < 0:
print(f"\n📉 本次交易亏损 {abs(actual_profit):.2f} 元,请谨慎操作!")
else:
print(f"\n🤝 本次交易盈亏平衡,无利润。")
# 盈亏平衡点分析
if actual_profit < 0:
break_even_price = (buy_total + fee) / grams
print(f"\n💡 盈亏平衡点:{break_even_price:.2f} 元/克")
print(f" 需要卖出价达到 {break_even_price:.2f} 元才能保本")
# 返回结果字典,方便后续使用
result = {
'buy_price': buy_price,
'sell_price': sell_price,
'grams': grams,
'fee_rate': fee_rate,
'buy_total': buy_total,
'sell_total_before_fee': sell_total_before_fee,
'fee': fee,
'sell_total_after_fee': sell_total_after_fee,
'paper_profit': paper_profit,
'paper_profit_percent': paper_profit_percent,
'actual_profit': actual_profit,
'actual_profit_percent': actual_profit_percent
}
return result
except ValueError:
print("❌ 输入错误!请输入有效的数字。")
return None
except Exception as e:
print(f"❌ 计算错误:{e}")
return None
def calculate_with_batch():
"""
批量计算多个场景,方便对比
"""
print("\n" + "=" * 50)
print("📊 批量计算模式")
print("=" * 50)
# 定义几个典型场景
scenarios = [
{"name": "示例场景1(1000买入1010卖出1克)", "buy": 1000, "sell": 1010, "grams": 1, "fee": 0.4},
{"name": "示例场景2(1000买入1020卖出1克)", "buy": 1000, "sell": 1020, "grams": 1, "fee": 0.4},
{"name": "示例场景3(1000买入1005卖出1克)", "buy": 1000, "sell": 1005, "grams": 1, "fee": 0.4},
{"name": "示例场景4(1000买入990卖出1克)", "buy": 1000, "sell": 990, "grams": 1, "fee": 0.4},
{"name": "示例场景5(500买入510卖出10克)", "buy": 500, "sell": 510, "grams": 10, "fee": 0.4},
]
print("\n📈 各场景收益对比:\n")
print(f"{'场景名称':<30} {'实际收益':<15} {'实际收益率':<15}")
print("-" * 60)
for scenario in scenarios:
buy_total = scenario["buy"] * scenario["grams"]
sell_total_before = scenario["sell"] * scenario["grams"]
fee = sell_total_before * (scenario["fee"] / 100)
actual_profit = (sell_total_before - fee) - buy_total
actual_profit_percent = (actual_profit / buy_total) * 100
print(f"{scenario['name']:<30} {actual_profit:+.2f}元{'':<10} {actual_profit_percent:+.2f}%")
print("\n💡 提示:手续费会显著影响实际收益,尤其是小额交易时")
def calculate_with_visual():
"""
带可视化显示的版本,使用emoji和格式美化
"""
print("\n" + "🌟" * 25)
print(" 积存金买卖计算器(豪华版)")
print("🌟" * 25)
try:
print("\n请输入以下信息:")
buy_price = float(input(" 📊 买入价(元/克):"))
sell_price = float(input(" 📈 卖出价(元/克):"))
grams = float(input(" ⚖️ 购买克数:"))
fee_rate = float(input(" 💸 手续费率(%):"))
# 计算
buy_total = buy_price * grams
sell_total_before = sell_price * grams
fee = sell_total_before * (fee_rate / 100)
sell_total_after = sell_total_before - fee
actual_profit = sell_total_after - buy_total
actual_profit_percent = (actual_profit / buy_total) * 100 if buy_total > 0 else 0
# 输出结果(美化版)
print("\n" + "=" * 50)
print("📋 交易结算单")
print("=" * 50)
print(f"\n【买入信息】")
print(f" 单价:{buy_price:.2f} 元/克")
print(f" 数量:{grams:.2f} 克")
print(f" 总价:{buy_total:.2f} 元")
print(f"\n【卖出信息】")
print(f" 单价:{sell_price:.2f} 元/克")
print(f" 总价(毛额):{sell_total_before:.2f} 元")
print(f" 手续费:{fee:.2f} 元")
print(f" 净收入:{sell_total_after:.2f} 元")
print(f"\n【收益分析】")
if actual_profit > 0:
print(f" 🎉 实际收益:{actual_profit:+.2f} 元")
print(f" 🎉 收益率:{actual_profit_percent:+.2f}%")
profit_icon = "📈"
elif actual_profit < 0:
print(f" 📉 实际亏损:{actual_profit:+.2f} 元")
print(f" 📉 收益率:{actual_profit_percent:+.2f}%")
profit_icon = "📉"
else:
print(f" 🤝 盈亏平衡")
profit_icon = "⚖️"
# 简单的趋势图
print(f"\n【趋势示意】")
price_change = sell_price - buy_price
if price_change > 0:
arrow = "▲"
trend = "上涨"
else:
arrow = "▼"
trend = "下跌"
print(f" 价格变动:{arrow} {abs(price_change):.2f} 元/克 ({trend})")
print(f" 本金:{buy_total:.2f} 元")
print(f" 手续费占比:{(fee / buy_total * 100):.2f}%")
# 盈亏平衡点提示
if actual_profit <= 0:
break_even = (buy_total + fee) / grams
print(f"\n💡 盈亏平衡价:{break_even:.2f} 元/克")
return {
'buy_total': buy_total,
'sell_total_after': sell_total_after,
'actual_profit': actual_profit,
'actual_profit_percent': actual_profit_percent
}
except ValueError:
print("❌ 输入无效,请输入数字!")
return None
if __name__ == "__main__":
print("🎯 积存金买卖计算工具")
print("=" * 50)
print("请选择模式:")
print("1. 单次计算模式")
print("2. 批量对比模式")
print("3. 豪华可视化模式")
print("4. 退出")
while True:
try:
choice = input("\n请选择(1/2/3/4):").strip()
if choice == '1':
calculate_gold_profit()
break
elif choice == '2':
calculate_with_batch()
break
elif choice == '3':
calculate_with_visual()
break
elif choice == '4':
print("👋 再见!")
break
else:
print("❌ 请输入 1、2、3 或 4")
except KeyboardInterrupt:
print("\n\n👋 程序已退出")
break


点掉一组,显示10分

不会做,可以提示按那些

重新洗牌,重新排列

但是我感觉每个都是红红的水果,不容易辨认


python
'''
02水果连连看6*6 多个关卡,难度一样
水果是红色,但是彩色背景
Deepseek,阿夏
202060325
'''
import os
def generate_fruit_link_game():
"""
生成水果连连看游戏HTML文件
包含积分、关卡机制,每关结束后自动进入下一关,难度保持不变
每种水果都有独特的颜色,让游戏更加生动
"""
html_content = '''<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>彩色水果连连看 - 益智闯关</title>
<style>
* {
user-select: none;
-webkit-tap-highlight-color: transparent;
}
body {
background: linear-gradient(145deg, #1a6d2b 0%, #0e4a1a 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Segoe UI', 'Comic Neue', 'Comic Neue', 'Comic Sans MS', 'Chalkboard SE', cursive, sans-serif;
margin: 0;
padding: 20px;
}
/* 游戏主面板 */
.game-container {
background: #fdf8e7;
border-radius: 72px;
box-shadow: 0 25px 40px rgba(0,0,0,0.3), inset 0 1px 3px rgba(255,255,200,0.8);
padding: 20px 25px 30px 25px;
text-align: center;
transition: all 0.2s;
}
/* 头部信息 */
.info-panel {
display: flex;
justify-content: space-between;
align-items: baseline;
background: #f5e5c8;
padding: 12px 24px;
border-radius: 60px;
margin-bottom: 20px;
gap: 20px;
flex-wrap: wrap;
box-shadow: inset 0 1px 4px rgba(0,0,0,0.05), 0 6px 12px rgba(0,0,0,0.1);
}
.score-box, .level-box {
background: #5a3e2b;
color: #ffefb9;
padding: 8px 20px;
border-radius: 40px;
font-weight: bold;
font-size: 1.5rem;
text-shadow: 0 2px 0 #2e1e12;
box-shadow: inset 0 1px 2px rgba(255,255,200,0.3), 0 4px 8px rgba(0,0,0,0.2);
}
.score-box span, .level-box span {
font-size: 1.8rem;
margin-left: 8px;
color: #ffd966;
}
/* 网格区域 */
.grid-wrapper {
background: #fffaec;
border-radius: 48px;
padding: 20px;
box-shadow: inset 0 0 0 2px #fff9e6, inset 0 0 0 6px #e7dbb8, 0 15px 20px rgba(0,0,0,0.2);
}
.game-grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 10px;
justify-items: center;
align-items: center;
margin: 0 auto;
}
/* 卡片样式 - 带颜色的水果 */
.card {
aspect-ratio: 1 / 1;
width: 100%;
max-width: 85px;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 2.7rem;
cursor: pointer;
transition: all 0.12s linear;
box-shadow: 0 8px 0 rgba(0,0,0,0.2);
transform: translateY(-2px);
background: radial-gradient(circle at 30% 25%, rgba(255,255,255,0.8), rgba(255,255,255,0.4));
}
/* 各种水果的不同颜色 */
.card[data-fruit="🍎"] { background: linear-gradient(135deg, #ff4d4d, #cc0000); box-shadow: 0 8px 0 #990000; }
.card[data-fruit="🍊"] { background: linear-gradient(135deg, #ffaa33, #ff8800); box-shadow: 0 8px 0 #cc6600; }
.card[data-fruit="🍒"] { background: linear-gradient(135deg, #cc3399, #990066); box-shadow: 0 8px 0 #660044; }
.card[data-fruit="🍓"] { background: linear-gradient(135deg, #ff6699, #ff3366); box-shadow: 0 8px 0 #cc0044; }
.card[data-fruit="🍉"] { background: linear-gradient(135deg, #66cc66, #339933); box-shadow: 0 8px 0 #226622; }
.card[data-fruit="🍑"] { background: linear-gradient(135deg, #ffcc88, #ffaa66); box-shadow: 0 8px 0 #cc8844; }
.card[data-fruit="🍍"] { background: linear-gradient(135deg, #ffdd77, #ffcc44); box-shadow: 0 8px 0 #ccaa33; }
.card[data-fruit="🥝"] { background: linear-gradient(135deg, #88cc44, #66aa33); box-shadow: 0 8px 0 #448822; }
.card[data-fruit="🍌"] { background: linear-gradient(135deg, #ffee88, #ffdd66); box-shadow: 0 8px 0 #ccaa44; }
.card[data-fruit="🍇"] { background: linear-gradient(135deg, #aa66ff, #8844cc); box-shadow: 0 8px 0 #552299; }
.card.selected {
box-shadow: 0 0 0 4px #ffb347, 0 0 0 8px #ffe484, 0 8px 0 rgba(0,0,0,0.2);
transform: scale(0.97) translateY(0px);
}
.card.removed {
visibility: hidden;
pointer-events: none;
box-shadow: none;
transform: scale(0.8);
background: transparent;
}
/* 按钮区域 */
.action-buttons {
margin-top: 25px;
display: flex;
justify-content: center;
gap: 20px;
flex-wrap: wrap;
}
button {
background: #ffb347;
border: none;
font-family: inherit;
font-weight: bold;
font-size: 1.3rem;
padding: 10px 28px;
border-radius: 60px;
color: #3d2a1a;
cursor: pointer;
box-shadow: 0 5px 0 #a45d2e;
transition: 0.07s linear;
display: inline-flex;
align-items: center;
gap: 8px;
}
button:active {
transform: translateY(3px);
box-shadow: 0 2px 0 #a45d2e;
}
.message-area {
margin-top: 20px;
background: #e9dbbc;
border-radius: 40px;
padding: 8px 16px;
font-size: 1.2rem;
font-weight: bold;
color: #674e2c;
min-height: 3.5rem;
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
flex-wrap: wrap;
}
/* 辅助工具 */
@media (max-width: 550px) {
.game-grid {
gap: 6px;
}
.card {
font-size: 2rem;
}
.score-box, .level-box {
font-size: 1rem;
padding: 4px 12px;
}
.score-box span, .level-box span {
font-size: 1.4rem;
}
button {
font-size: 1rem;
padding: 6px 20px;
}
}
footer {
font-size: 0.7rem;
margin-top: 15px;
color: #b48b4b;
}
</style>
</head>
<body>
<div class="game-container">
<div class="info-panel">
<div class="score-box">🍍 积分 <span id="scoreValue">0</span></div>
<div class="level-box">🍎 第 <span id="levelValue">1</span> 关</div>
</div>
<div class="grid-wrapper">
<div class="game-grid" id="gameGrid"></div>
</div>
<div class="action-buttons">
<button id="shuffleBtn">🔄 洗牌</button>
<button id="refreshHintBtn">✨ 提示</button>
</div>
<div class="message-area" id="messageArea">
🍉 点击相同水果,直线/拐两弯连接消除~
</div>
<footer>⭐ 每消除一对+10分 | 清空所有水果自动进入下一关,难度不变 | 🎨 每种水果都有独特颜色</footer>
</div>
<script>
// ---------- 游戏配置 ----------
const ROWS = 6;
const COLS = 6;
// 水果表情库 (丰富可爱,每个都有独特颜色)
const FRUITS = ['🍎', '🍊', '🍒', '🍓', '🍉', '🍑', '🍍', '🥝', '🍌', '🍇'];
// 每一关使用的水果种类数 (保持难度适中,6x6网格每种出现6次)
const FRUIT_TYPES_PER_LEVEL = 6; // 6种水果,每种出现6次 = 36格
let currentLevel = 1;
let currentScore = 0;
let gridData = []; // 二维数组存储水果字符,null表示已消除
let selectedRow = null, selectedCol = null;
// DOM 元素
const gridContainer = document.getElementById('gameGrid');
const scoreSpan = document.getElementById('scoreValue');
const levelSpan = document.getElementById('levelValue');
const messageDiv = document.getElementById('messageArea');
const shuffleBtn = document.getElementById('shuffleBtn');
const hintBtn = document.getElementById('refreshHintBtn');
// 辅助函数: 显示消息
function showMessage(msg, isError = false) {
messageDiv.innerHTML = `${isError ? '⚠️ ' : '🍬 '} ${msg}`;
setTimeout(() => {
if (messageDiv.innerHTML.includes(msg)) {
// 保持一会但是不清空过度消息
}
}, 2000);
}
// 刷新分数UI
function updateScoreUI() {
scoreSpan.innerText = currentScore;
}
// 刷新关卡UI
function updateLevelUI() {
levelSpan.innerText = currentLevel;
}
// 连连看核心算法: 判断两点之间是否能直线或一个拐点/两个拐点消除
function canConnect(row1, col1, row2, col2, data) {
if (row1 === row2 && col1 === col2) return false;
if (data[row1][col1] === null || data[row2][col2] === null) return false;
if (data[row1][col1] !== data[row2][col2]) return false;
const rows = data.length;
const cols = data[0].length;
// 临时检查函数: 水平直线
function checkRowClear(r, cA, cB) {
let minC = Math.min(cA, cB);
let maxC = Math.max(cA, cB);
for (let i = minC + 1; i < maxC; i++) {
if (data[r][i] !== null) return false;
}
return true;
}
// 垂直直线
function checkColClear(c, rA, rB) {
let minR = Math.min(rA, rB);
let maxR = Math.max(rA, rB);
for (let i = minR + 1; i < maxR; i++) {
if (data[i][c] !== null) return false;
}
return true;
}
// 1. 同行直线
if (row1 === row2 && checkRowClear(row1, col1, col2)) return true;
// 同列直线
if (col1 === col2 && checkColClear(col1, row1, row2)) return true;
// 2. 一个拐点
if (data[row1][col2] === null && checkRowClear(row1, col1, col2) && checkColClear(col2, row1, row2)) {
return true;
}
if (data[row2][col1] === null && checkColClear(col1, row1, row2) && checkRowClear(row2, col1, col2)) {
return true;
}
// 3. 两个拐点: 扫描列
for (let i = 0; i < rows; i++) {
if (i !== row1 && i !== row2) {
if (data[i][col1] === null && data[i][col2] === null &&
checkColClear(col1, row1, i) && checkRowClear(i, col1, col2) && checkColClear(col2, i, row2)) {
return true;
}
}
}
// 扫描行
for (let j = 0; j < cols; j++) {
if (j !== col1 && j !== col2) {
if (data[row1][j] === null && data[row2][j] === null &&
checkRowClear(row1, col1, j) && checkColClear(j, row1, row2) && checkRowClear(row2, j, col2)) {
return true;
}
}
}
return false;
}
// 检查是否胜利
function isWin() {
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) return false;
}
}
return true;
}
// 进入下一关
function nextLevel() {
currentLevel++;
updateLevelUI();
initLevelGrid();
clearSelected();
showMessage(`🎉 恭喜过关!进入第 ${currentLevel} 关,继续消除彩色水果吧!`, false);
setTimeout(() => {
if (!hasRemainingMoves()) {
autoShuffleSafe();
showMessage("🃏 没有可消除的对子啦,自动洗牌一次", false);
}
}, 200);
}
// 检测当前是否还有可消除的对
function hasRemainingMoves() {
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) {
for (let m = 0; m < ROWS; m++) {
for (let n = 0; n < COLS; n++) {
if ((i === m && j === n)) continue;
if (gridData[m][n] !== null && gridData[i][j] === gridData[m][n]) {
if (canConnect(i, j, m, n, gridData)) {
return true;
}
}
}
}
}
}
}
return false;
}
// 自动洗牌
function shuffleBoard() {
let fruitsList = [];
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) {
fruitsList.push(gridData[i][j]);
}
}
}
for (let i = fruitsList.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[fruitsList[i], fruitsList[j]] = [fruitsList[j], fruitsList[i]];
}
let idx = 0;
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) {
gridData[i][j] = fruitsList[idx++];
}
}
}
renderGrid();
clearSelected();
showMessage("♻️ 重新洗牌啦,继续挑战彩色水果吧", false);
}
function autoShuffleSafe() {
shuffleBoard();
if (!hasRemainingMoves()) {
shuffleBoard();
}
}
// 提示功能
let hintTimer = null;
function giveHint() {
if (hintTimer) clearTimeout(hintTimer);
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) {
for (let m = 0; m < ROWS; m++) {
for (let n = 0; n < COLS; n++) {
if ((i === m && j === n)) continue;
if (gridData[m][n] !== null && gridData[i][j] === gridData[m][n]) {
if (canConnect(i, j, m, n, gridData)) {
highlightPair(i, j, m, n);
showMessage(`💡 试试消除 ${gridData[i][j]} 吧!`, false);
return;
}
}
}
}
}
}
}
showMessage("🤔 暂时没有可消除的水果,试试洗牌吧!", true);
}
function highlightPair(row1, col1, row2, col2) {
const cards = document.querySelectorAll('.card');
const idx1 = row1 * COLS + col1;
const idx2 = row2 * COLS + col2;
if (cards[idx1] && cards[idx2]) {
cards[idx1].style.boxShadow = "0 0 0 4px gold, 0 0 0 8px #ffb347, 0 8px 0 rgba(0,0,0,0.2)";
cards[idx2].style.boxShadow = "0 0 0 4px gold, 0 0 0 8px #ffb347, 0 8px 0 rgba(0,0,0,0.2)";
if (hintTimer) clearTimeout(hintTimer);
hintTimer = setTimeout(() => {
renderGrid();
}, 1800);
}
}
// 消除一对
function eliminatePair(row1, col1, row2, col2) {
if (!canConnect(row1, col1, row2, col2, gridData)) return false;
gridData[row1][col1] = null;
gridData[row2][col2] = null;
currentScore += 10;
updateScoreUI();
renderGrid();
clearSelected();
showMessage(`🎉 +10分!消除成功!`, false);
if (isWin()) {
showMessage(`✨✨ 太厉害了!通关第 ${currentLevel} 关 ✨✨`, false);
nextLevel();
return true;
}
if (!hasRemainingMoves()) {
autoShuffleSafe();
showMessage("🧹 没有更多消除啦,已经帮你洗牌~", false);
}
return true;
}
function clearSelected() {
selectedRow = null;
selectedCol = null;
renderGrid();
}
// 渲染网格 - 添加data-fruit属性来控制颜色
function renderGrid() {
gridContainer.innerHTML = '';
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
const fruit = gridData[i][j];
const card = document.createElement('div');
card.className = 'card';
if (fruit === null) {
card.classList.add('removed');
card.innerText = '✨';
card.style.fontSize = '2rem';
card.style.opacity = '0.6';
} else {
card.innerText = fruit;
card.setAttribute('data-fruit', fruit);
}
if (selectedRow === i && selectedCol === j && fruit !== null) {
card.classList.add('selected');
}
card.addEventListener('click', (function(r, c) {
return function() { onCardClick(r, c); };
})(i, j));
gridContainer.appendChild(card);
}
}
}
// 点击处理
function onCardClick(row, col) {
if (gridData[row][col] === null) return;
if (selectedRow === null || selectedCol === null) {
selectedRow = row;
selectedCol = col;
renderGrid();
showMessage(`选中 ${gridData[row][col]} ,再点击另一个相同水果消除~`, false);
return;
}
const sRow = selectedRow, sCol = selectedCol;
if (sRow === row && sCol === col) {
clearSelected();
showMessage("已取消选中", false);
return;
}
if (gridData[sRow][sCol] !== null && gridData[row][col] !== null &&
gridData[sRow][sCol] === gridData[row][col] && canConnect(sRow, sCol, row, col, gridData)) {
eliminatePair(sRow, sCol, row, col);
} else {
if (gridData[row][col] !== null) {
if (gridData[sRow][sCol] !== gridData[row][col]) {
showMessage(`🍇 ${gridData[sRow][sCol]} 和 ${gridData[row][col]} 不一样,不能消除哦`, true);
} else {
showMessage(`🚫 路径不通,最多拐两弯~ 再试试洗牌吧`, true);
}
selectedRow = row;
selectedCol = col;
renderGrid();
} else {
clearSelected();
}
}
}
// 初始化关卡网格
function initLevelGrid() {
const totalCells = ROWS * COLS;
const typesCount = FRUIT_TYPES_PER_LEVEL;
const eachCount = totalCells / typesCount;
let fruitPool = [];
for (let i = 0; i < typesCount; i++) {
const fruitChar = FRUITS[i % FRUITS.length];
for (let k = 0; k < eachCount; k++) {
fruitPool.push(fruitChar);
}
}
for (let i = fruitPool.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[fruitPool[i], fruitPool[j]] = [fruitPool[j], fruitPool[i]];
}
gridData = Array(ROWS).fill().map(() => Array(COLS).fill(null));
let idx = 0;
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
gridData[i][j] = fruitPool[idx++];
}
}
if (!hasRemainingMoves()) {
for (let i = 0; i < ROWS && !hasRemainingMoves(); i++) {
for (let j = 0; j < COLS; j++) {
for (let m = 0; m < ROWS; m++) {
for (let n = 0; n < COLS; n++) {
if (gridData[i][j] && gridData[m][n] && (i !== m || j !== n) && gridData[i][j] !== gridData[m][n]) {
let temp = gridData[i][j];
gridData[i][j] = gridData[m][n];
gridData[m][n] = temp;
if (hasRemainingMoves()) break;
else {
let temp2 = gridData[i][j];
gridData[i][j] = gridData[m][n];
gridData[m][n] = temp2;
}
}
}
if (hasRemainingMoves()) break;
}
if (hasRemainingMoves()) break;
}
}
}
}
// 重置游戏
function resetGame() {
currentLevel = 1;
currentScore = 0;
updateScoreUI();
updateLevelUI();
initLevelGrid();
clearSelected();
renderGrid();
showMessage("🍍 彩色水果连连看开始啦!每种水果颜色都不同哦~", false);
if (!hasRemainingMoves()) {
shuffleBoard();
}
}
function onShuffle() {
shuffleBoard();
if (!hasRemainingMoves()) {
shuffleBoard();
showMessage("🔁 再次洗牌保证可玩", false);
}
}
shuffleBtn.addEventListener('click', () => onShuffle());
hintBtn.addEventListener('click', () => giveHint());
resetGame();
</script>
</body>
</html>'''
# 保存到当前目录下的文件
file_path = os.path.join(os.getcwd(), r'D:\test\20桌面素材\20260326水果连连看\02彩色水果连连看_闯关版.html')
try:
with open(file_path, 'w', encoding='utf-8') as f:
f.write(html_content)
print(f'✅ 彩色水果连连看游戏已成功生成!')
print(f'📁 文件保存位置: {file_path}')
print('🎮 游戏特性:')
print(' - 🌈 每种水果都有独特的颜色:苹果红色、橙子橙色、樱桃紫红、草莓粉红、西瓜绿色等')
print(' - 6x6水果连连看,经典的直线/拐弯消除规则')
print(' - 每消除一对水果+10分')
print(' - 清空所有水果自动进入下一关,难度保持不变')
print(' - 支持洗牌和提示功能,避免卡关')
print(' - 适合3-4岁幼儿的彩色水果设计和触摸操作')
print(' - 响应式布局,支持平板和手机')
return file_path
except Exception as e:
print(f'❌ 生成文件失败: {e}')
return None
if __name__ == '__main__':
# 直接运行即可生成HTML文件
generate_fruit_link_game()


它是红色水果,彩色底纹,虽然与我想的不一样(我想要黄色生梨、橘色橘子、紫色葡萄)但是还行,能看到不同颜色的底纹。
最后添加一些音频效果


python
'''
02水果连连看6*6 多个关卡,难度一样
水果是红色,但是彩色背景
增加音频,点按钮有声音,通关后会提示一共多少分
Deepseek,阿夏
202060325
'''
import os
def generate_fruit_link_game():
"""
生成水果连连看游戏HTML文件
包含积分、关卡机制,每关结束后自动进入下一关,难度保持不变
每种水果都有独特的颜色,让游戏更加生动
过关时播放音乐并语音播报得分
"""
html_content = '''<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>彩色水果连连看 - 益智闯关</title>
<style>
* {
user-select: none;
-webkit-tap-highlight-color: transparent;
}
body {
background: linear-gradient(145deg, #1a6d2b 0%, #0e4a1a 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Segoe UI', 'Comic Neue', 'Comic Neue', 'Comic Sans MS', 'Chalkboard SE', cursive, sans-serif;
margin: 0;
padding: 20px;
}
/* 游戏主面板 */
.game-container {
background: #fdf8e7;
border-radius: 72px;
box-shadow: 0 25px 40px rgba(0,0,0,0.3), inset 0 1px 3px rgba(255,255,200,0.8);
padding: 20px 25px 30px 25px;
text-align: center;
transition: all 0.2s;
}
/* 头部信息 */
.info-panel {
display: flex;
justify-content: space-between;
align-items: baseline;
background: #f5e5c8;
padding: 12px 24px;
border-radius: 60px;
margin-bottom: 20px;
gap: 20px;
flex-wrap: wrap;
box-shadow: inset 0 1px 4px rgba(0,0,0,0.05), 0 6px 12px rgba(0,0,0,0.1);
}
.score-box, .level-box {
background: #5a3e2b;
color: #ffefb9;
padding: 8px 20px;
border-radius: 40px;
font-weight: bold;
font-size: 1.5rem;
text-shadow: 0 2px 0 #2e1e12;
box-shadow: inset 0 1px 2px rgba(255,255,200,0.3), 0 4px 8px rgba(0,0,0,0.2);
}
.score-box span, .level-box span {
font-size: 1.8rem;
margin-left: 8px;
color: #ffd966;
}
/* 网格区域 */
.grid-wrapper {
background: #fffaec;
border-radius: 48px;
padding: 20px;
box-shadow: inset 0 0 0 2px #fff9e6, inset 0 0 0 6px #e7dbb8, 0 15px 20px rgba(0,0,0,0.2);
}
.game-grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 10px;
justify-items: center;
align-items: center;
margin: 0 auto;
}
/* 卡片样式 - 带颜色的水果 */
.card {
aspect-ratio: 1 / 1;
width: 100%;
max-width: 85px;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 2.7rem;
cursor: pointer;
transition: all 0.12s linear;
box-shadow: 0 8px 0 rgba(0,0,0,0.2);
transform: translateY(-2px);
background: radial-gradient(circle at 30% 25%, rgba(255,255,255,0.8), rgba(255,255,255,0.4));
}
/* 各种水果的不同颜色 */
.card[data-fruit="🍎"] { background: linear-gradient(135deg, #ff4d4d, #cc0000); box-shadow: 0 8px 0 #990000; }
.card[data-fruit="🍊"] { background: linear-gradient(135deg, #ffaa33, #ff8800); box-shadow: 0 8px 0 #cc6600; }
.card[data-fruit="🍒"] { background: linear-gradient(135deg, #cc3399, #990066); box-shadow: 0 8px 0 #660044; }
.card[data-fruit="🍓"] { background: linear-gradient(135deg, #ff6699, #ff3366); box-shadow: 0 8px 0 #cc0044; }
.card[data-fruit="🍉"] { background: linear-gradient(135deg, #66cc66, #339933); box-shadow: 0 8px 0 #226622; }
.card[data-fruit="🍑"] { background: linear-gradient(135deg, #ffcc88, #ffaa66); box-shadow: 0 8px 0 #cc8844; }
.card[data-fruit="🍍"] { background: linear-gradient(135deg, #ffdd77, #ffcc44); box-shadow: 0 8px 0 #ccaa33; }
.card[data-fruit="🥝"] { background: linear-gradient(135deg, #88cc44, #66aa33); box-shadow: 0 8px 0 #448822; }
.card[data-fruit="🍌"] { background: linear-gradient(135deg, #ffee88, #ffdd66); box-shadow: 0 8px 0 #ccaa44; }
.card[data-fruit="🍇"] { background: linear-gradient(135deg, #aa66ff, #8844cc); box-shadow: 0 8px 0 #552299; }
.card.selected {
box-shadow: 0 0 0 4px #ffb347, 0 0 0 8px #ffe484, 0 8px 0 rgba(0,0,0,0.2);
transform: scale(0.97) translateY(0px);
}
.card.removed {
visibility: hidden;
pointer-events: none;
box-shadow: none;
transform: scale(0.8);
background: transparent;
}
/* 按钮区域 */
.action-buttons {
margin-top: 25px;
display: flex;
justify-content: center;
gap: 20px;
flex-wrap: wrap;
}
button {
background: #ffb347;
border: none;
font-family: inherit;
font-weight: bold;
font-size: 1.3rem;
padding: 10px 28px;
border-radius: 60px;
color: #3d2a1a;
cursor: pointer;
box-shadow: 0 5px 0 #a45d2e;
transition: 0.07s linear;
display: inline-flex;
align-items: center;
gap: 8px;
}
button:active {
transform: translateY(3px);
box-shadow: 0 2px 0 #a45d2e;
}
.message-area {
margin-top: 20px;
background: #e9dbbc;
border-radius: 40px;
padding: 8px 16px;
font-size: 1.2rem;
font-weight: bold;
color: #674e2c;
min-height: 3.5rem;
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
flex-wrap: wrap;
}
/* 辅助工具 */
@media (max-width: 550px) {
.game-grid {
gap: 6px;
}
.card {
font-size: 2rem;
}
.score-box, .level-box {
font-size: 1rem;
padding: 4px 12px;
}
.score-box span, .level-box span {
font-size: 1.4rem;
}
button {
font-size: 1rem;
padding: 6px 20px;
}
}
footer {
font-size: 0.7rem;
margin-top: 15px;
color: #b48b4b;
}
/* 庆祝动画 */
@keyframes celebrate {
0% { transform: scale(1); }
50% { transform: scale(1.1); background: radial-gradient(circle, gold, #ffaa00); }
100% { transform: scale(1); }
}
.celebrate-card {
animation: celebrate 0.5s ease-in-out;
}
</style>
</head>
<body>
<div class="game-container">
<div class="info-panel">
<div class="score-box">🍍 积分 <span id="scoreValue">0</span></div>
<div class="level-box">🍎 第 <span id="levelValue">1</span> 关</div>
</div>
<div class="grid-wrapper">
<div class="game-grid" id="gameGrid"></div>
</div>
<div class="action-buttons">
<button id="shuffleBtn">🔄 洗牌</button>
<button id="refreshHintBtn">✨ 提示</button>
</div>
<div class="message-area" id="messageArea">
🍉 点击相同水果,直线/拐两弯连接消除~
</div>
<footer>⭐ 每消除一对+10分 | 清空所有水果自动进入下一关 | 🎨 每种水果都有独特颜色 | 🎵 过关有音乐和语音庆祝</footer>
</div>
<script>
// ---------- 游戏配置 ----------
const ROWS = 6;
const COLS = 6;
// 水果表情库 (丰富可爱,每个都有独特颜色)
const FRUITS = ['🍎', '🍊', '🍒', '🍓', '🍉', '🍑', '🍍', '🥝', '🍌', '🍇'];
// 每一关使用的水果种类数 (保持难度适中,6x6网格每种出现6次)
const FRUIT_TYPES_PER_LEVEL = 6; // 6种水果,每种出现6次 = 36格
let currentLevel = 1;
let currentScore = 0;
let gridData = []; // 二维数组存储水果字符,null表示已消除
let selectedRow = null, selectedCol = null;
// 音频上下文 (用于播放简单音效)
let audioContext = null;
// DOM 元素
const gridContainer = document.getElementById('gameGrid');
const scoreSpan = document.getElementById('scoreValue');
const levelSpan = document.getElementById('levelValue');
const messageDiv = document.getElementById('messageArea');
const shuffleBtn = document.getElementById('shuffleBtn');
const hintBtn = document.getElementById('refreshHintBtn');
// 播放简单胜利音乐 (使用Web Audio API)
function playVictoryMusic() {
try {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
}
const now = audioContext.currentTime;
// 播放一段欢快的旋律 (C大调音阶)
const notes = [523.25, 587.33, 659.25, 698.46, 783.99, 880.00, 987.77, 1046.50];
const durations = [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.3, 0.5];
notes.forEach((freq, index) => {
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.frequency.value = freq;
oscillator.type = 'sine';
gainNode.gain.setValueAtTime(0.3, now + index * 0.2);
gainNode.gain.exponentialRampToValueAtTime(0.0001, now + (index * 0.2) + durations[index]);
oscillator.start(now + index * 0.2);
oscillator.stop(now + (index * 0.2) + durations[index]);
});
// 添加和弦结尾
const chordOsc = audioContext.createOscillator();
const chordGain = audioContext.createGain();
chordOsc.connect(chordGain);
chordGain.connect(audioContext.destination);
chordOsc.frequency.value = 523.25;
chordOsc.type = 'triangle';
chordGain.gain.setValueAtTime(0.4, now + 1.6);
chordGain.gain.exponentialRampToValueAtTime(0.0001, now + 2.2);
chordOsc.start(now + 1.6);
chordOsc.stop(now + 2.2);
} catch(e) {
console.log('音频播放失败:', e);
}
}
// 播放庆祝音效
function playCheerSound() {
try {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
}
const now = audioContext.currentTime;
// 播放欢快的"叮叮当"音效
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.frequency.value = 880;
oscillator.type = 'sine';
gainNode.gain.setValueAtTime(0.2, now);
gainNode.gain.exponentialRampToValueAtTime(0.0001, now + 0.3);
oscillator.start(now);
oscillator.stop(now + 0.3);
setTimeout(() => {
const osc2 = audioContext.createOscillator();
const gain2 = audioContext.createGain();
osc2.connect(gain2);
gain2.connect(audioContext.destination);
osc2.frequency.value = 1046.5;
osc2.type = 'sine';
gain2.gain.setValueAtTime(0.2, now + 0.3);
gain2.gain.exponentialRampToValueAtTime(0.0001, now + 0.6);
osc2.start(now + 0.3);
osc2.stop(now + 0.6);
}, 300);
} catch(e) {
console.log('庆祝音效播放失败:', e);
}
}
// 语音播报函数
function speak(text) {
if ('speechSynthesis' in window) {
// 停止任何正在进行的语音
window.speechSynthesis.cancel();
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = 'zh-CN';
utterance.rate = 0.9;
utterance.pitch = 1.2;
utterance.volume = 1;
// 选择中文语音
const voices = window.speechSynthesis.getVoices();
const chineseVoice = voices.find(voice => voice.lang === 'zh-CN');
if (chineseVoice) {
utterance.voice = chineseVoice;
}
window.speechSynthesis.speak(utterance);
} else {
console.log('浏览器不支持语音播报');
}
}
// 过关庆祝函数
function celebrateLevelCompletion() {
const levelScore = currentScore;
const message = `恭喜你获得 ${levelScore} 分!`;
// 播放胜利音乐
playVictoryMusic();
// 语音播报
setTimeout(() => {
speak(message);
}, 500);
// 显示庆祝消息
showMessage(`🎉🎉🎉 ${message} 🎉🎉🎉`, false);
// 添加卡片庆祝动画
const cards = document.querySelectorAll('.card:not(.removed)');
cards.forEach((card, index) => {
setTimeout(() => {
card.classList.add('celebrate-card');
setTimeout(() => {
card.classList.remove('celebrate-card');
}, 500);
}, index * 50);
});
}
// 辅助函数: 显示消息
function showMessage(msg, isError = false) {
messageDiv.innerHTML = `${isError ? '⚠️ ' : '🍬 '} ${msg}`;
setTimeout(() => {
if (messageDiv.innerHTML.includes(msg)) {
// 保持一会但是不清空过度消息
}
}, 3000);
}
// 刷新分数UI
function updateScoreUI() {
scoreSpan.innerText = currentScore;
}
// 刷新关卡UI
function updateLevelUI() {
levelSpan.innerText = currentLevel;
}
// 连连看核心算法: 判断两点之间是否能直线或一个拐点/两个拐点消除
function canConnect(row1, col1, row2, col2, data) {
if (row1 === row2 && col1 === col2) return false;
if (data[row1][col1] === null || data[row2][col2] === null) return false;
if (data[row1][col1] !== data[row2][col2]) return false;
const rows = data.length;
const cols = data[0].length;
// 临时检查函数: 水平直线
function checkRowClear(r, cA, cB) {
let minC = Math.min(cA, cB);
let maxC = Math.max(cA, cB);
for (let i = minC + 1; i < maxC; i++) {
if (data[r][i] !== null) return false;
}
return true;
}
// 垂直直线
function checkColClear(c, rA, rB) {
let minR = Math.min(rA, rB);
let maxR = Math.max(rA, rB);
for (let i = minR + 1; i < maxR; i++) {
if (data[i][c] !== null) return false;
}
return true;
}
// 1. 同行直线
if (row1 === row2 && checkRowClear(row1, col1, col2)) return true;
// 同列直线
if (col1 === col2 && checkColClear(col1, row1, row2)) return true;
// 2. 一个拐点
if (data[row1][col2] === null && checkRowClear(row1, col1, col2) && checkColClear(col2, row1, row2)) {
return true;
}
if (data[row2][col1] === null && checkColClear(col1, row1, row2) && checkRowClear(row2, col1, col2)) {
return true;
}
// 3. 两个拐点: 扫描列
for (let i = 0; i < rows; i++) {
if (i !== row1 && i !== row2) {
if (data[i][col1] === null && data[i][col2] === null &&
checkColClear(col1, row1, i) && checkRowClear(i, col1, col2) && checkColClear(col2, i, row2)) {
return true;
}
}
}
// 扫描行
for (let j = 0; j < cols; j++) {
if (j !== col1 && j !== col2) {
if (data[row1][j] === null && data[row2][j] === null &&
checkRowClear(row1, col1, j) && checkColClear(j, row1, row2) && checkRowClear(row2, j, col2)) {
return true;
}
}
}
return false;
}
// 检查是否胜利
function isWin() {
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) return false;
}
}
return true;
}
// 进入下一关
function nextLevel() {
// 先播放庆祝效果
celebrateLevelCompletion();
// 延迟进入下一关,让庆祝效果充分展示
setTimeout(() => {
currentLevel++;
updateLevelUI();
initLevelGrid();
clearSelected();
showMessage(`🎉 进入第 ${currentLevel} 关!继续加油~ 🎉`, false);
setTimeout(() => {
if (!hasRemainingMoves()) {
autoShuffleSafe();
showMessage("🃏 没有可消除的对子啦,自动洗牌一次", false);
}
}, 200);
}, 2000);
}
// 检测当前是否还有可消除的对
function hasRemainingMoves() {
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) {
for (let m = 0; m < ROWS; m++) {
for (let n = 0; n < COLS; n++) {
if ((i === m && j === n)) continue;
if (gridData[m][n] !== null && gridData[i][j] === gridData[m][n]) {
if (canConnect(i, j, m, n, gridData)) {
return true;
}
}
}
}
}
}
}
return false;
}
// 自动洗牌
function shuffleBoard() {
let fruitsList = [];
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) {
fruitsList.push(gridData[i][j]);
}
}
}
for (let i = fruitsList.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[fruitsList[i], fruitsList[j]] = [fruitsList[j], fruitsList[i]];
}
let idx = 0;
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) {
gridData[i][j] = fruitsList[idx++];
}
}
}
renderGrid();
clearSelected();
showMessage("♻️ 重新洗牌啦,继续挑战彩色水果吧", false);
}
function autoShuffleSafe() {
shuffleBoard();
if (!hasRemainingMoves()) {
shuffleBoard();
}
}
// 提示功能
let hintTimer = null;
function giveHint() {
if (hintTimer) clearTimeout(hintTimer);
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) {
for (let m = 0; m < ROWS; m++) {
for (let n = 0; n < COLS; n++) {
if ((i === m && j === n)) continue;
if (gridData[m][n] !== null && gridData[i][j] === gridData[m][n]) {
if (canConnect(i, j, m, n, gridData)) {
highlightPair(i, j, m, n);
showMessage(`💡 试试消除 ${gridData[i][j]} 吧!`, false);
return;
}
}
}
}
}
}
}
showMessage("🤔 暂时没有可消除的水果,试试洗牌吧!", true);
}
function highlightPair(row1, col1, row2, col2) {
const cards = document.querySelectorAll('.card');
const idx1 = row1 * COLS + col1;
const idx2 = row2 * COLS + col2;
if (cards[idx1] && cards[idx2]) {
cards[idx1].style.boxShadow = "0 0 0 4px gold, 0 0 0 8px #ffb347, 0 8px 0 rgba(0,0,0,0.2)";
cards[idx2].style.boxShadow = "0 0 0 4px gold, 0 0 0 8px #ffb347, 0 8px 0 rgba(0,0,0,0.2)";
if (hintTimer) clearTimeout(hintTimer);
hintTimer = setTimeout(() => {
renderGrid();
}, 1800);
}
}
// 消除一对
function eliminatePair(row1, col1, row2, col2) {
if (!canConnect(row1, col1, row2, col2, gridData)) return false;
gridData[row1][col1] = null;
gridData[row2][col2] = null;
currentScore += 10;
updateScoreUI();
renderGrid();
clearSelected();
// 播放消除音效
playCheerSound();
showMessage(`🎉 +10分!消除成功!`, false);
if (isWin()) {
// 胜利时触发过关庆祝
nextLevel();
return true;
}
if (!hasRemainingMoves()) {
autoShuffleSafe();
showMessage("🧹 没有更多消除啦,已经帮你洗牌~", false);
}
return true;
}
function clearSelected() {
selectedRow = null;
selectedCol = null;
renderGrid();
}
// 渲染网格 - 添加data-fruit属性来控制颜色
function renderGrid() {
gridContainer.innerHTML = '';
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
const fruit = gridData[i][j];
const card = document.createElement('div');
card.className = 'card';
if (fruit === null) {
card.classList.add('removed');
card.innerText = '✨';
card.style.fontSize = '2rem';
card.style.opacity = '0.6';
} else {
card.innerText = fruit;
card.setAttribute('data-fruit', fruit);
}
if (selectedRow === i && selectedCol === j && fruit !== null) {
card.classList.add('selected');
}
card.addEventListener('click', (function(r, c) {
return function() { onCardClick(r, c); };
})(i, j));
gridContainer.appendChild(card);
}
}
}
// 点击处理
function onCardClick(row, col) {
if (gridData[row][col] === null) return;
if (selectedRow === null || selectedCol === null) {
selectedRow = row;
selectedCol = col;
renderGrid();
showMessage(`选中 ${gridData[row][col]} ,再点击另一个相同水果消除~`, false);
return;
}
const sRow = selectedRow, sCol = selectedCol;
if (sRow === row && sCol === col) {
clearSelected();
showMessage("已取消选中", false);
return;
}
if (gridData[sRow][sCol] !== null && gridData[row][col] !== null &&
gridData[sRow][sCol] === gridData[row][col] && canConnect(sRow, sCol, row, col, gridData)) {
eliminatePair(sRow, sCol, row, col);
} else {
if (gridData[row][col] !== null) {
if (gridData[sRow][sCol] !== gridData[row][col]) {
showMessage(`🍇 ${gridData[sRow][sCol]} 和 ${gridData[row][col]} 不一样,不能消除哦`, true);
} else {
showMessage(`🚫 路径不通,最多拐两弯~ 再试试洗牌吧`, true);
}
selectedRow = row;
selectedCol = col;
renderGrid();
} else {
clearSelected();
}
}
}
// 初始化关卡网格
function initLevelGrid() {
const totalCells = ROWS * COLS;
const typesCount = FRUIT_TYPES_PER_LEVEL;
const eachCount = totalCells / typesCount;
let fruitPool = [];
for (let i = 0; i < typesCount; i++) {
const fruitChar = FRUITS[i % FRUITS.length];
for (let k = 0; k < eachCount; k++) {
fruitPool.push(fruitChar);
}
}
for (let i = fruitPool.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[fruitPool[i], fruitPool[j]] = [fruitPool[j], fruitPool[i]];
}
gridData = Array(ROWS).fill().map(() => Array(COLS).fill(null));
let idx = 0;
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
gridData[i][j] = fruitPool[idx++];
}
}
if (!hasRemainingMoves()) {
for (let i = 0; i < ROWS && !hasRemainingMoves(); i++) {
for (let j = 0; j < COLS; j++) {
for (let m = 0; m < ROWS; m++) {
for (let n = 0; n < COLS; n++) {
if (gridData[i][j] && gridData[m][n] && (i !== m || j !== n) && gridData[i][j] !== gridData[m][n]) {
let temp = gridData[i][j];
gridData[i][j] = gridData[m][n];
gridData[m][n] = temp;
if (hasRemainingMoves()) break;
else {
let temp2 = gridData[i][j];
gridData[i][j] = gridData[m][n];
gridData[m][n] = temp2;
}
}
}
if (hasRemainingMoves()) break;
}
if (hasRemainingMoves()) break;
}
}
}
}
// 重置游戏
function resetGame() {
currentLevel = 1;
currentScore = 0;
updateScoreUI();
updateLevelUI();
initLevelGrid();
clearSelected();
renderGrid();
showMessage("🍍 彩色水果连连看开始啦!每种水果颜色都不同哦~", false);
if (!hasRemainingMoves()) {
shuffleBoard();
}
// 初始化语音系统
if ('speechSynthesis' in window) {
// 预加载语音
window.speechSynthesis.getVoices();
}
}
function onShuffle() {
shuffleBoard();
if (!hasRemainingMoves()) {
shuffleBoard();
showMessage("🔁 再次洗牌保证可玩", false);
}
}
shuffleBtn.addEventListener('click', () => onShuffle());
hintBtn.addEventListener('click', () => giveHint());
resetGame();
</script>
</body>
</html>'''
# 保存到指定路径
file_path = r'D:\test\20桌面素材\20260326水果连连看\03彩色声音水果连连看_闯关版.html'
# 确保目录存在
os.makedirs(os.path.dirname(file_path), exist_ok=True)
try:
with open(file_path, 'w', encoding='utf-8') as f:
f.write(html_content)
print(f'✅ 彩色水果连连看游戏已成功生成!')
print(f'📁 文件保存位置: {file_path}')
print('🎮 游戏特性:')
print(' - 🌈 每种水果都有独特的颜色:苹果红色、橙子橙色、樱桃紫红、草莓粉红、西瓜绿色等')
print(' - 🎵 过关时播放动听的胜利音乐')
print(' - 🗣️ 过关时语音播报"恭喜你获得X分"')
print(' - 🎉 过关时有卡片庆祝动画效果')
print(' - 6x6水果连连看,经典的直线/拐弯消除规则')
print(' - 每消除一对水果+10分')
print(' - 清空所有水果自动进入下一关,难度保持不变')
print(' - 支持洗牌和提示功能,避免卡关')
print(' - 适合3-4岁幼儿的彩色水果设计和触摸操作')
print(' - 响应式布局,支持平板和手机')
return file_path
except Exception as e:
print(f'❌ 生成文件失败: {e}')
return None
if __name__ == '__main__':
# 直接运行即可生成HTML文件
generate_fruit_link_game()




点击最后两个,下面显示文字"恭喜您获得180分",同时出现声音"恭喜您获得180分"此时页面直接跳到第2关(满屏水果)

20260325小2班幼儿操作

身高够不到顶部的图案

高个子孩子可以点到顶部图案






大部分孩子都够不到顶部图案

把屏幕向下拉




幼儿抢着点,网页会放大、移动位置
因为是触屏,很灵敏,经常误触底部的360杀毒、微信、软件管家等页面会弹出来,遮挡连连看界面,幼儿无法操作。

问题:
1、多个触摸点,导致html网页会移动,放大、幼儿需要滑屏(固定操作界面)
2、其他软件页面会覆盖html页面,影响幼儿操作(关闭微信、杀毒软件。不要有其他弹窗)
3、幼儿都挤上去点击,网页四处跑动,要求幼儿排队,但是6*6的内容太多,幼儿也不熟悉玩法。后续考虑把每一关内容做的少一点,每位幼儿操作快一点。
4、希沃白板不能存储html,今天下载的html到白板里,第二天打开就删除了
5、本次用了中文.html ,结果显示html的文件名是中文或英文都不影响显示效果
在"找影子"中实现了屏幕锁定


python
'''
02水果连连看6*6 多个关卡,难度一样
水果是红色,但是彩色背景
增加音频,
适配笔记本和希沃白板的不同显示屏比例
Deepseek,阿夏
20260324
'''
import os
def generate_fruit_link_game():
"""
生成水果连连看游戏HTML文件
包含积分、关卡机制,每关结束后自动进入下一关,难度保持不变
每种水果都有独特的颜色,让游戏更加生动
过关时播放音乐并语音播报得分
已适配希沃白板:无滚动条、屏幕锁定、完全居中
"""
html_content = '''<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>彩色水果连连看 - 希沃白板适配版</title>
<style>
* {
user-select: none;
-webkit-tap-highlight-color: transparent;
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* 完全锁定屏幕,无滚动条,固定视口 - 完美适配希沃白板 */
html, body {
width: 100%;
height: 100%;
overflow: hidden;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: 0;
padding: 0;
background: linear-gradient(145deg, #1a6d2b 0%, #0e4a1a 100%);
}
body {
display: flex;
justify-content: center;
align-items: center;
font-family: 'Segoe UI', 'Comic Neue', 'Comic Sans MS', 'Chalkboard SE', cursive, sans-serif;
touch-action: none; /* 禁止触摸滚动 */
-ms-touch-action: none;
overflow: hidden;
}
/* 游戏主面板 */
.game-container {
background: #fdf8e7;
border-radius: 56px;
box-shadow: 0 25px 40px rgba(0,0,0,0.3), inset 0 1px 3px rgba(255,255,200,0.8);
padding: 18px 22px 24px 22px;
width: 94%;
max-width: 850px;
height: auto;
max-height: 96vh;
display: flex;
flex-direction: column;
overflow: visible;
transition: all 0.2s;
}
/* 头部信息 */
.info-panel {
display: flex;
justify-content: space-between;
align-items: baseline;
background: #f5e5c8;
padding: 10px 22px;
border-radius: 60px;
margin-bottom: 14px;
gap: 16px;
flex-wrap: wrap;
box-shadow: inset 0 1px 4px rgba(0,0,0,0.05), 0 6px 12px rgba(0,0,0,0.1);
flex-shrink: 0;
}
.score-box, .level-box {
background: #5a3e2b;
color: #ffefb9;
padding: 6px 18px;
border-radius: 40px;
font-weight: bold;
font-size: 1.3rem;
text-shadow: 0 2px 0 #2e1e12;
box-shadow: inset 0 1px 2px rgba(255,255,200,0.3), 0 4px 8px rgba(0,0,0,0.2);
}
.score-box span, .level-box span {
font-size: 1.6rem;
margin-left: 6px;
color: #ffd966;
}
/* 进度条 */
.progress-bar {
margin: 5px 0 12px 0;
background: #e0d6bd;
border-radius: 20px;
height: 8px;
overflow: hidden;
flex-shrink: 0;
}
.progress-fill {
background: linear-gradient(90deg, #ffb347, #ff6b4a);
height: 100%;
width: 0%;
transition: width 0.3s ease;
border-radius: 20px;
}
/* 网格区域 */
.grid-wrapper {
background: #fffaec;
border-radius: 40px;
padding: 14px;
box-shadow: inset 0 0 0 2px #fff9e6, inset 0 0 0 6px #e7dbb8, 0 12px 18px rgba(0,0,0,0.15);
flex-shrink: 1;
overflow: visible;
}
.game-grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 10px;
justify-items: center;
align-items: center;
margin: 0 auto;
}
/* 卡片样式 - 带颜色的水果 */
.card {
aspect-ratio: 1 / 1;
width: 100%;
max-width: 92px;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 2.6rem;
cursor: pointer;
transition: all 0.12s linear;
box-shadow: 0 7px 0 rgba(0,0,0,0.2);
transform: translateY(-2px);
background: radial-gradient(circle at 30% 25%, rgba(255,255,255,0.8), rgba(255,255,255,0.4));
touch-action: manipulation;
}
/* 各种水果的不同颜色 */
.card[data-fruit="🍎"] { background: linear-gradient(135deg, #ff4d4d, #cc0000); box-shadow: 0 7px 0 #990000; }
.card[data-fruit="🍊"] { background: linear-gradient(135deg, #ffaa33, #ff8800); box-shadow: 0 7px 0 #cc6600; }
.card[data-fruit="🍒"] { background: linear-gradient(135deg, #cc3399, #990066); box-shadow: 0 7px 0 #660044; }
.card[data-fruit="🍓"] { background: linear-gradient(135deg, #ff6699, #ff3366); box-shadow: 0 7px 0 #cc0044; }
.card[data-fruit="🍉"] { background: linear-gradient(135deg, #66cc66, #339933); box-shadow: 0 7px 0 #226622; }
.card[data-fruit="🍑"] { background: linear-gradient(135deg, #ffcc88, #ffaa66); box-shadow: 0 7px 0 #cc8844; }
.card[data-fruit="🍍"] { background: linear-gradient(135deg, #ffdd77, #ffcc44); box-shadow: 0 7px 0 #ccaa33; }
.card[data-fruit="🥝"] { background: linear-gradient(135deg, #88cc44, #66aa33); box-shadow: 0 7px 0 #448822; }
.card[data-fruit="🍌"] { background: linear-gradient(135deg, #ffee88, #ffdd66); box-shadow: 0 7px 0 #ccaa44; }
.card[data-fruit="🍇"] { background: linear-gradient(135deg, #aa66ff, #8844cc); box-shadow: 0 7px 0 #552299; }
.card.selected {
box-shadow: 0 0 0 4px #ffb347, 0 0 0 8px #ffe484, 0 7px 0 rgba(0,0,0,0.2);
transform: scale(0.97) translateY(0px);
}
.card.removed {
visibility: hidden;
pointer-events: none;
box-shadow: none;
transform: scale(0.8);
background: transparent;
}
/* 按钮区域 */
.action-buttons {
margin-top: 16px;
display: flex;
justify-content: center;
gap: 20px;
flex-wrap: wrap;
flex-shrink: 0;
}
button {
background: #ffb347;
border: none;
font-family: inherit;
font-weight: bold;
font-size: 1.15rem;
padding: 8px 26px;
border-radius: 60px;
color: #3d2a1a;
cursor: pointer;
box-shadow: 0 5px 0 #a45d2e;
transition: 0.07s linear;
touch-action: manipulation;
}
button:active {
transform: translateY(3px);
box-shadow: 0 2px 0 #a45d2e;
}
.message-area {
margin-top: 12px;
background: #e9dbbc;
border-radius: 40px;
padding: 8px 14px;
font-size: 1rem;
font-weight: bold;
color: #674e2c;
min-height: 3rem;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
flex-wrap: wrap;
text-align: center;
flex-shrink: 0;
}
footer {
font-size: 0.68rem;
margin-top: 10px;
color: #b48b4b;
text-align: center;
flex-shrink: 0;
}
/* 庆祝动画 */
@keyframes celebrate {
0% { transform: scale(1); }
50% { transform: scale(1.1); background: radial-gradient(circle, gold, #ffaa00); }
100% { transform: scale(1); }
}
.celebrate-card {
animation: celebrate 0.5s ease-in-out;
}
/* 响应式 - 完美适配希沃白板和各种屏幕比例 */
@media (max-width: 750px) {
.game-grid {
gap: 8px;
}
.card {
font-size: 2.2rem;
}
.info-panel {
padding: 6px 16px;
}
.score-box, .level-box {
font-size: 1rem;
padding: 4px 14px;
}
.score-box span, .level-box span {
font-size: 1.3rem;
}
button {
font-size: 1rem;
padding: 6px 20px;
}
}
@media (max-width: 580px) {
.game-grid {
gap: 6px;
}
.card {
font-size: 1.9rem;
}
.grid-wrapper {
padding: 8px;
}
.game-container {
padding: 12px 15px;
}
}
@media (max-height: 700px) {
.game-container {
padding: 12px 18px;
}
.card {
font-size: 2rem;
}
.action-buttons {
margin-top: 10px;
}
.message-area {
min-height: 2.6rem;
font-size: 0.9rem;
}
}
</style>
</head>
<body>
<div class="game-container">
<div class="info-panel">
<div class="score-box">🍍 积分 <span id="scoreValue">0</span></div>
<div class="level-box">🍎 第 <span id="levelValue">1</span> 关</div>
</div>
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<div class="grid-wrapper">
<div class="game-grid" id="gameGrid"></div>
</div>
<div class="action-buttons">
<button id="shuffleBtn">🔄 洗牌</button>
<button id="refreshHintBtn">✨ 提示</button>
</div>
<div class="message-area" id="messageArea">
🍉 点击相同水果,直线/拐两弯连接消除~
</div>
<footer>⭐ 每消除一对+10分 | 清空所有水果自动进入下一关 | 🎨 每种水果都有独特颜色 | 🎵 过关有音乐和语音庆祝</footer>
</div>
<script>
// ---------- 完全锁定屏幕滚动 (无滚动条,适配希沃白板) ----------
(function lockScreen() {
// 禁止触摸移动导致页面滚动
document.body.addEventListener('touchmove', function(e) {
e.preventDefault();
}, { passive: false });
// 禁止鼠标滚轮滚动
document.body.addEventListener('wheel', function(e) {
e.preventDefault();
}, { passive: false });
// 禁止键盘方向键滚动
window.addEventListener('keydown', function(e) {
const keys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'PageUp', 'PageDown', 'Home', 'End', ' ', 'Space'];
if (keys.includes(e.key) || e.key === ' ') {
e.preventDefault();
}
});
// 禁止页面滚动条 (双重保险)
document.documentElement.style.overflow = 'hidden';
document.body.style.overflow = 'hidden';
})();
// ---------- 游戏配置 ----------
const ROWS = 6;
const COLS = 6;
// 水果表情库 (丰富可爱,每个都有独特颜色)
const FRUITS = ['🍎', '🍊', '🍒', '🍓', '🍉', '🍑', '🍍', '🥝', '🍌', '🍇'];
// 每一关使用的水果种类数 (保持难度适中,6x6网格每种出现6次)
const FRUIT_TYPES_PER_LEVEL = 6; // 6种水果,每种出现6次 = 36格
let currentLevel = 1;
let currentScore = 0;
let gridData = []; // 二维数组存储水果字符,null表示已消除
let selectedRow = null, selectedCol = null;
// 音频上下文 (用于播放简单音效)
let audioContext = null;
// DOM 元素
const gridContainer = document.getElementById('gameGrid');
const scoreSpan = document.getElementById('scoreValue');
const levelSpan = document.getElementById('levelValue');
const messageDiv = document.getElementById('messageArea');
const shuffleBtn = document.getElementById('shuffleBtn');
const hintBtn = document.getElementById('refreshHintBtn');
const progressFill = document.getElementById('progressFill');
// 更新进度条
function updateProgress() {
let percent = ((currentLevel - 1) % 20) / 20 * 100;
if (currentLevel <= 20) percent = ((currentLevel - 1) / 20) * 100;
progressFill.style.width = `${Math.min(100, percent)}%`;
}
// 播放简单胜利音乐
function playVictoryMusic() {
try {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
if (audioContext.state === 'suspended') audioContext.resume();
}
const now = audioContext.currentTime;
const notes = [523.25, 587.33, 659.25, 698.46, 783.99, 880.00, 987.77, 1046.50];
const durations = [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.3, 0.5];
notes.forEach((freq, index) => {
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.frequency.value = freq;
oscillator.type = 'sine';
gainNode.gain.setValueAtTime(0.3, now + index * 0.2);
gainNode.gain.exponentialRampToValueAtTime(0.0001, now + (index * 0.2) + durations[index]);
oscillator.start(now + index * 0.2);
oscillator.stop(now + (index * 0.2) + durations[index]);
});
const chordOsc = audioContext.createOscillator();
const chordGain = audioContext.createGain();
chordOsc.connect(chordGain);
chordGain.connect(audioContext.destination);
chordOsc.frequency.value = 523.25;
chordOsc.type = 'triangle';
chordGain.gain.setValueAtTime(0.4, now + 1.6);
chordGain.gain.exponentialRampToValueAtTime(0.0001, now + 2.2);
chordOsc.start(now + 1.6);
chordOsc.stop(now + 2.2);
} catch(e) {
console.log('音频播放失败:', e);
}
}
// 播放庆祝音效 (点击按钮和消除时)
function playCheerSound() {
try {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
if (audioContext.state === 'suspended') audioContext.resume();
}
const now = audioContext.currentTime;
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.frequency.value = 880;
oscillator.type = 'sine';
gainNode.gain.setValueAtTime(0.2, now);
gainNode.gain.exponentialRampToValueAtTime(0.0001, now + 0.3);
oscillator.start(now);
oscillator.stop(now + 0.3);
} catch(e) {
console.log('庆祝音效播放失败:', e);
}
}
// 语音播报函数
function speak(text) {
if ('speechSynthesis' in window) {
window.speechSynthesis.cancel();
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = 'zh-CN';
utterance.rate = 0.9;
utterance.pitch = 1.2;
utterance.volume = 1;
const voices = window.speechSynthesis.getVoices();
const chineseVoice = voices.find(voice => voice.lang === 'zh-CN');
if (chineseVoice) utterance.voice = chineseVoice;
window.speechSynthesis.speak(utterance);
}
}
// 过关庆祝函数
function celebrateLevelCompletion() {
const message = `恭喜过关!当前总得分 ${currentScore} 分!`;
playVictoryMusic();
setTimeout(() => speak(message), 300);
showMessage(`🎉🎉🎉 ${message} 🎉🎉🎉`, false);
const cards = document.querySelectorAll('.card:not(.removed)');
cards.forEach((card, index) => {
setTimeout(() => {
card.classList.add('celebrate-card');
setTimeout(() => card.classList.remove('celebrate-card'), 500);
}, index * 50);
});
}
function showMessage(msg, isError = false) {
messageDiv.innerHTML = `${isError ? '⚠️ ' : '🍬 '} ${msg}`;
setTimeout(() => {}, 3000);
}
function updateScoreUI() {
scoreSpan.innerText = currentScore;
}
function updateLevelUI() {
levelSpan.innerText = currentLevel;
updateProgress();
}
// 连连看核心算法
function canConnect(row1, col1, row2, col2, data) {
if (row1 === row2 && col1 === col2) return false;
if (data[row1][col1] === null || data[row2][col2] === null) return false;
if (data[row1][col1] !== data[row2][col2]) return false;
const rows = data.length;
const cols = data[0].length;
function checkRowClear(r, cA, cB) {
let minC = Math.min(cA, cB), maxC = Math.max(cA, cB);
for (let i = minC + 1; i < maxC; i++) if (data[r][i] !== null) return false;
return true;
}
function checkColClear(c, rA, rB) {
let minR = Math.min(rA, rB), maxR = Math.max(rA, rB);
for (let i = minR + 1; i < maxR; i++) if (data[i][c] !== null) return false;
return true;
}
if (row1 === row2 && checkRowClear(row1, col1, col2)) return true;
if (col1 === col2 && checkColClear(col1, row1, row2)) return true;
if (data[row1][col2] === null && checkRowClear(row1, col1, col2) && checkColClear(col2, row1, row2)) return true;
if (data[row2][col1] === null && checkColClear(col1, row1, row2) && checkRowClear(row2, col1, col2)) return true;
for (let i = 0; i < rows; i++) {
if (i !== row1 && i !== row2 && data[i][col1] === null && data[i][col2] === null &&
checkColClear(col1, row1, i) && checkRowClear(i, col1, col2) && checkColClear(col2, i, row2)) return true;
}
for (let j = 0; j < cols; j++) {
if (j !== col1 && j !== col2 && data[row1][j] === null && data[row2][j] === null &&
checkRowClear(row1, col1, j) && checkColClear(j, row1, row2) && checkRowClear(row2, j, col2)) return true;
}
return false;
}
function isWin() {
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) return false;
}
}
return true;
}
function hasRemainingMoves() {
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) {
for (let m = 0; m < ROWS; m++) {
for (let n = 0; n < COLS; n++) {
if ((i === m && j === n)) continue;
if (gridData[m][n] !== null && gridData[i][j] === gridData[m][n] && canConnect(i, j, m, n, gridData)) {
return true;
}
}
}
}
}
}
return false;
}
function shuffleBoard() {
let fruitsList = [];
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) fruitsList.push(gridData[i][j]);
}
}
for (let i = fruitsList.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[fruitsList[i], fruitsList[j]] = [fruitsList[j], fruitsList[i]];
}
let idx = 0;
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) gridData[i][j] = fruitsList[idx++];
}
}
renderGrid();
clearSelected();
showMessage("♻️ 重新洗牌啦,继续挑战彩色水果吧", false);
playCheerSound();
}
let hintTimer = null;
function giveHint() {
if (hintTimer) clearTimeout(hintTimer);
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (gridData[i][j] !== null) {
for (let m = 0; m < ROWS; m++) {
for (let n = 0; n < COLS; n++) {
if ((i === m && j === n)) continue;
if (gridData[m][n] !== null && gridData[i][j] === gridData[m][n] && canConnect(i, j, m, n, gridData)) {
highlightPair(i, j, m, n);
showMessage(`💡 试试消除 ${gridData[i][j]} 吧!`, false);
playCheerSound();
return;
}
}
}
}
}
}
showMessage("🤔 暂时没有可消除的水果,试试洗牌吧!", true);
}
function highlightPair(row1, col1, row2, col2) {
const cards = document.querySelectorAll('.card');
const idx1 = row1 * COLS + col1;
const idx2 = row2 * COLS + col2;
if (cards[idx1] && cards[idx2]) {
cards[idx1].style.boxShadow = "0 0 0 4px gold, 0 0 0 8px #ffb347, 0 7px 0 rgba(0,0,0,0.2)";
cards[idx2].style.boxShadow = "0 0 0 4px gold, 0 0 0 8px #ffb347, 0 7px 0 rgba(0,0,0,0.2)";
hintTimer = setTimeout(() => renderGrid(), 1800);
}
}
function eliminatePair(row1, col1, row2, col2) {
if (!canConnect(row1, col1, row2, col2, gridData)) return false;
gridData[row1][col1] = null;
gridData[row2][col2] = null;
currentScore += 10;
updateScoreUI();
renderGrid();
clearSelected();
playCheerSound();
showMessage(`🎉 +10分!消除成功!`, false);
if (isWin()) {
celebrateLevelCompletion();
setTimeout(() => {
currentLevel++;
updateLevelUI();
initLevelGrid();
clearSelected();
showMessage(`🎉 进入第 ${currentLevel} 关!继续加油~ 🎉`, false);
setTimeout(() => {
if (!hasRemainingMoves()) shuffleBoard();
}, 200);
}, 2000);
return true;
}
if (!hasRemainingMoves()) {
setTimeout(() => {
if (!hasRemainingMoves()) shuffleBoard();
}, 200);
}
return true;
}
function clearSelected() {
selectedRow = null;
selectedCol = null;
renderGrid();
}
function renderGrid() {
gridContainer.innerHTML = '';
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
const fruit = gridData[i][j];
const card = document.createElement('div');
card.className = 'card';
if (fruit === null) {
card.classList.add('removed');
card.innerText = '✨';
card.style.fontSize = '2rem';
card.style.opacity = '0.6';
} else {
card.innerText = fruit;
card.setAttribute('data-fruit', fruit);
}
if (selectedRow === i && selectedCol === j && fruit !== null) {
card.classList.add('selected');
}
card.addEventListener('click', (function(r, c) {
return function() { onCardClick(r, c); };
})(i, j));
gridContainer.appendChild(card);
}
}
}
function onCardClick(row, col) {
if (gridData[row][col] === null) return;
playCheerSound();
if (selectedRow === null || selectedCol === null) {
selectedRow = row;
selectedCol = col;
renderGrid();
showMessage(`选中 ${gridData[row][col]} ,再点击另一个相同水果消除~`, false);
return;
}
const sRow = selectedRow, sCol = selectedCol;
if (sRow === row && sCol === col) {
clearSelected();
showMessage("已取消选中", false);
return;
}
if (gridData[sRow][sCol] !== null && gridData[row][col] !== null &&
gridData[sRow][sCol] === gridData[row][col] && canConnect(sRow, sCol, row, col, gridData)) {
eliminatePair(sRow, sCol, row, col);
} else {
if (gridData[row][col] !== null) {
if (gridData[sRow][sCol] !== gridData[row][col]) {
showMessage(`🍇 ${gridData[sRow][sCol]} 和 ${gridData[row][col]} 不一样,不能消除哦`, true);
} else {
showMessage(`🚫 路径不通,最多拐两弯~ 再试试洗牌吧`, true);
}
selectedRow = row;
selectedCol = col;
renderGrid();
} else {
clearSelected();
}
}
}
function initLevelGrid() {
const totalCells = ROWS * COLS;
const typesCount = FRUIT_TYPES_PER_LEVEL;
const eachCount = totalCells / typesCount;
let fruitPool = [];
for (let i = 0; i < typesCount; i++) {
const fruitChar = FRUITS[i % FRUITS.length];
for (let k = 0; k < eachCount; k++) fruitPool.push(fruitChar);
}
for (let i = fruitPool.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[fruitPool[i], fruitPool[j]] = [fruitPool[j], fruitPool[i]];
}
gridData = Array(ROWS).fill().map(() => Array(COLS).fill(null));
let idx = 0;
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
gridData[i][j] = fruitPool[idx++];
}
}
if (!hasRemainingMoves()) shuffleBoard();
}
function resetGame() {
currentLevel = 1;
currentScore = 0;
updateScoreUI();
updateLevelUI();
initLevelGrid();
clearSelected();
showMessage("🍍 彩色水果连连看开始啦!每种水果颜色都不同哦~", false);
if (!hasRemainingMoves()) shuffleBoard();
if ('speechSynthesis' in window) window.speechSynthesis.getVoices();
}
shuffleBtn.addEventListener('click', () => { shuffleBoard(); });
hintBtn.addEventListener('click', () => { giveHint(); });
resetGame();
</script>
</body>
</html>'''
# 保存到指定路径
file_path = r'D:\test\20桌面素材\20260326水果连连看\04 锁定屏幕,彩色声音水果连连看_希沃白板适配版.html'
# 确保目录存在
os.makedirs(os.path.dirname(file_path), exist_ok=True)
try:
with open(file_path, 'w', encoding='utf-8') as f:
f.write(html_content)
print(f'✅ 彩色水果连连看游戏已成功生成!')
print(f'📁 文件保存位置: {file_path}')
print('🎮 游戏特性:')
print(' - 🔒 屏幕完全锁定,无滚动条,完美适配希沃白板')
print(' - 🌈 每种水果都有独特的颜色:苹果红色、橙子橙色、樱桃紫红、草莓粉红、西瓜绿色等')
print(' - 🎵 点击按钮和消除时有音效,过关时播放动听的胜利音乐')
print(' - 🗣️ 过关时语音播报"恭喜过关!当前总得分X分"')
print(' - 🎉 过关时有卡片庆祝动画效果')
print(' - 6x6水果连连看,经典的直线/拐弯消除规则')
print(' - 每消除一对水果+10分')
print(' - 清空所有水果自动进入下一关,难度保持不变')
print(' - 支持洗牌和提示功能,避免卡关')
print(' - 进度条显示闯关进度')
print(' - 响应式布局,完美支持希沃白板、平板和手机')
return file_path
except Exception as e:
print(f'❌ 生成文件失败: {e}')
return None
if __name__ == '__main__':
# 直接运行即可生成HTML文件
generate_fruit_link_game()
撑满屏幕,无滚动条,但是很高,矮个子估计点不到顶部图案