纸牌接龙是一个经典的单人纸牌游戏,玩家需要按照一定的规则将纸牌排成一堆,并完成接龙。通常,游戏规则要求玩家根据纸牌的点数和花色进行排列,从而逐步完成接龙。尽管规则简单,纸牌的自动排序和发放以及操作逻辑的实现却需要一定的复杂性,尤其是在处理牌堆和规则检查时。
过去,制作一个纸牌接龙游戏需要编写发牌、排序和判断的代码,确保游戏的逻辑和UI能够流畅地运行。但现在,通过 Trae IDE,只需要输入简单的指令,Trae 就能够自动帮我完成所有复杂的游戏逻辑和UI设计。接下来,我将分享如何通过 Trae 快速生成一个纸牌接龙游戏,让玩家轻松体验这款经典纸牌游戏。
💡 我的需求其实很简单
我的需求非常明确:制作一个纸牌接龙游戏,功能要求如下:
- 纸牌发放:游戏开始时,纸牌会自动发放到指定位置。规则排列:玩家按规则排列纸牌,通常是按照点数从大到小,交替的红黑花色排列。自动排序:当玩家完成一部分排列时,纸牌会自动移动到正确的顺序。游戏完成:当所有纸牌正确排列完成时,游戏自动判定完成接龙。简洁的UI设计:游戏界面直观,操作简单,纸牌发放和排序清晰明了。
虽然规则看起来简单,但涉及到纸牌的发放、排序、移动和判断等操作,手动实现这些功能依然需要不少的时间。
✨ Trae 如何理解需求并生成代码?
我只需要在 Trae 中输入一句话:
“生成接龙游戏,玩家按规则排列纸牌,最终完成接龙。”
Trae 会自动解析我的需求,并生成完整的纸牌接龙游戏代码,包括:
- 纸牌发放:游戏开始时,纸牌会按照指定规则自动发放到桌面上的不同位置。纸牌排序:玩家按照接龙规则排列纸牌,纸牌会自动按点数和花色排序。游戏规则确保纸牌的排列顺序正确。自动化操作:当玩家操作时,纸牌会自动进行排序和移动,确保游戏逻辑流畅运行。胜利判定:当玩家成功完成接龙后,系统会判定游戏胜利并显示“游戏完成”的提示。简洁的UI设计:游戏界面设计简洁,纸牌的排列和操作非常直观,玩家可以轻松完成接龙任务。
通过简单的指令,Trae 就能为我自动生成一个完整的纸牌接龙游戏,并处理所有复杂的操作和逻辑。
🧩 游戏操作简便,玩法清晰
Trae 生成的纸牌接龙游戏操作非常直观,玩家只需点击纸牌并拖动到正确的位置,游戏会根据规则自动排列纸牌。每次移动纸牌,游戏界面都会即时更新,确保玩家能够清晰看到纸牌的排序进展。
如果玩家完成了某部分接龙,纸牌会自动整理并移动到新的位置,玩家不需要手动去整理纸牌,操作十分流畅。
🛠 游戏拓展,功能轻松加
虽然 Trae 生成的纸牌接龙游戏已经非常完备,但它也支持轻松添加更多功能。例如:
- 多种接龙模式:可以增加不同的接龙玩法,如四堆接龙、空位接龙等,给玩家提供更多的挑战。计时器功能:为游戏加入计时器,记录玩家完成接龙的时间,增加游戏的竞技性。得分系统:可以根据玩家完成接龙的速度和完成度来给出分数。音效和动画:为纸牌的发放、排序和移动添加动画和音效,使游戏更具互动性。
这些新功能都可以通过简单描述,Trae 会自动生成并将它们集成到现有的游戏中。
这就是纸牌接龙游戏开发的新体验
通过这次纸牌接龙游戏的开发,我深刻感受到了 Trae 带来的便利。从纸牌的发放,到玩家的操作,再到排序和判定,Trae 都能够自动帮我完成。这不仅节省了大量开发时间,也提高了开发效率,让我可以更专注于游戏设计和功能扩展。
对于独立开发者或小团队来说,Trae 是一个非常高效的工具,它帮助你将繁琐的逻辑和操作自动化,让你专注于创意和优化。
结语
如果你也想制作一个经典的纸牌接龙游戏,试试 Trae IDE,输入类似的需求:
“生成接龙游戏,玩家按规则排列纸牌,最终完成接龙。”
几秒钟内,Trae 就会生成完整的纸牌接龙游戏代码,带有纸牌发放、排序、玩家操作和胜利判定等功能。你可以直接将它嵌入到你的项目中,甚至根据需求继续扩展和优化。
快来体验一下 Trae,让你的纸牌接龙游戏开发变得更加轻松、有趣!
<!DOCTYPE html><html lang="zh-CN"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>纸牌接龙游戏</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: Arial, sans-serif; background-color: #076324; color: white; padding: 20px; } .game-container { max-width: 1000px; margin: 0 auto; } .header { display: flex; justify-content: space-between; margin-bottom: 20px; align-items: center; } .title { font-size: 24px; font-weight: bold; } .controls button { padding: 8px 16px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; margin-left: 10px; } .controls button:hover { background-color: #45a049; } .game-area { display: grid; grid-template-rows: auto auto; gap: 20px; } .top-row { display: grid; grid-template-columns: repeat(8, 1fr); gap: 10px; } .bottom-row { display: grid; grid-template-columns: repeat(7, 1fr); gap: 10px; } .card-slot { background-color: rgba(0, 0, 0, 0.2); border: 2px dashed rgba(255, 255, 255, 0.3); border-radius: 8px; height: 120px; position: relative; } .foundation { background-color: rgba(0, 100, 0, 0.5); } .tableau { min-height: 300px; } .card { width: 80px; height: 120px; background-color: white; border-radius: 8px; position: absolute; cursor: pointer; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); transition: all 0.2s ease; user-select: none; } .card:hover { transform: translateY(-5px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); } .card.red { color: red; } .card.black { color: black; } .card-content { display: flex; flex-direction: column; height: 100%; padding: 5px; } .card-value { font-size: 16px; font-weight: bold; } .card-suit { font-size: 16px; } .card-center { display: flex; justify-content: center; align-items: center; flex-grow: 1; font-size: 30px; } .card-back { background-color: #2980b9; background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.1) 10px, transparent 10px, transparent 20px); } .card.dragging { opacity: 0.8; z-index: 1000; } .message { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: rgba(0, 0, 0, 0.8); color: white; padding: 20px; border-radius: 10px; text-align: center; display: none; z-index: 2000; } .message h2 { margin-bottom: 15px; } .message button { padding: 8px 16px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; margin-top: 10px; } .timer { font-size: 18px; margin-right: 20px; } .moves { font-size: 18px; } </style></head><body> <div class="game-container"> <div class="header"> <div class="title">纸牌接龙</div> <div class="stats"> <span class="timer">时间: 00:00</span> <span class="moves">移动次数: 0</span> </div> <div class="controls"> <button id="new-game">新游戏</button> <button id="undo">撤销</button> <button id="hint">提示</button> </div> </div> <div class="game-area"> <div class="top-row"> <div class="card-slot stock" id="stock"></div> <div class="card-slot waste" id="waste"></div> <div class="card-slot placeholder"></div> <div class="card-slot foundation" id="foundation-0"></div> <div class="card-slot foundation" id="foundation-1"></div> <div class="card-slot foundation" id="foundation-2"></div> <div class="card-slot foundation" id="foundation-3"></div> </div> <div class="bottom-row"> <div class="card-slot tableau" id="tableau-0"></div> <div class="card-slot tableau" id="tableau-1"></div> <div class="card-slot tableau" id="tableau-2"></div> <div class="card-slot tableau" id="tableau-3"></div> <div class="card-slot tableau" id="tableau-4"></div> <div class="card-slot tableau" id="tableau-5"></div> <div class="card-slot tableau" id="tableau-6"></div> </div> </div> </div> <div class="message" id="win-message"> <h2>恭喜你赢了!</h2> <p>你用了 <span id="final-time"></span> 和 <span id="final-moves"></span> 次移动完成了游戏</p> <button id="play-again">再玩一次</button> </div> <script> document.addEventListener('DOMContentLoaded', () => { // 游戏状态变量 let deck = []; let stock = []; let waste = []; let foundations = [[], [], [], []]; let tableaus = [[], [], [], [], [], [], []]; let selectedCard = null; let selectedStack = []; let selectedSource = null; let moves = 0; let seconds = 0; let timerInterval = null; let moveHistory = []; let isDragging = false; let draggedCard = null; let draggedCards = []; let startX, startY; let offsetX, offsetY; // DOM 元素 const stockElement = document.getElementById('stock'); const wasteElement = document.getElementById('waste'); const foundationElements = [ document.getElementById('foundation-0'), document.getElementById('foundation-1'), document.getElementById('foundation-2'), document.getElementById('foundation-3') ]; const tableauElements = [ document.getElementById('tableau-0'), document.getElementById('tableau-1'), document.getElementById('tableau-2'), document.getElementById('tableau-3'), document.getElementById('tableau-4'), document.getElementById('tableau-5'), document.getElementById('tableau-6') ]; const timerElement = document.querySelector('.timer'); const movesElement = document.querySelector('.moves'); const newGameButton = document.getElementById('new-game'); const undoButton = document.getElementById('undo'); const hintButton = document.getElementById('hint'); const winMessage = document.getElementById('win-message'); const finalTimeElement = document.getElementById('final-time'); const finalMovesElement = document.getElementById('final-moves'); const playAgainButton = document.getElementById('play-again'); // 初始化游戏 initGame(); // 事件监听器 newGameButton.addEventListener('click', initGame); undoButton.addEventListener('click', undoMove); hintButton.addEventListener('click', showHint); playAgainButton.addEventListener('click', () => { winMessage.style.display = 'none'; initGame(); }); stockElement.addEventListener('click', dealFromStock); // 初始化游戏函数 function initGame() { // 重置游戏状态 deck = createDeck(); stock = [...deck]; waste = []; foundations = [[], [], [], []]; tableaus = [[], [], [], [], [], [], []]; selectedCard = null; selectedStack = []; selectedSource = null; moves = 0; seconds = 0; moveHistory = []; updateMovesDisplay(); // 清除计时器并重置 if (timerInterval) { clearInterval(timerInterval); } timerInterval = setInterval(updateTimer, 1000); updateTimerDisplay(); // 洗牌 shuffleDeck(stock); // 发牌到tableau dealInitialCards(); // 渲染游戏 renderGame(); // 添加事件监听器 addEventListeners(); } // 创建一副牌 function createDeck() { const suits = ['♥', '♦', '♠', '♣']; const values = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']; const deck = []; for (let suit of suits) { const color = (suit === '♥' || suit === '♦') ? 'red' : 'black'; for (let i = 0; i < values.length; i++) { deck.push({ suit, value: values[i], color, rank: i + 1, faceUp: false, id: `${values[i]}-${suit}` }); } } return deck; } // 洗牌函数 function shuffleDeck(deck) { for (let i = deck.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [deck[i], deck[j]] = [deck[j], deck[i]]; } } // 发初始牌 function dealInitialCards() { for (let i = 0; i < 7; i++) { for (let j = i; j < 7; j++) { const card = stock.pop(); if (i === j) { card.faceUp = true; } tableaus[j].push(card); } } } // 从stock发牌 function dealFromStock() { if (stock.length === 0) { // 如果stock为空,将waste中的牌放回stock if (waste.length > 0) { stock = waste.reverse(); waste = []; stock.forEach(card => card.faceUp = false); renderGame(); } return; } // 记录移动历史 recordMove({ type: 'dealFromStock', stockLength: stock.length, wasteLength: waste.length }); // 从stock顶部取一张牌放到waste const card = stock.pop(); card.faceUp = true; waste.push(card); moves++; updateMovesDisplay(); renderGame(); } // 渲染游戏 function renderGame() { // 清空所有区域 stockElement.innerHTML = ''; wasteElement.innerHTML = ''; foundationElements.forEach(el => el.innerHTML = ''); tableauElements.forEach(el => el.innerHTML = ''); // 渲染stock if (stock.length > 0) { const cardElement = createCardElement({ faceUp: false }); stockElement.appendChild(cardElement); } // 渲染waste if (waste.length > 0) { const topCard = waste[waste.length - 1]; const cardElement = createCardElement(topCard); cardElement.dataset.source = 'waste'; cardElement.dataset.index = waste.length - 1; wasteElement.appendChild(cardElement); } // 渲染foundations foundations.forEach((foundation, i) => { if (foundation.length > 0) { const topCard = foundation[foundation.length - 1]; const cardElement = createCardElement(topCard); cardElement.dataset.source = `foundation-${i}`; cardElement.dataset.index = foundation.length - 1; foundationElements[i].appendChild(cardElement); } }); // 渲染tableaus tableaus.forEach((tableau, i) => { tableau.forEach((card, j) => { const cardElement = createCardElement(card); cardElement.style.top = `${j * 25}px`; cardElement.dataset.source = `tableau-${i}`; cardElement.dataset.index = j; tableauElements[i].appendChild(cardElement); }); }); // 检查是否获胜 checkWinCondition(); } // 创建卡牌元素 function createCardElement(card) { const cardElement = document.createElement('div'); cardElement.className = 'card'; if (!card.faceUp) { cardElement.classList.add('card-back'); return cardElement; } cardElement.classList.add(card.color); cardElement.dataset.id = card.id; const cardContent = document.createElement('div'); cardContent.className = 'card-content'; const topValue = document.createElement('div'); topValue.className = 'card-value'; topValue.textContent = card.value; const topSuit = document.createElement('div'); topSuit.className = 'card-suit'; topSuit.textContent = card.suit; const center = document.createElement('div'); center.className = 'card-center'; center.textContent = card.suit; const bottomValue = document.createElement('div'); bottomValue.className = 'card-value'; bottomValue.style.transform = 'rotate(180deg)'; bottomValue.textContent = card.value; const bottomSuit = document.createElement('div'); bottomSuit.className = 'card-suit'; bottomSuit.style.transform = 'rotate(180deg)'; bottomSuit.textContent = card.suit; cardContent.appendChild(topValue); cardContent.appendChild(topSuit); cardContent.appendChild(center); cardContent.appendChild(bottomSuit); cardContent.appendChild(bottomValue); cardElement.appendChild(cardContent); return cardElement; } // 添加事件监听器 function addEventListeners() { // 为waste中的牌添加点击事件 document.querySelectorAll('#waste .card').forEach(card => { card.addEventListener('click', handleCardClick); card.addEventListener('mousedown', handleCardMouseDown); }); // 为foundation中的牌添加点击事件 document.querySelectorAll('.foundation .card').forEach(card => { card.addEventListener('click', handleCardClick); card.addEventListener('mousedown', handleCardMouseDown); }); // 为tableau中的牌添加点击事件 document.querySelectorAll('.tableau .card').forEach(card => { card.addEventListener('click', handleCardClick); card.addEventListener('mousedown', handleCardMouseDown); }); // 为空的foundation添加点击事件 document.querySelectorAll('.foundation:empty').forEach((foundation, i) => { foundation.addEventListener('click', () => handleEmptyFoundationClick(i)); }); // 为空的tableau添加点击事件 document.querySelectorAll('.tableau:empty').forEach((tableau, i) => { tableau.addEventListener('click', () => handleEmptyTableauClick(i)); }); // 添加全局鼠标事件 document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); } // 处理卡牌点击 function handleCardClick(e) { const cardElement = e.currentTarget; const source = cardElement.dataset.source; const index = parseInt(cardElement.dataset.index); // 如果已经选中了卡牌,尝试移动 if (selectedCard) { const targetCard = getCardFromElement(cardElement); const targetSource = source; const targetIndex = index; // 尝试移动卡牌 if (tryMoveCard(selectedCard, selectedSource, targetCard, targetSource)) { // 移动成功,重置选中状态 selectedCard = null; selectedStack = []; selectedSource = null; document.querySelectorAll('.card.selected').forEach(card => { card.classList.remove('selected'); }); renderGame(); } else { // 移动失败,选中新卡牌 selectCard(cardElement, source, index); } } else { // 选中卡牌 selectCard(cardElement, source, index); } } // 选中卡牌 function selectCard(cardElement, source, index) { // 清除之前的选中状态 document.querySelectorAll('.card.selected').forEach(card => { card.classList.remove('selected'); }); // 设置新的选中状态 selectedCard = getCardFromElement(cardElement); selectedSource = source; // 如果是tableau中的牌,可能需要选中一堆牌 if (source.startsWith('tableau-')) { const tableauIndex = parseInt(source.split('-')[1]); const tableau = tableaus[tableauIndex]; // 只能选择正面朝上的牌 if (selectedCard.faceUp) { // 选中从index到末尾的所有牌 selectedStack = tableau.slice(index); // 高亮显示选中的牌 const tableauElement = document.getElementById(`tableau-${tableauIndex}`); const cards = tableauElement.querySelectorAll('.card'); for (let i = index; i < cards.length; i++) { cards[i].classList.add('selected'); } } } else { // 其他区域只能选中一张牌 selectedStack = [selectedCard]; cardElement.classList.add('selected'); } } // 从元素获取卡牌对象 function getCardFromElement(cardElement) { const source = cardElement.dataset.source; const index = parseInt(cardElement.dataset.index); if (source === 'waste') { return waste[index]; } else if (source.startsWith('foundation-')) { const foundationIndex = parseInt(source.split('-')[1]); return foundations[foundationIndex][index]; } else if (source.startsWith('tableau-')) { const tableauIndex = parseInt(source.split('-')[1]); return tableaus[tableauIndex][index]; } return null; } // 尝试移动卡牌 function tryMoveCard(sourceCard, sourceLocation, targetCard, targetLocation) { // 如果源和目标相同,不移动 if (sourceLocation === targetLocation) { return false; } // 移动到foundation if (targetLocation && targetLocation.startsWith('foundation-')) { const foundationIndex = parseInt(targetLocation.split('-')[1]); // 只能移动单张牌到foundation if (selectedStack.length !== 1) { return false; } // 检查移动规则 if (canMoveToFoundation(sourceCard, foundations[foundationIndex])) { // 记录移动历史 recordMove({ type: 'moveToFoundation', sourceCard, sourceLocation, foundationIndex }); // 执行移动 moveCardToFoundation(sourceCard, sourceLocation, foundationIndex); return true; } } // 移动到tableau else if (targetLocation && targetLocation.startsWith('tableau-')) { const tableauIndex = parseInt(targetLocation.split('-')[1]); // 检查移动规则 if (canMoveToTableau(selectedStack[0], tableaus[tableauIndex])) { // 记录移动历史 recordMove({ type: 'moveToTableau', sourceStack: [...selectedStack], sourceLocation, tableauIndex }); // 执行移动 moveCardToTableau(selectedStack, sourceLocation, tableauIndex); return true; } } return false; } // 处理空foundation点击 function handleEmptyFoundationClick(foundationIndex) { if (selectedCard && selectedStack.length === 1) { // 检查是否可以移动到空foundation if (canMoveToEmptyFoundation(selectedCard)) { // 记录移动历史 recordMove({ type: 'moveToFoundation', sourceCard: selectedCard, sourceLocation: selectedSource, foundationIndex }); // 执行移动 moveCardToFoundation(selectedCard, selectedSource, foundationIndex); // 重置选中状态 selectedCard = null; selectedStack = []; selectedSource = null; document.querySelectorAll('.card.selected').forEach(card => { card.classList.remove('selected'); }); renderGame(); } } } // 处理空tableau点击 function handleEmptyTableauClick(tableauIndex) { if (selectedCard && selectedStack.length > 0) { // 检查是否可以移动到空tableau if (canMoveToEmptyTableau(selectedStack[0])) { // 记录移动历史 recordMove({ type: 'moveToTableau', sourceStack: [...selectedStack], sourceLocation: selectedSource, tableauIndex }); // 执行移动 moveCardToTableau(selectedStack, selectedSource, tableauIndex); // 重置选中状态 selectedCard = null; selectedStack = []; selectedSource = null; document.querySelectorAll('.card.selected').forEach(card => { card.classList.remove('selected'); }); renderGame(); } } } // 检查是否可以移动到foundation function canMoveToFoundation(card, foundation) { // 如果foundation为空,只能放A if (foundation.length === 0) { return card.value === 'A'; } // 否则,检查花色和顺序 const topCard = foundation[foundation.length - 1]; return card.suit === topCard.suit && card.rank === topCard.rank + 1; } // 检查是否可以移动到空foundation function canMoveToEmptyFoundation(card) { return card.value === 'A'; } // 检查是否可以移动到tableau function canMoveToTableau(card, tableau) { // 如果tableau为空,只能放K if (tableau.length === 0) { return card.value === 'K'; } // 否则,检查颜色和顺序 const topCard = tableau[tableau.length - 1]; return topCard.faceUp && card.color !== topCard.color && card.rank === topCard.rank - 1; } // 检查是否可以移动到空tableau function canMoveToEmptyTableau(card) { return card.value === 'K'; } // 移动卡牌到foundation function moveCardToFoundation(card, sourceLocation, foundationIndex) { // 从源位置移除卡牌 if (sourceLocation === 'waste') { waste.pop(); } else if (sourceLocation.startsWith('tableau-')) { const tableauIndex = parseInt(sourceLocation.split('-')[1]); tableaus[tableauIndex].pop(); // 如果tableau中还有牌,翻转顶部的牌 if (tableaus[tableauIndex].length > 0 && !tableaus[tableauIndex][tableaus[tableauIndex].length - 1].faceUp) { tableaus[tableauIndex][tableaus[tableauIndex].length - 1].faceUp = true; } } else if (sourceLocation.startsWith('foundation-')) { const sourceFoundationIndex = parseInt(sourceLocation.split('-')[1]); foundations[sourceFoundationIndex].pop(); } // 添加到foundation foundations[foundationIndex].push(card); // 更新移动次数 moves++; updateMovesDisplay(); } // 移动卡牌到tableau function moveCardToTableau(cardStack, sourceLocation, tableauIndex) { // 从源位置移除卡牌 if (sourceLocation === 'waste') { waste.pop(); } else if (sourceLocation.startsWith('tableau-')) { const sourceTableauIndex = parseInt(sourceLocation.split('-')[1]); const startIndex = tableaus[sourceTableauIndex].length - cardStack.length; tableaus[sourceTableauIndex].splice(startIndex, cardStack.length); // 如果tableau中还有牌,翻转顶部的牌 if (tableaus[sourceTableauIndex].length > 0 && !tableaus[sourceTableauIndex][tableaus[sourceTableauIndex].length - 1].faceUp) { tableaus[sourceTableauIndex][tableaus[sourceTableauIndex].length - 1].faceUp = true; } } else if (sourceLocation.startsWith('foundation-')) { const foundationIndex = parseInt(sourceLocation.split('-')[1]); foundations[foundationIndex].pop(); } // 添加到tableau tableaus[tableauIndex].push(...cardStack); // 更新移动次数 moves++; updateMovesDisplay(); } // 记录移动历史 function recordMove(move) { moveHistory.push({ ...move, stock: [...stock], waste: [...waste], foundations: foundations.map(f => [...f]), tableaus: tableaus.map(t => t.map(card => ({...card}))), moves }); } // 撤销移动 function undoMove() { if (moveHistory.length === 0) { return; } const lastMove = moveHistory.pop(); stock = [...lastMove.stock]; waste = [...lastMove.waste]; foundations = lastMove.foundations.map(f => [...f]); tableaus = lastMove.tableaus.map(t => t.map(card => ({...card}))); moves = lastMove.moves; updateMovesDisplay(); renderGame(); } // 显示提示 function showHint() { // 实现提示逻辑 alert('提示功能正在开发中...'); } // 更新移动次数显示 function updateMovesDisplay() { movesElement.textContent = `移动次数: ${moves}`; } // 更新计时器 function updateTimer() { seconds++; updateTimerDisplay(); } // 更新计时器显示 function updateTimerDisplay() { const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; timerElement.textContent = `时间: ${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; } // 检查胜利条件 function checkWinCondition() { // 检查所有foundation是否都有13张牌 const isWin = foundations.every(foundation => foundation.length === 13); if (isWin) { // 停止计时器 clearInterval(timerInterval); // 显示胜利消息 finalTimeElement.textContent = timerElement.textContent.replace('时间: ', ''); finalMovesElement.textContent = `${moves}`; winMessage.style.display = 'block'; } } // 拖拽相关函数 function handleCardMouseDown(e) { if (e.button !== 0) return; // 只处理左键点击 const cardElement = e.currentTarget; const source = cardElement.dataset.source; const index = parseInt(cardElement.dataset.index); // 只能拖拽正面朝上的牌 const card = getCardFromElement(cardElement); if (!card.faceUp) return; isDragging = true; // 设置拖拽的卡牌 if (source.startsWith('tableau-')) { const tableauIndex = parseInt(source.split('-')[1]); const tableau = tableaus[tableauIndex]; draggedCards = tableau.slice(index); draggedCard = card; selectedSource = source; } else { draggedCards = [card]; draggedCard = card; selectedSource = source; } // 记录鼠标位置 startX = e.clientX; startY = e.clientY; // 计算偏移量 const rect = cardElement.getBoundingClientRect(); offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; // 添加拖拽样式 cardElement.classList.add('dragging'); e.preventDefault(); } function handleMouseMove(e) { if (!isDragging || !draggedCard) return; const cardElements = document.querySelectorAll('.dragging'); cardElements.forEach(card => { card.style.position = 'fixed'; card.style.left = `${e.clientX - offsetX}px`; card.style.top = `${e.clientY - offsetY}px`; card.style.zIndex = '1000'; }); } function handleMouseUp(e) { if (!isDragging) return; isDragging = false; // 移除拖拽样式 document.querySelectorAll('.dragging').forEach(card => { card.classList.remove('dragging'); card.style.position = ''; card.style.left = ''; card.style.top = ''; card.style.zIndex = ''; }); // 检查是否放在有效位置 const targetElement = document.elementFromPoint(e.clientX, e.clientY); if (targetElement) { let dropTarget = targetElement; // 查找最近的卡牌或槽位 while (dropTarget && !dropTarget.classList.contains('card') && !dropTarget.classList.contains('card-slot')) { dropTarget = dropTarget.parentElement; } if (dropTarget) { // 如果是卡牌 if (dropTarget.classList.contains('card')) { const targetSource = dropTarget.dataset.source; const targetIndex = parseInt(dropTarget.dataset.index); const targetCard = getCardFromElement(dropTarget); // 尝试移动卡牌 tryMoveCard(draggedCard, selectedSource, targetCard, targetSource); } // 如果是空槽位 else if (dropTarget.classList.contains('card-slot')) { if (dropTarget.classList.contains('foundation')) { const foundationIndex = parseInt(dropTarget.id.split('-')[1]); if (draggedCards.length === 1 && canMoveToEmptyFoundation(draggedCards[0])) { // 记录移动历史 recordMove({ type: 'moveToFoundation', sourceCard: draggedCards[0], sourceLocation: selectedSource, foundationIndex }); // 执行移动 moveCardToFoundation(draggedCards[0], selectedSource, foundationIndex); } } else if (dropTarget.classList.contains('tableau')) { const tableauIndex = parseInt(dropTarget.id.split('-')[1]); if (canMoveToEmptyTableau(draggedCards[0])) { // 记录移动历史 recordMove({ type: 'moveToTableau', sourceStack: [...draggedCards], sourceLocation: selectedSource, tableauIndex }); // 执行移动 moveCardToTableau(draggedCards, selectedSource, tableauIndex); } } } } } // 重置拖拽状态 draggedCard = null; draggedCards = []; selectedSource = null; // 重新渲染游戏 renderGame(); } }); </script></body></html>
