
El código fuente tiene una IA de búsqueda
La IA de othello-web/lib/ai.ts lee varias jugadas por delante con búsqueda alfa-beta. Si hay muchas casillas vacías lee 4 jugadas, con 12 casillas o menos lee 6 y con 8 casillas o menos lee hasta el final. Evalúa el tablero por los pesos de las casillas, el número de casillas donde se puede jugar, las esquinas y las casillas diagonalmente contiguas a las esquinas (casillas X). El aiplayer.cpp de la app de Qt funciona de la misma manera.
Si se hace que esta IA juegue la secuencia del 13–0, en la 6.ª jugada juega B5 en lugar de D6. No sigue la secuencia de los registros.
Lo que se publicó era otra IA
Desempaquetamos la parte de la IA del código de la página que sirve ahora othello.mariago.kr. No hay búsqueda. Prueba a colocar una ficha una vez en cada casilla donde se puede jugar y elige la de mayor puntuación.
- Puntuación = peso de la casilla×4 + fichas en el tablero + (fichas propias − fichas del rival)×3 − casillas donde puede jugar el rival×2
- Si es una esquina, se suman 40 puntos.
Si se hace que esta IA juegue la secuencia del 13–0, las cuatro jugadas de las blancas coinciden todas con los registros.
La última compilación de la web se hizo 13 minutos antes de guardar la IA de búsqueda. Después no se volvió a compilar, así que en el sitio se quedó la primera IA.
La jugada 8
La imagen de arriba muestra las seis casillas donde pueden jugar las blancas en la jugada 8. En cuatro de ellas, en cuanto juegan, las negras voltean todas las fichas blancas con la jugada siguiente. La IA de una jugada valoró F4 como la más alta, con -12 puntos, y la eligió. Como no mira la siguiente jugada de las negras, no puede ver la aniquilación. La IA de búsqueda ve las cuatro como jugadas perdedoras y elige B6.
Enfrentando las IA entre sí
Enfrentamos tres IA, 100 partidas por pareja. Alternaron negras y blancas, y las 4 primeras jugadas fueron aleatorias para que no saliera siempre la misma partida.
- IA de búsqueda contra IA de una jugada: 100 a 0
- IA de búsqueda contra aleatoria: 99 a 1
- IA de una jugada contra aleatoria: 86 a 10, 4 empates
Las secuencias de las negras que aniquilan a las blancas en 11 jugadas o menos son 2 contra la IA de una jugada y 0 contra la IA de búsqueda.

El código real de esta etapa
Esta es la IA de una jugada desempaquetada del código de la página publicada. Solo se cambiaron los nombres de variables abreviados para que se lean mejor.
IA en la versión publicada
const WEIGHTS = [
[100, -20, 10, 5, 5, 10, -20, 100],
[-20, -50, -2, -2, -2, -2, -50, -20],
[10, -2, 1, 1, 1, 1, -2, 10],
[5, -2, 1, 0, 0, 1, -2, 5],
[5, -2, 1, 0, 0, 1, -2, 5],
[10, -2, 1, 1, 1, 1, -2, 10],
[-20, -50, -2, -2, -2, -2, -50, -20],
[100, -20, 10, 5, 5, 10, -20, 100],
];
function suggestMove(board, who) {
const moves = legalMoves(board, who);
if (moves.length === 0) return null;
const opp = opponent(who);
let best = moves[0];
let bestScore = -1e9;
for (const mv of moves) {
const res = playAt(board, mv.r, mv.c, who, "playing");
if (!res.ok) continue;
const mine = who === BLACK ? res.black : res.white;
const theirs = who === BLACK ? res.white : res.black;
let score = 4 * WEIGHTS[mv.r][mv.c];
score += res.black + res.white;
score += (mine - theirs) * 3;
score -= 2 * legalMoves(res.board, opp).length;
if ((mv.r === 0 || mv.r === 7) && (mv.c === 0 || mv.c === 7)) score += 40;
if (score > bestScore) {
bestScore = score;
best = mv;
}
}
return best;
}Esta es la IA de búsqueda del código fuente.
othello-web/lib/ai.ts
function searchDepth(empties: number): number {
if (empties <= 8) return empties;
if (empties <= 12) return 6;
if (empties <= 20) return 5;
return 4;
}
// ...
function negamax(
board: Stone[],
who: Stone,
depth: number,
alpha: number,
beta: number,
): SearchResult {
const moves = legalMoves(board, who);
const opp = opponent(who);
if (moves.length === 0) {
if (legalMoves(board, opp).length === 0) {
const { black, white } = counts(board);
const mine = who === BLACK ? black : white;
const theirs = who === BLACK ? white : black;
return { score: (mine - theirs) * 100_000, move: null };
}
const child = negamax(board, opp, depth - 1, -beta, -alpha);
return { score: -child.score, move: null };
}
if (depth <= 0) {
return { score: evaluate(board, who), move: null };
}
let bestScore = -Infinity;
let bestMove: Point | null = null;
for (const mv of orderMoves(moves)) {
const res = playAt(board, mv.r, mv.c, who, "playing");
if (!res.ok) continue;
const child = negamax(res.board, opp, depth - 1, -beta, -alpha);
const score = -child.score;
if (score > bestScore) {
bestScore = score;
bestMove = mv;
}
if (score > alpha) alpha = score;
if (alpha >= beta) break;
}
return { score: bestScore, move: bestMove };
}
/** 알파·베타 탐색. 초반은 위치·기동력, 종반은 돌 수를 중시. */
export function suggestMove(board: Stone[], who: Stone): Point | null {
const moves = legalMoves(board, who);
if (moves.length === 0) return null;
if (moves.length === 1) return moves[0]!;
const depth = searchDepth(emptyCount(board));
const { move } = negamax(board, who, depth, -Infinity, Infinity);
return move ?? moves[0]!;
}La siguiente entrada es "3. El VLM nunca jugó: Gemma 4 no se pudo cargar".
COMMENTS · CHAPTER 02
Una IA que solo mira una jugada: la IA publicada no coincidía con el código fuente 0 comentarios
Todavía no hay comentarios. Deja una pregunta o algo que quieras añadir.
Para publicar un comentario, empieza con Google y registra un apodo y un correo.
Empezar con Google