前言
- 让AI Grok做双人象棋小游戏,但是通过一次提示词的话,效果并不理想,只能说能玩而已,还需要多次提示词去优化游戏才行
- 废话不多说,上代码
环境说明
- Grok 我是直接在网页上使用的 Grok3
-
- 先预告一点结果小内容:Grok 网页上输出结果非常快,Grok都生成好了,Trea上的 Gemini 2.5 还在一步一步的思考,非常慢,这可能更多是Trea的问题,过程中经常出现修复修改失败这种情况,循环尝试后,就最终失败告终
提示词
这是份微信小程序中的小游戏代码的主场景游代码,我现在要你基于现在的代码,帮我实现一个双人中国象棋游戏,象棋棋盘位于整个屏幕的居中位置,棋盘以及棋盘中的格子和棋盘中的棋子尺寸都基于屏幕的宽度进行计算,屏幕宽度越宽尺寸就相对增加,整个棋盘的宽度是屏幕宽度的90%,棋盘中的棋子分为红方和黑方,即棋子中的文字颜色分为红色和黑色,棋子的背景色都是近似木头的浅色,棋子都是圆形的;红方和黑方棋谱分布方式为上下分布,中间楚河汉界,上方为红方,下方为黑方;象棋玩法你可以去网上查找,就是以往传统的中国象棋游戏,最终如果有一方胜利了,就用console.log打印出胜利的一方,如:红方胜利;且有一方胜利后,棋局就不能再继续了;而且要通过实现drawWinResult并调用drawWinResult函数在屏幕居中显示一个展示棋局结果的矩形信息区域,这个矩形区域边框是黄色,背景是咖啡色,里面文字水平和垂直都居中展示,文字颜色是白色,字体尺寸是屏幕宽度的30%,字体颜色是白色,这个矩形信息区域的宽度与屏幕宽度相同,高度则比其中的文字高5%,其中文字内容则展示胜利结果,如“红方胜”或“黑方胜”
请根据我上面的需求帮我实现这个双人中国象棋游戏吧
下面是我这份已有的主场景代码 import { SCREEN_WIDTH, SCREEN_HEIGHT } from '../../render';
function getTouchPosition(event) { const touches = event.changedTouches; if (!touches || touches.length === 0) return null;
const touch = touches[0]; const touchX = touch.clientX; const touchY = touch.clientY;
return { x: touchX, y: touchY }; }
const CAN_BACK_STEP_COUNT = 1;
export default class Chessboard { constructor(musicCtrl) { this.musicCtrl = musicCtrl; this.isPlayedMusic = false;
this.initBoard(); this.bindTouchEvent(); }
bindTouchEvent() { wx.onTouchEnd(this.handleClick.bind(this)); }
initBoard() { }
backstep() { }
handleClick(event) { const position = getTouchPosition(event); if (!position) return;
const { x: canvasX, y: canvasY } = position; }
drawWinResult(ctx, text) { }
update() { }
render(ctx) { if (!this.ctx) { this.ctx = ctx; }
this.update(); } }
Grok 结果
- 效果截图

-
- 体验:只能说能玩,但是AI几乎不懂得优化,比如中间的楚河汉界就是直接覆盖掉了格子,还有整个棋盘画的也不理想,点击棋子后,倒是有选中棋子的状态,但是,画面的其他棋子边框也会发生一点影响,总之效果还要多次通过提示词来进行优化,现在只能说能玩而已
import { SCREEN_WIDTH, SCREEN_HEIGHT } from '../../render';
function getTouchPosition(event) {
const touches = event.changedTouches;
if (!touches || touches.length === 0) return null;
const touch = touches[0];
const touchX = touch.clientX;
const touchY = touch.clientY;
return { x: touchX, y: touchY };
}
const CAN_BACK_STEP_COUNT = 1;
export default class Chessboard {
constructor(musicCtrl) {
this.musicCtrl = musicCtrl;
this.isPlayedMusic = false;
this.initBoard();
this.bindTouchEvent();
}
initBoard() {
this.boardWidth = SCREEN_WIDTH * 0.9;
this.cellSize = this.boardWidth / 9;
this.pieceRadius = this.cellSize * 0.4;
this.boardLeft = (SCREEN_WIDTH - this.boardWidth) / 2;
this.boardTop = (SCREEN_HEIGHT - this.boardWidth * 10 / 9) / 2;
this.boardHeight = this.boardWidth * 10 / 9;
this.history = [];
this.selectedPiece = null;
this.currentPlayer = 'red';
this.gameOver = false;
this.board = Array(10).fill().map(() => Array(9).fill(0));
this.pieces = [
{ type: '車', player: 'red', pos: [9, 0], alive: true },
{ type: '馬', player: 'red', pos: [9, 1], alive: true },
{ type: '象', player: 'red', pos: [9, 2], alive: true },
{ type: '士', player: 'red', pos: [9, 3], alive: true },
{ type: '将', player: 'red', pos: [9, 4], alive: true },
{ type: '士', player: 'red', pos: [9, 5], alive: true },
{ type: '象', player: 'red', pos: [9, 6], alive: true },
{ type: '馬', player: 'red', pos: [9, 7], alive: true },
{ type: '車', player: 'red', pos: [9, 8], alive: true },
{ type: '炮', player: 'red', pos: [7, 1], alive: true },
{ type: '炮', player: 'red', pos: [7, 7], alive: true },
{ type: '兵', player: 'red', pos: [6, 0], alive: true },
{ type: '兵', player: 'red', pos: [6, 2], alive: true },
{ type: '兵', player: 'red', pos: [6, 4], alive: true },
{ type: '兵', player: 'red', pos: [6, 6], alive: true },
{ type: '兵', player: 'red', pos: [6, 8], alive: true },
{ type: '車', player: 'black', pos: [0, 0], alive: true },
{ type: '馬', player: 'black', pos: [0, 1], alive: true },
{ type: '象', player: 'black', pos: [0, 2], alive: true },
{ type: '士', player: 'black', pos: [0, 3], alive: true },
{ type: '将', player: 'black', pos: [0, 4], alive: true },
{ type: '士', player: 'black', pos: [0, 5], alive: true },
{ type: '象', player: 'black', pos: [0, 6], alive: true },
{ type: '馬', player: 'black', pos: [0, 7], alive: true },
{ type: '車', player: 'black', pos: [0, 8], alive: true },
{ type: '炮', player: 'black', pos: [2, 1], alive: true },
{ type: '炮', player: 'black', pos: [2, 7], alive: true },
{ type: '卒', player: 'black', pos: [3, 0], alive: true },
{ type: '卒', player: 'black', pos: [3, 2], alive: true },
{ type: '卒', player: 'black', pos: [3, 4], alive: true },
{ type: '卒', player: 'black', pos: [3, 6], alive: true },
{ type: '卒', player: 'black', pos: [3, 8], alive: true },
];
this.updateBoard();
}
bindTouchEvent() {
wx.onTouchEnd(this.handleClick.bind(this));
}
updateBoard() {
this.board = Array(10).fill().map(() => Array(9).fill(0));
for (const piece of this.pieces) {
if (piece.alive) {
const [row, col] = piece.pos;
this.board[row][col] = piece.player === 'red' ? 1 : 2;
}
}
}
screenToBoard(x, y) {
const col = Math.round((x - this.boardLeft) / this.cellSize);
const row = Math.round((y - this.boardTop) / this.cellSize);
return { row, col };
}
boardToScreen(row, col) {
const x = this.boardLeft + col * this.cellSize;
const y = this.boardTop + row * this.cellSize;
return { x, y };
}
isValidMove(piece, newRow, newCol) {
if (this.gameOver) return false;
if (newRow < 0 || newRow > 9 || newCol < 0 || newCol > 8) return false;
const [oldRow, oldCol] = piece.pos;
const targetPiece = this.pieces.find(p => p.alive && p.pos[0] === newRow && p.pos[1] === newCol);
if (targetPiece && targetPiece.player === piece.player) return false;
switch (piece.type) {
case '車':
return this.isValidRookMove(oldRow, oldCol, newRow, newCol);
case '馬':
return this.isValidKnightMove(oldRow, oldCol, newRow, newCol);
case '象':
return this.isValidElephantMove(oldRow, oldCol, newRow, newCol, piece.player);
case '士':
return this.isValidAdvisorMove(oldRow, oldCol, newRow, newCol, piece.player);
case '将':
return this.isValidKingMove(oldRow, oldCol, newRow, newCol, piece.player);
case '炮':
return this.isValidCannonMove(oldRow, oldCol, newRow, newCol, targetPiece);
case '兵':
case '卒':
return this.isValidPawnMove(oldRow, oldCol, newRow, newCol, piece.player);
default:
return false;
}
}
isValidRookMove(oldRow, oldCol, newRow, newCol) {
if (oldRow !== newRow && oldCol !== newCol) return false;
if (oldRow === newRow) {
const step = oldCol < newCol ? 1 : -1;
for (let col = oldCol + step; col !== newCol; col += step) {
if (this.board[oldRow][col] !== 0) return false;
}
} else {
const step = oldRow < newRow ? 1 : -1;
for (let row = oldRow + step; row !== newRow; row += step) {
if (this.board[row][oldCol] !== 0) return false;
}
}
return true;
}
isValidKnightMove(oldRow, oldCol, newRow, newCol) {
const rowDiff = Math.abs(newRow - oldRow);
const colDiff = Math.abs(newCol - oldCol);
if (!((rowDiff === 2 && colDiff === 1) || (rowDiff === 1 && colDiff === 2))) return false;
if (rowDiff === 2) {
const midRow = (oldRow + newRow) / 2;
if (this.board[midRow][oldCol] !== 0) return false;
} else {
const midCol = (oldCol + newCol) / 2;
if (this.board[oldRow][midCol] !== 0) return false;
}
return true;
}
isValidElephantMove(oldRow, oldCol, newRow, newCol, player) {
if (player === 'red' && newRow < 5 || player === 'black' && newRow > 4) return false;
if (Math.abs(newRow - oldRow) !== 2 || Math.abs(newCol - oldCol) !== 2) return false;
const midRow = (oldRow + newRow) / 2;
const midCol = (oldCol + newCol) / 2;
return this.board[midRow][midCol] === 0;
}
isValidAdvisorMove(oldRow, oldCol, newRow, newCol, player) {
if (player === 'red' && (newRow < 7 || newCol < 3 || newCol > 5)) return false;
if (player === 'black' && (newRow > 2 || newCol < 3 || newCol > 5)) return false;
return Math.abs(newRow - oldRow) === 1 && Math.abs(newCol - oldCol) === 1;
}
isValidKingMove(oldRow, oldCol, newRow, newCol, player) {
if (player === 'red' && (newRow < 7 || newCol < 3 || newCol > 5)) return false;
if (player === 'black' && (newRow > 2 || newCol < 3 || newCol > 5)) return false;
if (Math.abs(newRow - oldRow) + Math.abs(newCol - oldCol) !== 1) return false;
if (oldCol === newCol && this.board[newRow][newCol] === (player === 'red' ? 2 : 1)) {
const step = player === 'red' ? -1 : 1;
for (let row = oldRow + step; row !== newRow; row += step) {
if (this.board[row][newCol] !== 0) return false;
}
return true;
}
return true;
}
isValidCannonMove(oldRow, oldCol, newRow, newCol, targetPiece) {
if (oldRow !== newRow && oldCol !== newCol) return false;
let pieceCount = 0;
if (oldRow === newRow) {
const step = oldCol < newCol ? 1 : -1;
for (let col = oldCol + step; col !== newCol; col += step) {
if (this.board[oldRow][col] !== 0) pieceCount++;
}
} else {
const step = oldRow < newRow ? 1 : -1;
for (let row = oldRow + step; row !== newRow; row += step) {
if (this.board[row][oldCol] !== 0) pieceCount++;
}
}
return (targetPiece && pieceCount === 1) || (!targetPiece && pieceCount === 0);
}
isValidPawnMove(oldRow, oldCol, newRow, newCol, player) {
const rowDiff = newRow - oldRow;
const colDiff = Math.abs(newCol - oldCol);
if (colDiff > 1 || Math.abs(rowDiff) > 1) return false;
if (player === 'red') {
if (oldRow <= 4 && colDiff === 1) return false;
if (rowDiff > 0) return false;
return colDiff === 0 || (colDiff === 1 && oldRow <= 4);
} else {
if (oldRow >= 5 && colDiff === 1) return false;
if (rowDiff < 0) return false;
return colDiff === 0 || (colDiff === 1 && oldRow >= 5);
}
}
checkWin() {
const redKing = this.pieces.find(p => p.type === '将' && p.player === 'red' && p.alive);
const blackKing = this.pieces.find(p => p.type === '将' && p.player === 'black' && p.alive);
if (!redKing) {
console.log('黑方胜利');
this.gameOver = true;
return 'black';
}
if (!blackKing) {
console.log('红方胜利');
this.gameOver = true;
return 'red';
}
return null;
}
handleClick(event) {
if (this.gameOver) return;
const position = getTouchPosition(event);
if (!position) return;
const { x, y } = position;
const { row, col } = this.screenToBoard(x, y);
if (row < 0 || row > 9 || col < 0 || col > 8) return;
const clickedPiece = this.pieces.find(p => p.alive && p.pos[0] === row && p.pos[1] === col);
if (this.selectedPiece) {
if (this.isValidMove(this.selectedPiece, row, col)) {
const targetPiece = this.pieces.find(p => p.alive && p.pos[0] === row && p.pos[1] === col);
if (targetPiece) {
targetPiece.alive = false;
}
this.history.push({
piece: { ...this.selectedPiece },
from: [...this.selectedPiece.pos],
to: [row, col],
eaten: targetPiece ? { ...targetPiece } : null
});
this.selectedPiece.pos = [row, col];
this.updateBoard();
const winner = this.checkWin();
if (winner) {
this.drawWinResult(this.ctx, winner === 'red' ? '红方胜' : '黑方胜');
} else {
this.currentPlayer = this.currentPlayer === 'red' ? 'black' : 'red';
}
this.selectedPiece = null;
} else {
this.selectedPiece = null;
}
} else if (clickedPiece && clickedPiece.player === this.currentPlayer) {
this.selectedPiece = clickedPiece;
}
}
backstep() {
if (this.gameOver || this.history.length === 0 || this.history.length > CAN_BACK_STEP_COUNT) return;
const lastMove = this.history.pop();
lastMove.piece.pos = lastMove.from;
if (lastMove.eaten) {
lastMove.eaten.alive = true;
}
this.updateBoard();
this.currentPlayer = this.currentPlayer === 'red' ? 'black' : 'red';
this.selectedPiece = null;
}
drawWinResult(ctx, text) {
const fontSize = SCREEN_WIDTH * 0.3;
const rectWidth = SCREEN_WIDTH;
const rectHeight = fontSize * 1.05;
const rectX = 0;
const rectY = (SCREEN_HEIGHT - rectHeight) / 2;
ctx.fillStyle = '#8B4513';
ctx.strokeStyle = '#FFFF00';
ctx.lineWidth = 2;
ctx.fillRect(rectX, rectY, rectWidth, rectHeight);
ctx.strokeRect(rectX, rectY, rectWidth, rectHeight);
ctx.fillStyle = '#FFFFFF';
ctx.font = `${fontSize}px Arial`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(text, SCREEN_WIDTH / 2, rectY + rectHeight / 2);
}
render(ctx) {
if (!this.ctx) {
this.ctx = ctx;
}
ctx.fillStyle = '#F4A460';
ctx.fillRect(this.boardLeft, this.boardTop, this.boardWidth, this.boardHeight);
ctx.strokeStyle = '#000000';
ctx.lineWidth = 2;
for (let i = 0; i <= 9; i++) {
const y = this.boardTop + i * this.cellSize;
ctx.beginPath();
ctx.moveTo(this.boardLeft, y);
ctx.lineTo(this.boardLeft + this.boardWidth, y);
ctx.stroke();
}
for (let i = 0; i <= 8; i++) {
const x = this.boardLeft + i * this.cellSize;
ctx.beginPath();
ctx.moveTo(x, this.boardTop);
ctx.lineTo(x, this.boardTop + this.boardHeight);
ctx.stroke();
}
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(this.boardLeft, this.boardTop + 4.5 * this.cellSize, this.boardWidth, this.cellSize);
ctx.fillStyle = '#000000';
ctx.font = `${this.cellSize * 0.5}px Arial`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('楚河 汉界', this.boardLeft + this.boardWidth / 2, this.boardTop + 5 * this.cellSize);
const drawPalace = (rowStart, colStart) => {
ctx.beginPath();
ctx.moveTo(this.boardLeft + colStart * this.cellSize, this.boardTop + rowStart * this.cellSize);
ctx.lineTo(this.boardLeft + (colStart + 2) * this.cellSize, this.boardTop + (rowStart + 2) * this.cellSize);
ctx.moveTo(this.boardLeft + (colStart + 2) * this.cellSize, this.boardTop + rowStart * this.cellSize);
ctx.lineTo(this.boardLeft + colStart * this.cellSize, this.boardTop + (rowStart + 2) * this.cellSize);
ctx.stroke();
};
drawPalace(0, 3);
drawPalace(7, 3);
for (const piece of this.pieces) {
if (piece.alive) {
const { x, y } = this.boardToScreen(piece.pos[0], piece.pos[1]);
ctx.fillStyle = '#DEB887';
ctx.beginPath();
ctx.arc(x, y, this.pieceRadius, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#000000';
ctx.stroke();
ctx.fillStyle = piece.player === 'red' ? '#FF0000' : '#000000';
ctx.font = `${this.pieceRadius * 0.8}px Arial`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(piece.type, x, y);
if (piece === this.selectedPiece) {
ctx.strokeStyle = '#00FF00';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(x, y, this.pieceRadius, 0, Math.PI * 2);
ctx.stroke();
}
}
}
if (this.gameOver) {
const winner = this.checkWin();
if (winner) {
this.drawWinResult(ctx, winner === 'red' ? '红方胜' : '黑方胜');
}
}
this.update();
}
update() {
}
}