第七代电脑

This commit is contained in:
icezhb 2024-12-29 12:47:05 +08:00
parent 617344cbeb
commit 43d761d49a
4 changed files with 310 additions and 1451 deletions

1420
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -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"
}
}

View File

@ -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,238 @@ 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 space = false
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) {
space = true
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) {
space = true
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 +726,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 +902,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 +1458,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>

View File

@ -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: {