纸牌接龙是一个经典的单人纸牌游戏,玩家需要按照一定的规则将纸牌排成一堆,并完成接龙。通常,游戏规则要求玩家根据纸牌的点数和花色进行排列,从而逐步完成接龙。尽管规则简单,纸牌的自动排序和发放以及操作逻辑的实现却需要一定的复杂性,尤其是在处理牌堆和规则检查时。
过去,制作一个纸牌接龙游戏需要编写发牌、排序和判断的代码,确保游戏的逻辑和UI能够流畅地运行。但现在,通过 Trae IDE,只需要输入简单的指令,Trae 就能够自动帮我完成所有复杂的游戏逻辑和UI设计。接下来,我将分享如何通过 Trae 快速生成一个纸牌接龙游戏,让玩家轻松体验这款经典纸牌游戏。
💡 我的需求其实很简单
我的需求非常明确:制作一个纸牌接龙游戏,功能要求如下:
- 纸牌发放:游戏开始时,纸牌会自动发放到指定位置。
- 规则排列:玩家按规则排列纸牌,通常是按照点数从大到小,交替的红黑花色排列。
- 自动排序:当玩家完成一部分排列时,纸牌会自动移动到正确的顺序。
- 游戏完成:当所有纸牌正确排列完成时,游戏自动判定完成接龙。
- 简洁的UI设计:游戏界面直观,操作简单,纸牌发放和排序清晰明了。
虽然规则看起来简单,但涉及到纸牌的发放、排序、移动和判断等操作,手动实现这些功能依然需要不少的时间。
✨ Trae 如何理解需求并生成代码?
我只需要在 Trae 中输入一句话:
"生成接龙游戏,玩家按规则排列纸牌,最终完成接龙。"

Trae 会自动解析我的需求,并生成完整的纸牌接龙游戏代码,包括:
- 纸牌发放:游戏开始时,纸牌会按照指定规则自动发放到桌面上的不同位置。
- 纸牌排序:玩家按照接龙规则排列纸牌,纸牌会自动按点数和花色排序。游戏规则确保纸牌的排列顺序正确。
- 自动化操作:当玩家操作时,纸牌会自动进行排序和移动,确保游戏逻辑流畅运行。
- 胜利判定:当玩家成功完成接龙后,系统会判定游戏胜利并显示"游戏完成"的提示。
- 简洁的UI设计:游戏界面设计简洁,纸牌的排列和操作非常直观,玩家可以轻松完成接龙任务。

通过简单的指令,Trae 就能为我自动生成一个完整的纸牌接龙游戏,并处理所有复杂的操作和逻辑。
🧩 游戏操作简便,玩法清晰
Trae 生成的纸牌接龙游戏操作非常直观,玩家只需点击纸牌并拖动到正确的位置,游戏会根据规则自动排列纸牌。每次移动纸牌,游戏界面都会即时更新,确保玩家能够清晰看到纸牌的排序进展。
如果玩家完成了某部分接龙,纸牌会自动整理并移动到新的位置,玩家不需要手动去整理纸牌,操作十分流畅。
🛠 游戏拓展,功能轻松加
虽然 Trae 生成的纸牌接龙游戏已经非常完备,但它也支持轻松添加更多功能。例如:
- 多种接龙模式:可以增加不同的接龙玩法,如四堆接龙、空位接龙等,给玩家提供更多的挑战。
- 计时器功能:为游戏加入计时器,记录玩家完成接龙的时间,增加游戏的竞技性。
- 得分系统:可以根据玩家完成接龙的速度和完成度来给出分数。
- 音效和动画:为纸牌的发放、排序和移动添加动画和音效,使游戏更具互动性。
这些新功能都可以通过简单描述,Trae 会自动生成并将它们集成到现有的游戏中。
这就是纸牌接龙游戏开发的新体验
通过这次纸牌接龙游戏的开发,我深刻感受到了 Trae 带来的便利。从纸牌的发放,到玩家的操作,再到排序和判定,Trae 都能够自动帮我完成。这不仅节省了大量开发时间,也提高了开发效率,让我可以更专注于游戏设计和功能扩展。
对于独立开发者或小团队来说,Trae 是一个非常高效的工具,它帮助你将繁琐的逻辑和操作自动化,让你专注于创意和优化。
结语
如果你也想制作一个经典的纸牌接龙游戏,试试 Trae IDE,输入类似的需求:
"生成接龙游戏,玩家按规则排列纸牌,最终完成接龙。"
几秒钟内,Trae 就会生成完整的纸牌接龙游戏代码,带有纸牌发放、排序、玩家操作和胜利判定等功能。你可以直接将它嵌入到你的项目中,甚至根据需求继续扩展和优化。
快来体验一下 Trae,让你的纸牌接龙游戏开发变得更加轻松、有趣!
html
<!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>