Compare commits
2 Commits
617344cbeb
...
c48a15552e
Author | SHA1 | Date | |
---|---|---|---|
c48a15552e | |||
43d761d49a |
1420
package-lock.json
generated
1420
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -20,7 +20,6 @@
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-plugin-vue": "^9.30.0",
|
||||
"prettier": "^3.3.3",
|
||||
"vite": "^6.0.5",
|
||||
"vite-plugin-vue-devtools": "^7.6.8"
|
||||
"vite": "^6.0.5"
|
||||
}
|
||||
}
|
||||
|
333
src/App.vue
333
src/App.vue
@ -84,6 +84,12 @@
|
||||
{{ getPlayerName(winner) }}胜利!<br />
|
||||
第 {{ moveCount }} 手获胜
|
||||
</p>
|
||||
<p
|
||||
v-if="gameMode === 'pve' && winner !== (isPlayerBlack ? 1 : 2)"
|
||||
class="taunt-message"
|
||||
>
|
||||
{{ getTauntMessage() }}
|
||||
</p>
|
||||
<div class="modal-buttons">
|
||||
<button @click="closeModal" class="modal-button secondary">查看棋盘</button>
|
||||
<button @click="playAgain" class="modal-button primary">再来一局</button>
|
||||
@ -138,6 +144,30 @@ export default {
|
||||
gameEnded: false,
|
||||
lastMove: null, // 记录最后一手的位置
|
||||
lastWinner: null, // 保存最后的获胜者信息
|
||||
taunts: {
|
||||
computerWin: [
|
||||
'这就是你的全部实力吗?太让我失望了!',
|
||||
'或许你该找个AI初级版本玩玩?',
|
||||
'我都觉得自己下棋太温柔了...',
|
||||
'你的棋力比我的运算量还小呢!',
|
||||
'要不要我让你三手?',
|
||||
],
|
||||
timeoutWin: [
|
||||
'思考太久对身体不好哦~',
|
||||
'看来是我太强了,让你想不出对策?',
|
||||
'时间管理也是实力的一部分呢!',
|
||||
],
|
||||
quickWin: [
|
||||
'这么快就结束了?我都还没热身呢!',
|
||||
'你确定你不是在帮我练习?',
|
||||
'我建议你先去看看五子棋入门教程...',
|
||||
],
|
||||
closeWin: [
|
||||
'差一点就被你赢了呢...骗你的!',
|
||||
'让你以为有机会赢,这样才有趣嘛!',
|
||||
'看起来很激烈?其实我一直在掌控局面哦!',
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
@ -455,52 +485,235 @@ export default {
|
||||
evaluatePosition(row, col, player) {
|
||||
let score = 0
|
||||
const directions = [
|
||||
[1, 0], // 垂直
|
||||
[0, 1], // 水平
|
||||
[1, 1], // 右下
|
||||
[1, -1], // 左下
|
||||
[1, 0],
|
||||
[0, 1],
|
||||
[1, 1],
|
||||
[1, -1],
|
||||
]
|
||||
|
||||
// 分析当前位置的防守价值
|
||||
const opponent = player === 1 ? 2 : 1
|
||||
let defenseScore = 0
|
||||
let attackScore = 0
|
||||
|
||||
// 提高中心位置的权重
|
||||
const centerWeight = Math.max(0, 15 - (Math.abs(7 - row) + Math.abs(7 - col))) * 15
|
||||
|
||||
// 检查是否能形成更复杂的棋型
|
||||
const complexPatterns = this.checkComplexPatterns(row, col, player)
|
||||
if (complexPatterns.doubleFour) attackScore += 150000
|
||||
if (complexPatterns.tripleThree) attackScore += 40000
|
||||
|
||||
// 评估进攻价值
|
||||
for (const [dx, dy] of directions) {
|
||||
attackScore += this.evaluateDirection(row, col, dx, dy, player)
|
||||
const pattern = this.checkPattern(row, col, dx, dy, player)
|
||||
if (pattern.liveFour) attackScore += 120000
|
||||
if (pattern.liveThree) attackScore += 20000
|
||||
if (pattern.sleepingFour) attackScore += 15000
|
||||
if (pattern.doubleThree) attackScore += 25000
|
||||
}
|
||||
|
||||
// 评估防守价值
|
||||
for (const [dx, dy] of directions) {
|
||||
defenseScore += this.evaluateDirection(row, col, dx, dy, opponent)
|
||||
const pattern = this.checkPattern(row, col, dx, dy, opponent)
|
||||
if (pattern.liveFour) defenseScore += 110000
|
||||
if (pattern.liveThree) defenseScore += 18000
|
||||
if (pattern.sleepingFour) defenseScore += 14000
|
||||
if (pattern.doubleThree) defenseScore += 22000
|
||||
}
|
||||
|
||||
// 智能权重分配
|
||||
if (defenseScore >= 1000) {
|
||||
// 对手有四或冲四
|
||||
score = Math.max(attackScore, defenseScore * 1.2) // 防守优先
|
||||
} else if (defenseScore >= 500) {
|
||||
// 对手有活三
|
||||
score = Math.max(attackScore, defenseScore * 1.1)
|
||||
// 优化进攻与防守的平衡
|
||||
if (defenseScore >= 80000) {
|
||||
score = Math.max(attackScore * 1.3, defenseScore * 2)
|
||||
} else if (defenseScore >= 15000) {
|
||||
score = attackScore * 1.8 + defenseScore * 1.2
|
||||
} else {
|
||||
score = Math.max(attackScore * 1.1, defenseScore) // 略偏向进攻
|
||||
score = attackScore * 2.5 + defenseScore * 0.4
|
||||
}
|
||||
|
||||
// 根据位置给予额外分数
|
||||
const centerWeight = 15 - (Math.abs(7 - row) + Math.abs(7 - col))
|
||||
score += centerWeight * 3 // 增加中心位置权重
|
||||
// 增加位置权重和连接性评分
|
||||
score += centerWeight * 20
|
||||
const connectivityScore = this.evaluateConnectivity(row, col, player)
|
||||
score += connectivityScore * 250
|
||||
|
||||
// 优先选择靠近已有棋子的位置
|
||||
const nearbyScore = this.evaluateNearbyPieces(row, col)
|
||||
score += nearbyScore
|
||||
// 在开局阶段更注重布局
|
||||
if (this.moveCount < 10) {
|
||||
score += this.evaluateOpeningPosition(row, col) * 400
|
||||
}
|
||||
|
||||
// 在中盘更注重进攻
|
||||
if (this.moveCount >= 10 && this.moveCount < 25) {
|
||||
score *= 1.2
|
||||
}
|
||||
|
||||
return score
|
||||
},
|
||||
|
||||
evaluateNearbyPieces(row, col) {
|
||||
let score = 0
|
||||
const range = 2 // 检查2格范围内的棋子
|
||||
// 新增:检查复杂棋型
|
||||
checkComplexPatterns(row, col, player) {
|
||||
const patterns = {
|
||||
doubleFour: false, // 双四
|
||||
tripleThree: false, // 三三
|
||||
}
|
||||
|
||||
let fourCount = 0
|
||||
let threeCount = 0
|
||||
|
||||
const directions = [
|
||||
[1, 0],
|
||||
[0, 1],
|
||||
[1, 1],
|
||||
[1, -1],
|
||||
]
|
||||
|
||||
this.board[row][col] = player
|
||||
|
||||
for (const [dx, dy] of directions) {
|
||||
const pattern = this.checkPattern(row, col, dx, dy, player)
|
||||
if (pattern.liveFour || pattern.sleepingFour) fourCount++
|
||||
if (pattern.liveThree) threeCount++
|
||||
}
|
||||
|
||||
this.board[row][col] = 0
|
||||
|
||||
patterns.doubleFour = fourCount >= 2
|
||||
patterns.tripleThree = threeCount >= 3
|
||||
|
||||
return patterns
|
||||
},
|
||||
|
||||
// 新增:评估开局位置
|
||||
evaluateOpeningPosition(row, col) {
|
||||
// 开局更倾向于下在距离中心区域的位置
|
||||
const centerDist = Math.sqrt(Math.pow(row - 7, 2) + Math.pow(col - 7, 2))
|
||||
if (centerDist <= 4) return 1
|
||||
if (centerDist <= 6) return 0.7
|
||||
return 0.3
|
||||
},
|
||||
|
||||
// 新增:检查棋型
|
||||
checkPattern(row, col, dx, dy, player) {
|
||||
const pattern = {
|
||||
liveFour: false, // 活四
|
||||
liveThree: false, // 活三
|
||||
sleepingFour: false, // 眠四
|
||||
doubleThree: false, // 双三
|
||||
}
|
||||
|
||||
// 临时在此位置落子以检查棋型
|
||||
this.board[row][col] = player
|
||||
|
||||
let consecutive = 1
|
||||
let blocked = 0
|
||||
|
||||
// 正向检查
|
||||
for (let i = 1; i <= 4; i++) {
|
||||
const newRow = row + dx * i
|
||||
const newCol = col + dy * i
|
||||
if (!this.isValidPosition(newRow, newCol)) {
|
||||
blocked++
|
||||
break
|
||||
}
|
||||
if (this.board[newRow][newCol] === player) {
|
||||
consecutive++
|
||||
} else if (this.board[newRow][newCol] === 0) {
|
||||
break
|
||||
} else {
|
||||
blocked++
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 反向检查
|
||||
for (let i = 1; i <= 4; i++) {
|
||||
const newRow = row - dx * i
|
||||
const newCol = col - dy * i
|
||||
if (!this.isValidPosition(newRow, newCol)) {
|
||||
blocked++
|
||||
break
|
||||
}
|
||||
if (this.board[newRow][newCol] === player) {
|
||||
consecutive++
|
||||
} else if (this.board[newRow][newCol] === 0) {
|
||||
break
|
||||
} else {
|
||||
blocked++
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 恢复棋盘
|
||||
this.board[row][col] = 0
|
||||
|
||||
// 判断棋型
|
||||
if (consecutive >= 4 && blocked === 0) pattern.liveFour = true
|
||||
if (consecutive >= 4 && blocked === 1) pattern.sleepingFour = true
|
||||
if (consecutive === 3 && blocked === 0) pattern.liveThree = true
|
||||
if (this.checkDoubleThree(row, col, player)) pattern.doubleThree = true
|
||||
|
||||
return pattern
|
||||
},
|
||||
|
||||
// 新增:检查是否形成双三
|
||||
checkDoubleThree(row, col, player) {
|
||||
let threeCount = 0
|
||||
const directions = [
|
||||
[
|
||||
[1, 0],
|
||||
[-1, 0],
|
||||
], // 垂直
|
||||
[
|
||||
[0, 1],
|
||||
[0, -1],
|
||||
], // 水平
|
||||
[
|
||||
[1, 1],
|
||||
[-1, -1],
|
||||
], // 右下-左上
|
||||
[
|
||||
[1, -1],
|
||||
[-1, 1],
|
||||
], // 右上-左下
|
||||
]
|
||||
|
||||
this.board[row][col] = player
|
||||
|
||||
for (const [dir1, dir2] of directions) {
|
||||
let count = 1
|
||||
let blocked = 0
|
||||
|
||||
// 检查两个方向
|
||||
for (const [dx, dy] of [dir1, dir2]) {
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
const newRow = row + dx * i
|
||||
const newCol = col + dy * i
|
||||
if (!this.isValidPosition(newRow, newCol)) {
|
||||
blocked++
|
||||
break
|
||||
}
|
||||
if (this.board[newRow][newCol] === player) {
|
||||
count++
|
||||
} else if (this.board[newRow][newCol] !== 0) {
|
||||
blocked++
|
||||
break
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count === 3 && blocked === 0) threeCount++
|
||||
}
|
||||
|
||||
this.board[row][col] = 0
|
||||
return threeCount >= 2
|
||||
},
|
||||
|
||||
// 新增:评估连接性
|
||||
evaluateConnectivity(row, col, player) {
|
||||
let connectivity = 0
|
||||
const range = 2
|
||||
|
||||
for (let i = -range; i <= range; i++) {
|
||||
for (let j = -range; j <= range; j++) {
|
||||
@ -510,17 +723,15 @@ export default {
|
||||
const newCol = col + j
|
||||
|
||||
if (this.isValidPosition(newRow, newCol)) {
|
||||
const piece = this.board[newRow][newCol]
|
||||
if (piece !== 0) {
|
||||
// 距离近分数越高
|
||||
const distance = Math.max(Math.abs(i), Math.abs(j))
|
||||
score += (range - distance + 1) * 20
|
||||
if (this.board[newRow][newCol] === player) {
|
||||
// 距离越近,连接性分数越高
|
||||
connectivity += (range + 1 - Math.max(Math.abs(i), Math.abs(j))) * 30
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return score
|
||||
return connectivity
|
||||
},
|
||||
|
||||
evaluateDirection(row, col, dx, dy, player) {
|
||||
@ -688,6 +899,43 @@ export default {
|
||||
// 可以在这里添加胜利时的额外动画效果
|
||||
// 比如闪烁、缩放等
|
||||
},
|
||||
|
||||
getTauntMessage() {
|
||||
if (this.gameMode !== 'pve' || this.winner === (this.isPlayerBlack ? 1 : 2)) {
|
||||
return null // 如果不是人机模式或者玩家赢了,不显示嘲讽
|
||||
}
|
||||
|
||||
let taunts
|
||||
if (this.winner === 'timeout') {
|
||||
taunts = this.taunts.timeoutWin
|
||||
} else if (this.moveCount < 15) {
|
||||
taunts = this.taunts.quickWin
|
||||
} else if (this.hasCloseWin()) {
|
||||
taunts = this.taunts.closeWin
|
||||
} else {
|
||||
taunts = this.taunts.computerWin
|
||||
}
|
||||
|
||||
return taunts[Math.floor(Math.random() * taunts.length)]
|
||||
},
|
||||
|
||||
hasCloseWin() {
|
||||
// 检查是否是险胜(通过检查玩家是否有连四)
|
||||
const playerPiece = this.isPlayerBlack ? 1 : 2
|
||||
for (let i = 0; i < 15; i++) {
|
||||
for (let j = 0; j < 15; j++) {
|
||||
if (this.board[i][j] === 0) {
|
||||
this.board[i][j] = playerPiece
|
||||
const pattern = this.checkPattern(i, j, [1, 0], playerPiece)
|
||||
this.board[i][j] = 0
|
||||
if (pattern.liveFour || pattern.sleepingFour) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
@ -1207,4 +1455,33 @@ export default {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 15px rgba(76, 175, 80, 0.3);
|
||||
}
|
||||
|
||||
.taunt-message {
|
||||
margin-top: 15px;
|
||||
padding: 10px;
|
||||
background: linear-gradient(145deg, #e53935, #d32f2f);
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
font-style: italic;
|
||||
animation: tauntPulse 2s infinite;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0 4px 15px rgba(229, 57, 53, 0.4);
|
||||
}
|
||||
|
||||
@keyframes tauntPulse {
|
||||
from {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 4px 15px rgba(229, 57, 53, 0.4);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 6px 20px rgba(229, 57, 53, 0.6);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 4px 15px rgba(229, 57, 53, 0.4);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -2,13 +2,11 @@ import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
vueDevTools(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
|
Loading…
Reference in New Issue
Block a user