將製作ejcees(中國象棋打譜程式)
Re: 將製作ejcees(中國象棋打譜程式)
https://ejsoon.vip/ejcees20260223commentbtn952/
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
gemini,download and upload
https://ejsoon.vip/wp-content/uploads/2 ... pload.html
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
代码: 全选
/**
* Simulates a move based on coordinates and returns the new FEN string.
* @param {string} fen - The current FEN string before the move.
* @param {number} startX - The starting X coordinate (0-8).
* @param {number} startY - The starting Y coordinate (0-9).
* @param {number} endX - The target X coordinate (0-8).
* @param {number} endY - The target Y coordinate (0-9).
* @returns {string} The new FEN string after the move.
*/
function simulateMove(fen, startX, startY, endX, endY) {
const parts = fen.split(' ');
const boardPart = parts[0];
let turn = parts[1] || 'w';
// 1. Initialize an empty 10x9 board (y: 0-9, x: 0-8)
const board = Array.from({ length: 10 }, () => Array(9).fill(''));
// 2. Parse the current FEN to populate the board array
const rows = boardPart.split('/');
rows.forEach((row, y) => {
let x = 0;
for (let i = 0; i < row.length; i++) {
const char = row[i];
if (/[0-9]/.test(char)) {
// If it's a number, skip that many empty squares
x += parseInt(char, 10);
} else {
// If it's a letter (piece), place it on the board
board[y][x] = char;
x++;
}
}
});
// 3. Extract the moving piece
const piece = board[startY][startX];
// Safety check: ensure there is actually a piece to move
if (!piece) {
console.warn(`simulateMove: No piece found at (${startX}, ${startY})`);
return fen;
}
// 4. Apply the move (remove from start, place at end)
board[startY][startX] = '';
board[endY][endX] = piece; // This automatically overwrites (captures) any existing piece
// 5. Toggle the turn ('w' -> 'b', 'b' -> 'w')
turn = (turn === 'w') ? 'b' : 'w';
// 6. Generate the new FEN string from the updated board array
let newFenBoard = '';
for (let y = 0; y <= 9; y++) {
let emptyCount = 0;
for (let x = 0; x <= 8; x++) {
if (board[y][x] === '') {
emptyCount++;
} else {
if (emptyCount > 0) {
newFenBoard += emptyCount;
emptyCount = 0;
}
newFenBoard += board[y][x];
}
}
// Append any remaining empty spaces at the end of the row
if (emptyCount > 0) {
newFenBoard += emptyCount;
}
// Add row separator, except for the last row
if (y < 9) {
newFenBoard += '/';
}
}
// Return the combined FEN string
return `${newFenBoard} ${turn}`;
}代码: 全选
/**
* Derives start and end coordinates from a FEN string and move notation.
* Handles complex notations like "+C=5", "3p+1", and "+3=7".
* * @param {string} fen - The FEN string before the move.
* @param {string} move - The move notation (e.g., "C2=5", "+n+8", "3p+1").
* @param {boolean} [isRed] - Optional flag indicating if it's Red's turn.
* If not provided, it parses it from the FEN string.
* @returns {Object} An object containing { startX, startY, endX, endY }.
*/
function deriveCoordsFromMove(fen, move, isRed) {
// Determine player color from FEN if not explicitly provided
if (typeof isRed === 'undefined') {
isRed = fen.includes(' w');
}
// 1. Parse the board from FEN to extract piece coordinates
const boardPart = fen.split(' ')[0];
const rows = boardPart.split('/');
let myPieces = [];
rows.forEach((row, y) => {
let x = 0;
for (let i = 0; i < row.length; i++) {
const char = row[i];
if (/[0-9]/.test(char)) {
// Skip empty squares
x += parseInt(char, 10);
} else {
// Check if the piece belongs to the current player
const pieceIsRed = (char >= 'A' && char <= 'Z');
if (pieceIsRed === isRed) {
myPieces.push({ char, x, y });
}
x++;
}
}
});
// 2. Dissect the 4-character move notation
const char1 = move.charAt(0);
const char2 = move.charAt(1);
const action = move.charAt(2);
const val = parseInt(move.slice(3), 10);
let startX = -1;
let startY = -1;
let pieceType = '';
/**
* Helper to select the correct piece based on prefix (+, -, =, 1, 2, 3...)
* Assumes the array is sorted from "Front" to "Back".
*/
const getPieceFromPrefix = (piecesInCol, prefix) => {
if (prefix === '+') return piecesInCol[0];
if (prefix === '-') return piecesInCol[piecesInCol.length - 1];
if (prefix === '=') return piecesInCol[1]; // Middle piece of 3
const num = parseInt(prefix, 10);
if (!isNaN(num) && num > 0) return piecesInCol[num - 1];
return piecesInCol[0]; // Fallback
};
// 3. Identify the moving piece and its starting coordinates
if (/[a-zA-Z]/.test(char1) && /[0-9]/.test(char2)) {
// Case 1: Standard Notation (e.g., "C2=5", "P3+1", "n8+7")
pieceType = isRed ? char1.toUpperCase() : char1.toLowerCase();
const startCol = parseInt(char2, 10);
startX = isRed ? (9 - startCol) : (startCol - 1);
const candidate = myPieces.find(p => p.char === pieceType && p.x === startX);
if (candidate) {
startY = candidate.y;
}
}
else if (/[\+\-\=12345]/.test(char1) && /[a-zA-Z]/.test(char2)) {
// Case 2: Prefix + Piece Notation (e.g., "+C=5", "-n+8")
pieceType = isRed ? char2.toUpperCase() : char2.toLowerCase();
// Group pieces of this specific type by column
const typePieces = myPieces.filter(p => p.char === pieceType);
const colGroups = {};
typePieces.forEach(p => {
if (!colGroups[p.x]) colGroups[p.x] = [];
colGroups[p.x].push(p);
});
// Find the column that actually has multiple pieces of this type
let targetGroup = null;
for (let x in colGroups) {
if (colGroups[x].length > 1) {
targetGroup = colGroups[x];
break; // Usually only one column meets this criteria (except for pawns)
}
}
if (targetGroup) {
// Sort Front to Back: Red Front is smaller Y, Black Front is larger Y
targetGroup.sort((a, b) => isRed ? (a.y - b.y) : (b.y - a.y));
const candidate = getPieceFromPrefix(targetGroup, char1);
if (candidate) {
startX = candidate.x;
startY = candidate.y;
}
}
}
else if (/[\+\-\=12345]/.test(char1) && /[0-9]/.test(char2)) {
// Case 3: Prefix + Column Notation specifically for Pawns (e.g., "+3=4", "25+1")
pieceType = isRed ? 'P' : 'p';
const startCol = parseInt(char2, 10);
startX = isRed ? (9 - startCol) : (startCol - 1);
// Extract all pawns located on this specific column
const targetGroup = myPieces.filter(p => p.char === pieceType && p.x === startX);
if (targetGroup.length > 1) {
// Sort Front to Back
targetGroup.sort((a, b) => isRed ? (a.y - b.y) : (b.y - a.y));
const candidate = getPieceFromPrefix(targetGroup, char1);
if (candidate) {
startY = candidate.y;
}
}
}
// Safety check if notation parsing failed
if (startX === -1 || startY === -1) {
console.error("Failed to derive start coordinates for move:", move);
return null;
}
// 4. Calculate target coordinates (endX, endY)
let endX = -1;
let endY = -1;
// Some pieces use the `val` to represent the target column instead of step count
const valIsEndCol = ['n', 'N', 'b', 'B', 'a', 'A', 'k', 'K'].includes(pieceType);
if (action === '=') {
// Horizontal move: Y stays the same, X is directly derived from the target column
endX = isRed ? (9 - val) : (val - 1);
endY = startY;
} else {
// Vertical or Diagonal move ('+' or '-')
// Direction multiplier: For Red, '+' means moving up (-Y). For Black, '+' means moving down (+Y).
const dir = isRed ? (action === '+' ? -1 : 1) : (action === '+' ? 1 : -1);
if (valIsEndCol) {
// For Knights, Elephants, Advisors, and King: The value indicates the target column
endX = isRed ? (9 - val) : (val - 1);
const dx = Math.abs(endX - startX);
let dy = 0;
const lowerType = pieceType.toLowerCase();
if (lowerType === 'n') {
dy = (dx === 1) ? 2 : 1; // Knight moves in 1x2 or 2x1 L-shape
} else if (lowerType === 'b') {
dy = 2; // Elephant moves 2x2 diagonally
} else if (lowerType === 'a' || lowerType === 'k') {
dy = 1; // Advisor moves 1x1 diagonally, King moves 1 step vertically
}
endY = startY + dir * dy;
} else {
// For linear pieces (Chariot, Cannon, Pawn): The value represents the number of steps
endX = startX;
const steps = val;
endY = startY + dir * steps;
}
}
return { startX, startY, endX, endY };
}
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
需要修複:當只有一列兵或卒時,仍要用「前卒、後卒」,而當這一列兵或卒的數量超過三個時,其處於中間的兵或卒將用「二兵、三兵、四兵」來描述。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
代码: 全选
在function getMoveNotation中,以下這段代碼需要修正:
// --- KEY FIX: Check for ambiguity across different columns ---
if (isPawn && multiPawnCols.length > 1 && prefix !== '=') {
// If more than one column has multiple pawns, use Column Number instead of "Pawn"
location = startCol;
} else {
location = name;
即使有多個兵或卒在同一列,最前面的仍然要用「+」,最後面的仍然要用「-」。
function getMoveNotation(pieceId, startX, startY, endX, endY, capturedId) {
const char = pieceId[0];
const isRed = (char === char.toUpperCase());
const startCol = isRed ? (9 - startX) : (startX + 1);
const endCol = isRed ? (9 - endX) : (endX + 1);
const isPawn = char.toLowerCase() === 'p';
// 1. Find all friendly pieces of the same type
const samePieces = [];
for (const [pos, id] of tileMap.entries()) {
if (id.startsWith(char)) {
const [px, py] = pos.split(',').map(Number);
samePieces.push({
id,
x: px,
y: py
});
}
}
// 2. Identify if multiple columns have multiple pawns (for the "Multi-Pawn Columns" rule)
const multiPawnCols = [];
if (isPawn) {
for (let c = 0; c <= 8; c++) {
const pawnsInThisCol = samePieces.filter(p => p.x === c);
if (pawnsInThisCol.length > 1) {
multiPawnCols.push(c);
}
}
}
// 3. Current column pieces
const colPieces = samePieces.filter(p => p.x === startX);
colPieces.sort((a, b) => a.y - b.y); // Sort by Y ascending (0 is top)
let prefix = '';
let location = '';
const name = char;
if (colPieces.length > 1) {
// Normalize order: Front-to-Back
let sortedInCol = [...colPieces];
if (isRed) {
sortedInCol.sort((a, b) => a.y - b.y); // For Red, smaller Y is "Front"
} else {
sortedInCol.sort((a, b) => b.y - a.y); // For Black, larger Y is "Front"
}
const pIdx = sortedInCol.findIndex(p => p.id === pieceId);
// Determine Prefix (Front/Middle/Back or digits)
if (colPieces.length === 2) {
prefix = (pIdx === 0) ? '+' : '-';
} else if (colPieces.length === 3) {
prefix = (pIdx === 0) ? '+' : (pIdx === 1 ? '=' : '-');
} else {
prefix = pIdx + 1;
}
// --- KEY FIX: Check for ambiguity across different columns ---
if (isPawn && multiPawnCols.length > 1 && prefix !== '=') {
// If more than one column has multiple pawns, use Column Number instead of "Pawn"
location = startCol;
} else {
location = name;
}
} else {
prefix = name;
location = startCol;
}
// 4. Action and Value
let action = '';
let val = 0;
if (startY === endY) {
action = '=';
val = endCol;
} else {
const isAdvancing = isRed ? (startY > endY) : (startY < endY);
action = isAdvancing ? '+' : '-';
val = (['n', 'N', 'b', 'B', 'a', 'A', 'k', 'K'].includes(char)) ? endCol : Math.abs(startY - endY);
}
return prefix + location + action + val;
}
一並連同function deriveCoordsFromMove也要修正:
/**
* Derives start and end coordinates from a FEN string and move notation.
* Handles complex notations like "+C=5", "3p+1", and "+3=7".
* * @param {string} fen - The FEN string before the move.
* @param {string} move - The move notation (e.g., "C2=5", "+n+8", "3p+1").
* @param {boolean} [isRed] - Optional flag indicating if it's Red's turn.
* If not provided, it parses it from the FEN string.
* @returns {Object} An object containing { startX, startY, endX, endY }.
*/
function deriveCoordsFromMove(fen, move, isRed) {
// Determine player color from FEN if not explicitly provided
if (typeof isRed === 'undefined') {
isRed = fen.includes(' w');
}
// 1. Parse the board from FEN to extract piece coordinates
const boardPart = fen.split(' ')[0];
const rows = boardPart.split('/');
let myPieces = [];
rows.forEach((row, y) => {
let x = 0;
for (let i = 0; i < row.length; i++) {
const char = row[i];
if (/[0-9]/.test(char)) {
// Skip empty squares
x += parseInt(char, 10);
} else {
// Check if the piece belongs to the current player
const pieceIsRed = (char >= 'A' && char <= 'Z');
if (pieceIsRed === isRed) {
myPieces.push({
char,
x,
y
});
}
x++;
}
}
});
// 2. Dissect the 4-character move notation
const char1 = move.charAt(0);
const char2 = move.charAt(1);
const action = move.charAt(2);
const val = parseInt(move.slice(3), 10);
let startX = -1;
let startY = -1;
let pieceType = '';
/**
* Helper to select the correct piece based on prefix (+, -, =, 1, 2, 3...)
* Assumes the array is sorted from "Front" to "Back".
*/
const getPieceFromPrefix = (piecesInCol, prefix) => {
if (prefix === '+') return piecesInCol[0];
if (prefix === '-') return piecesInCol[piecesInCol.length - 1];
if (prefix === '=') return piecesInCol[1]; // Middle piece of 3
const num = parseInt(prefix, 10);
if (!isNaN(num) && num > 0) return piecesInCol[num - 1];
return piecesInCol[0]; // Fallback
};
// 3. Identify the moving piece and its starting coordinates
if (/[a-zA-Z]/.test(char1) && /[0-9]/.test(char2)) {
// Case 1: Standard Notation (e.g., "C2=5", "P3+1", "n8+7")
pieceType = isRed ? char1.toUpperCase() : char1.toLowerCase();
const startCol = parseInt(char2, 10);
startX = isRed ? (9 - startCol) : (startCol - 1);
const candidate = myPieces.find(p => p.char === pieceType && p.x === startX);
if (candidate) {
startY = candidate.y;
}
} else if (/[\+\-\=12345]/.test(char1) && /[a-zA-Z]/.test(char2)) {
// Case 2: Prefix + Piece Notation (e.g., "+C=5", "-n+8")
pieceType = isRed ? char2.toUpperCase() : char2.toLowerCase();
// Group pieces of this specific type by column
const typePieces = myPieces.filter(p => p.char === pieceType);
const colGroups = {};
typePieces.forEach(p => {
if (!colGroups[p.x]) colGroups[p.x] = [];
colGroups[p.x].push(p);
});
// Find the column that actually has multiple pieces of this type
let targetGroup = null;
for (let x in colGroups) {
if (colGroups[x].length > 1) {
targetGroup = colGroups[x];
break; // Usually only one column meets this criteria (except for pawns)
}
}
if (targetGroup) {
// Sort Front to Back: Red Front is smaller Y, Black Front is larger Y
targetGroup.sort((a, b) => isRed ? (a.y - b.y) : (b.y - a.y));
const candidate = getPieceFromPrefix(targetGroup, char1);
if (candidate) {
startX = candidate.x;
startY = candidate.y;
}
}
} else if (/[\+\-\=12345]/.test(char1) && /[0-9]/.test(char2)) {
// Case 3: Prefix + Column Notation specifically for Pawns (e.g., "+3=4", "25+1")
pieceType = isRed ? 'P' : 'p';
const startCol = parseInt(char2, 10);
startX = isRed ? (9 - startCol) : (startCol - 1);
// Extract all pawns located on this specific column
const targetGroup = myPieces.filter(p => p.char === pieceType && p.x === startX);
if (targetGroup.length > 1) {
// Sort Front to Back
targetGroup.sort((a, b) => isRed ? (a.y - b.y) : (b.y - a.y));
const candidate = getPieceFromPrefix(targetGroup, char1);
if (candidate) {
startY = candidate.y;
}
}
}
// Safety check if notation parsing failed
if (startX === -1 || startY === -1) {
console.error("Failed to derive start coordinates for move:", move);
return null;
}
// 4. Calculate target coordinates (endX, endY)
let endX = -1;
let endY = -1;
// Some pieces use the `val` to represent the target column instead of step count
const valIsEndCol = ['n', 'N', 'b', 'B', 'a', 'A', 'k', 'K'].includes(pieceType);
if (action === '=') {
// Horizontal move: Y stays the same, X is directly derived from the target column
endX = isRed ? (9 - val) : (val - 1);
endY = startY;
} else {
// Vertical or Diagonal move ('+' or '-')
// Direction multiplier: For Red, '+' means moving up (-Y). For Black, '+' means moving down (+Y).
const dir = isRed ? (action === '+' ? -1 : 1) : (action === '+' ? 1 : -1);
if (valIsEndCol) {
// For Knights, Elephants, Advisors, and King: The value indicates the target column
endX = isRed ? (9 - val) : (val - 1);
const dx = Math.abs(endX - startX);
let dy = 0;
const lowerType = pieceType.toLowerCase();
if (lowerType === 'n') {
dy = (dx === 1) ? 2 : 1; // Knight moves in 1x2 or 2x1 L-shape
} else if (lowerType === 'b') {
dy = 2; // Elephant moves 2x2 diagonally
} else if (lowerType === 'a' || lowerType === 'k') {
dy = 1; // Advisor moves 1x1 diagonally, King moves 1 step vertically
}
endY = startY + dir * dy;
} else {
// For linear pieces (Chariot, Cannon, Pawn): The value represents the number of steps
endX = startX;
const steps = val;
endY = startY + dir * steps;
}
}
return {
startX,
startY,
endX,
endY
};
}
給出修正後的完整代碼,並告知所改動的地方。https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
代码: 全选
const timestamp = now.toISOString().replace(/[-T:.Z]/g, '').slice(0, 14);
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
const timestamp = now.toISOString().replace(/[-T:.Z]/g, '').slice(0, 14);
跟當前系統時間不符,修正為系統時間。
<span class="branch-delete-icon">刪除</span>
把「刪除」二字,替換成跟「btn-del-move」一樣的svg圖標。
把tool-open的圖標,換成另一個更像是「打開文件」的svg圖標。
只需給出要修改的地方,所有的代碼和注釋都要使用英文。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
https://ejsoon.vip/wp-content/uploads/2 ... ave96.html
(臨時文件)
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
代码: 全选
{"v":[{"m":"C2=5","v":[{"m":"c2=5","v":[{"m":"N2+3","v":[{"m":"n8+9","v":[{"m":"R1=2","v":[{"m":"r9=8","v":[{"m":"N8+7","v":[{"m":"n2+3","v":[{"m":"C8+4","v":[{"m":"r1+1","v":[{"m":"P7+1","v":[{"m":"r1=6","v":[{"m":"C5=6","v":[{"m":"p9+1","v":[{"m":"P3+1","c":"應直接跳馬","v":[{"m":"r6+3","v":[{"m":"N7+6","v":[{"m":"r6=2","v":[{"m":"P7+1","c":"炮被捉死,只好拱兵","v":[{"m":"r2-1","v":[{"m":"P7+1","v":[{"m":"r2+2","v":[{"m":"N6+4","v":[{"m":"n3-5","v":[{"m":"C6=5","v":[{"m":"r2=7","c":"黑方不夠穩健,應提砲看中卒。","v":[{"m":"C5+4","v":[{"m":"r7+2","v":[{"m":"N4+6","v":[{"m":"r7=4","v":[{"m":"R9+2","v":[{"m":"r4-3","v":[{"m":"R9=4","v":[{"m":"c8+1","v":[{"m":"R2+6","v":[{"m":"r8+3","v":[{"m":"A4+5","v":[{"m":"n9-8","v":[{"m":"C5=2","c":"錯誤,應先出帥","v":[{"m":"n5+7","v":[{"m":"N6+4","v":[{"m":"k5+5","v":[{"m":"P7+1","v":[{"m":"b7+9","v":[{"m":"C2=9","v":[{"m":"n8+6","v":[{"m":"C9=4","v":[{"m":"p7+1","v":[{"m":"C4+2","v":[{"m":"k5=6","v":[{"m":"P7=6","v":[{"m":"c5-2","c":"敗著!應直接兌車","v":[{"m":"N4-6","c":"妙手!回馬即擋住黑方吃兵,又能使對方不能兌車","v":[{"m":"k6=5","c":"錯過最後一次求和的機會,此時黑方應跳馬擋住","v":[{"m":"K5=4","v":[{"m":"c5+6","v":[{"m":"P6=5","c":"妙著連連,黑方招架不住","v":[{"m":"k5=4","v":[{"m":"N6+8","c":"紅勝"}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}],"fen":"rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w"}https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
代码: 全选
{"v":[{"m":"C2=5","v":[{"m":"c2=5","v":[{"m":"N2+3","v":[{"m":"n8+9","v":[{"m":"R1=2","v":[{"m":"r9=8","v":[{"m":"N8+7","v":[{"m":"n2+3","v":[{"m":"C8+4","v":[{"m":"p3+1","v":[{"m":"R2+5","v":[{"m":"r1=2","v":[{"m":"R9=8","v":[{"m":"c8=7","v":[{"m":"R2=7","v":[{"m":"r8+8","v":[{"m":"C5=6","v":[{"m":"r8=3","v":[{"m":"R8+2","v":[{"m":"r3+1","v":[{"m":"B3+5","v":[{"m":"r3-1","v":[{"m":"A4+5","v":[{"m":"p5+1","v":[{"m":"R7+1","v":[{"m":"p5+1","v":[{"m":"P5+1","v":[{"m":"r3-1","v":[{"m":"R8+2","v":[{"m":"r2+2","v":[{"m":"P5+1","v":[{"m":"p9+1","v":[{"m":"P5+1","v":[{"m":"c5+5","v":[{"m":"K5=4","v":[{"m":"a4+5","v":[{"m":"N3+5","v":[{"m":"r3+1","v":[{"m":"N5+4","v":[{"m":"c7-1","v":[{"m":"N4+6","v":[{"m":"n3-4","v":[{"m":"R8=4","v":[{"m":"r3-1","v":[{"m":"R4+4","v":[{"m":"r2=6","v":[{"m":"P5=4","v":[{"m":"r6=3","v":[{"m":"N6+7","v":[{"m":"-r-1","v":[{"m":"R7+2","v":[{"m":"r3=2","v":[{"m":"C8=5","v":[{"m":"b3+5","v":[{"m":"P4=3","c":"黑方認輸"}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}],"fen":"rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w"}https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
在线用户
正浏览此版面之用户: 没有注册用户 和 1 访客
