Spec 01 four distinct ghosts #1
+47
-8
@@ -110,9 +110,52 @@ function movePacman( game ) {
|
||||
wrapTunnel( p, width );
|
||||
}
|
||||
|
||||
// Celda situada `n` casillas por delante de Pac-Man segun su direccion.
|
||||
// Las columnas se mantienen dentro del laberinto con clamp; si el offset
|
||||
// se sale lateralmente por el tunel, la columna se ancla a la de Pac-Man.
|
||||
function aheadOfPacman( game, n ) {
|
||||
const p = game.pacman;
|
||||
const W = game.grid[ 0 ].length;
|
||||
const d = DIRS[ p.dir ] || { x: 0, y: 0 };
|
||||
const px = Math.round( p.x );
|
||||
const py = Math.round( p.y );
|
||||
const ty = py + d.y * n;
|
||||
if ( ty === TUNNEL_ROW ) return { x: px, y: ty };
|
||||
return { x: Math.max( 0, Math.min( W - 1, px + d.x * n ) ), y: ty };
|
||||
}
|
||||
|
||||
// Objetivo de cada arquetipo. Las cuatro ramas comparten el filtro de
|
||||
// candidatos y el desempate; solo cambia la celda contra la que se compara.
|
||||
function ghostTarget( game, g ) {
|
||||
const p = game.pacman;
|
||||
const px = Math.round( p.x );
|
||||
const py = Math.round( p.y );
|
||||
|
||||
// Blinky: perseguir sin mas.
|
||||
if ( g.kind === 'blinky' ) return { x: px, y: py };
|
||||
|
||||
// Pinky: emboscarse 4 casillas por delante.
|
||||
if ( g.kind === 'pinky' ) return aheadOfPacman( game, 4 );
|
||||
|
||||
// Inky: flanquear, reflejando a Blinky sobre el pivot a 2 casillas delante.
|
||||
if ( g.kind === 'inky' ) {
|
||||
const pivot = aheadOfPacman( game, 2 );
|
||||
const blinky = game.ghosts.find( ( o ) => o.kind === 'blinky' );
|
||||
// Sin Blinky (defensivo, no ocurre hoy) Pinky hace de suplente.
|
||||
if ( !blinky ) return aheadOfPacman( game, 4 );
|
||||
return {
|
||||
x: 2 * pivot.x - Math.round( blinky.x ),
|
||||
y: 2 * pivot.y - Math.round( blinky.y ),
|
||||
};
|
||||
}
|
||||
|
||||
// Clyde: persigue mientras este lejos y se retira a su esquina si se acerca.
|
||||
if ( Math.abs( g.x - px ) + Math.abs( g.y - py ) > 8 ) return { x: px, y: py };
|
||||
return { x: 0, y: 30 };
|
||||
}
|
||||
|
||||
function decideGhost( game, g ) {
|
||||
const grid = game.grid;
|
||||
const p = game.pacman;
|
||||
|
||||
const options = Object.keys( DIRS ).filter(
|
||||
( dir ) => dir !== OPPOSITE[ g.dir ] && canMove( grid, g.x, g.y, dir, 'ghost' )
|
||||
@@ -120,25 +163,21 @@ function decideGhost( game, g ) {
|
||||
// Sin salida (callejon): permitir el giro de 180.
|
||||
const choices = options.length ? options : [ '' + OPPOSITE[ g.dir ] ];
|
||||
|
||||
if ( g.kind === 'hunter' ) {
|
||||
const px = Math.round( p.x );
|
||||
const py = Math.round( p.y );
|
||||
const target = ghostTarget( game, g );
|
||||
|
||||
let best = choices[ 0 ];
|
||||
let bestDist = Infinity;
|
||||
for ( const dir of choices ) {
|
||||
const d = DIRS[ dir ];
|
||||
const nx = g.x + d.x;
|
||||
const ny = g.y + d.y;
|
||||
const dist = Math.abs( nx - px ) + Math.abs( ny - py );
|
||||
const dist = Math.abs( nx - target.x ) + Math.abs( ny - target.y );
|
||||
if ( dist < bestDist ) {
|
||||
bestDist = dist;
|
||||
best = dir;
|
||||
}
|
||||
}
|
||||
g.dir = best;
|
||||
} else {
|
||||
g.dir = choices[ Math.floor( Math.random() * choices.length ) ];
|
||||
}
|
||||
}
|
||||
|
||||
function moveGhost( game, g ) {
|
||||
|
||||
+7
-2
@@ -51,9 +51,14 @@ const MAZE = MAZE_STR.map( ( row ) => row.split( '' ).map( parseTile ) );
|
||||
|
||||
const TUNNEL_ROW = 14;
|
||||
const PACMAN_START = { x: 13, y: 23 };
|
||||
// Los cuatro arquetipos clasicos, dentro de la pen. Simetricos respecto al
|
||||
// eje vertical (cols 11<->16, 13<->14) y en el orden de GHOST_COLORS de
|
||||
// render.js (blinky rojo, pinky cyan, inky rosa, clyde naranja).
|
||||
const GHOST_STARTS = [
|
||||
{ x: 13, y: 14, kind: 'hunter' }, // dentro de la pen
|
||||
{ x: 14, y: 14, kind: 'random' }, // dentro de la pen
|
||||
{ x: 11, y: 14, kind: 'blinky' },
|
||||
{ x: 13, y: 14, kind: 'pinky' },
|
||||
{ x: 14, y: 14, kind: 'inky' },
|
||||
{ x: 16, y: 14, kind: 'clyde' },
|
||||
];
|
||||
|
||||
window.MAZE = MAZE;
|
||||
|
||||
Reference in New Issue
Block a user