A. M. DeWitt wrote on Sat, Jan 21, 2023 03:20 PM UTC:
I'm having a problem with Suzumu Shogi's interactive diagram. I managed to get the Fire Demon's burning restriction implemented properly in the pieceZone function using the clicks array, but as it turns out, clicks is not used by the AI's move generator, so the AI doesn't work properly. I was wondering if there is a similar array used by the AI to keep track of the squares it visits?
In case you need it, here is the relevant portion of the pieceZone code and its supporting functions (I left the rest out, since it is quite complicated)
function pieceZone(x2, y2, piece, color, x1, y1, ex, ey)
{
if(touched) return 0; // not during ShowMoves()
// ... Heavenly Tetrarch Section ...
// Fire Demon
v = board[y2][x2] & 511; // Highlight square
firstX = (clicks.length >= 4) ? clicks[2] : -1;
firstY = (clicks.length >= 4) ? clicks[3] : -1;
firstVictim = (clicks.length >= 4) ? board[firstY][firstX] & 511 : -1;
secondX = (clicks.length >= 6) ? clicks[4] : -1;
secondY = (clicks.length >= 6) ? clicks[5] : -1;
secondVictim = (clicks.length >= 6) ? board[secondY][secondX] & 511 : -1;
if(isBurner(p))
{
// Always allow starting square
if(x2 == x1 && y2 == y1) return 0;
// Reject captures of Fire Demon outside normal range
if(isBurner(v) && !nonBurningRange(x1, y1, x2, y2)) return 1;
// Allow direct capture of Fire Demon with second burn after first burn
if(firstVictim > 0 && !isBurner(firstVictim) && clicks.length == 4)
{
if(isBurner(v) && nonBurningRange(x1, y1, x2, y2) && canBurn(x2, y2, firstX, firstY)) return 0;
}
// If first victim is a Fire Demon, allow move to start square, reject moving to empty square or burning another Fire Demon
if(isBurner(firstVictim))
{
// Always allow starting square
if(x2 == x1 && y2 == y1) return 0;
// If a Fire Demon was captured via igui, always allow second burn of Fire Demon
if(isBurner(firstVictim) && secondX == x1 && secondY == y1) return 0;
// if second victim is not an empty square or a Fire Demon, only allow single burn
if(secondVictim > 0 && !isBurner(secondVictim)) return !(x2 == secondX && y2 == secondY);
// Reject moves to empty square or burn of Fire Demon
else return (v == 0 || (isBurner(v) && (x2 != firstX || y2 != firstY)));
}
// If first victim is not a Fire Demon, allow direct capture with optional second burn, reject burn of another Fire Demon
else
{
if(firstVictim != -1 && !isBurner(firstVictim))
{
if(isBurner(v)) return 1;
}
}
}
// ... Range Capturing Pieces Section ...
return 0;
}
// Supporting Functions
// Checks whether the destination (x2, y2) is within the Fire Demon's non-burning range
function nonBurningRange(x1, y1, x2, y2)
{
return checkAreaMove(x1, y1, x1, y1, x2, y2, 3)
|| checkARide(x1, y1, x1, y1, 1, 1, x2, y2)
|| checkARide(x1, y1, x1, y1, 1, 0, x2, y2)
|| checkARide(x1, y1, x1, y1, 1, -1, x2, y2)
|| checkARide(x1, y1, x1, y1, -1, 1, x2, y2)
|| checkARide(x1, y1, x1, y1, -1, 0, x2, y2)
|| checkARide(x1, y1, x1, y1, -1, -1, x2, y2);
}
// Checks whether the moving Fire Demon can burn a second time
function canBurn(x, y, fx, fy)
{
var piece, i, j, l=(x ? x-1 : 0), r=(x==(files-1) ? files-1 : x+1), t=(y==(ranks-1) ? ranks-1 : y+1), b=(y ? y-1 : 0);
for(i=b; i<=t; i++) for(j=l; j<=r; j++) if((i!=y || j!=x) && (i!=fy || j!=fx)) {
pc = board[i][j] & 511;
if(pc > 0 && !isBurner(pc) && !((board[i][j] ^ board[y][x]) & 1024))
{
return true;
}
}
return false;
}
// Checks whether move is within an n-step area move
function checkAreaMove(ox, oy, x1, y1, x2, y2, steps)
{
// Verify origin and destination coords are real.
if(ox < 0 || ox > (files-1) || oy < 0 || oy > (ranks-1)) return false;
if(x2 < 0 || x2 > (files-1) || y2 < 0 || y2 > (ranks-1)) return false;
// Always allow start square.
if(x2 == ox && y2 == oy) return true;
// Path has stopped. Did we make it?
if(steps < 1) return x1 == x2 && y1 == y2;
// Check if we have made it already.
if(x1 == x2 && y1 == y2) return true;
// Verify coords of current square are real.
if(x1 < 0 || x1 > files-1 || y1 < 0 || y1 > ranks-1) return false;
// Set changeX and changeY for area move checks.
changeX = Math.abs(x2-x1);
changeY = Math.abs(y2-y1);
// Path blocked.
if((board[y1][x1] & 511) != 0 && (x1 != ox || y1 != oy)) return false;
// Too far away.
if(changeX > steps || changeY > steps) return false;
// Succeed, dest is one step away.
if(steps >= 1 && changeX <= 1 && changeY <= 1) return true;
// Decrement max number of steps for next King step in path.
--steps;
// Next King step in path.
return checkAreaMove(ox, oy, x1-1, y1-1, x2, y2, steps)
|| checkAreaMove(ox, oy, x1-1, y1, x2, y2, steps)
|| checkAreaMove(ox, oy, x1-1, y1+1, x2, y2, steps)
|| checkAreaMove(ox, oy, x1, y1-1, x2, y2, steps)
|| checkAreaMove(ox, oy, x1, y1+1, x2, y2, steps)
|| checkAreaMove(ox, oy, x1+1, y1-1, x2, y2, steps)
|| checkAreaMove(ox, oy, x1+1, y1, x2, y2, steps)
|| checkAreaMove(ox, oy, x1+1, y1+1, x2, y2, steps);
}
// Checks whether move is within a slide in the direction (cx,cy)
function checkARide(ox, oy, x1, y1, cx, cy, x2, y2)
{
// Verify coords are real.
if(ox < 0 || ox > files-1 || oy < 0 || oy > ranks-1) return false;
if(x2 < 0 || x2 > files-1 || y2 < 0 || y2 > ranks-1) return false;
if(x1 < 0 || x1 > files-1 || y1 < 0 || y1 > ranks-1) return false;
// Set cx and cy for next step in path.
// Always allow start square.
if(x2 == ox && y2 == oy) return true;
// No checking self.
if(x1 == ox && y1 == oy) return checkARide(ox, oy, x1+cx, y1+cy, cx, cy, x2, y2); // No checking self
// Succeed if made it already.
if(x1 == x2 && y1 == y2) return true;
// Fail if path is blocked.
else if((board[y1][x1] & 511) != 0 && (x1 != ox || y1 != oy)) return false;
// Next square in path.
return checkARide(ox, oy, x1+cx, y1+cy, cx, cy, x2, y2);
}
// Returns the piece numbers of the Fire Demons
function isBurner(p)
{
return p == 35 || p == 66; // Fire Demon
}
I'm having a problem with Suzumu Shogi's interactive diagram. I managed to get the Fire Demon's burning restriction implemented properly in the pieceZone function using the clicks array, but as it turns out, clicks is not used by the AI's move generator, so the AI doesn't work properly. I was wondering if there is a similar array used by the AI to keep track of the squares it visits?
In case you need it, here is the relevant portion of the pieceZone code and its supporting functions (I left the rest out, since it is quite complicated)