/* A "busy" AI for the BMD Game Author: Brian Go */ include "lib_fsm.bmd" include "stdlib.bmd" bool isAtRisk(point myPosition, bomb list bomblist) { while (bomblist != nil[bomb]) { bomb cur = car bomblist; if ((cur.position.x = myPosition.x) || (cur.position.y = myPosition.y)) { return true; } bomblist = cdr bomblist; } return false; } bool isCurrentlyAtRisk (environment env) { bomb list bomblist = env.visibleBombs; point myPosition = env.playerStatus.position; return isAtRisk(myPosition, bomblist); } bool isFree (point position, TileType array [] array [] map) { TileType tile = map[position.x][position.y]; return (tile != TileType.Brick) && (tile != TileType.Block) && (tile != TileType.Unknown); } moveDirection list getNonRiskyMoves(point myPosition, bomb list bomblist, TileType array [] array[] map) { point north = myPosition; point east = myPosition; point south = myPosition; point west = myPosition; north.y -= 1; east.x += 1; south.y += 1; west.x -= 1; moveDirection list retval = nil[moveDirection]; if(~isAtRisk(north,bomblist) && isFree(north,map)) { retval ::= moveDirection.North; } if(~isAtRisk(east,bomblist) && isFree(east,map)) { retval ::= moveDirection.East; } if(~isAtRisk(south,bomblist) && isFree(south,map)) { retval ::= moveDirection.South; } if(~isAtRisk(west,bomblist) && isFree(west,map)) { retval ::= moveDirection.West; } if(~isAtRisk(myPosition,bomblist)) { retval ::= moveDirection.Void; } return retval; } moveDirection list getFreeMoves(point myPosition, TileType array [] array[] map) { point north = myPosition; point east = myPosition; point south = myPosition; point west = myPosition; north.y -= 1; east.x += 1; south.y += 1; west.x -= 1; moveDirection list retval = [moveDirection.Void]; if(isFree(north,map)) { retval ::= moveDirection.North; } if(isFree(east,map)) { retval ::= moveDirection.East; } if(isFree(south,map)) { retval ::= moveDirection.South; } if(isFree(west,map)) { retval ::= moveDirection.West; } return retval; } bool hasDetonate (environment env) { return env.playerStatus.hasDetonate; } bool hasBomb (environment env) { return (env.playerStatus.maxBombs > env.playerStatus.deployedBombs); } bool hasAnyDeployed (environment env) { return (env.playerStatus.deployedBombs > 0); } bool alwaysTrue (fsmStateInformation info) { return true; } void doNothing0 (point pos) { return; } void doNothing1 () { return; } move moveRequest (environment env) { !(print("A move was requested.\n")); move retval; //At Risk if(isCurrentlyAtRisk(env)){ retval.placeBomb = false; retval.detonate = false; moveDirection list options = getNonRiskyMoves(env.playerStatus.position, env.visibleBombs, env.map); if (options = nil[moveDirection]) { options = getFreeMoves(env.playerStatus.position, env.map); } if (options = nil[moveDirection]) { retval.direction = moveDirection.Void; } else { while((cdr options) != nil[moveDirection]) { float rnd = 0.0; !(rand(),rnd); if (rnd < 0.5) { retval.direction = car options; break; } else { options = cdr options; } } if(null retval.direction) { retval.direction = moveDirection.Void; } } } else { //safe, bomb deployed if(hasAnyDeployed(env)) { retval.placeBomb = false; retval.detonate = true; retval.direction = moveDirection.Void; } //safe, no bomb deployed else { retval.placeBomb = true; retval.detonate = false; moveDirection list options = getNonRiskyMoves(env.playerStatus.position, env.visibleBombs, env.map); if (options = nil[moveDirection]) { options = getFreeMoves(env.playerStatus.position, env.map); } if (options = nil[moveDirection]) { retval.direction = moveDirection.Void; } else { while((cdr options) != nil[moveDirection]) { float rnd = 0.0; !(rand(),rnd); if (rnd < 0.5) { retval.direction = car options; break; } else { options = cdr options; } } if(null retval.direction) { retval.direction = moveDirection.Void; } } } } !(print("Returning a move!\n")); return retval; } stateMachine busyAI { stateMachineInit: doNothing1; state start { onInit: doNothing0; onMoveRequest: moveRequest; onTeammateDeath: doNothing1; onBombDetonate: doNothing0; onDeath: doNothing1; stateTransition { transitionPredicates: alwaysTrue; transitionTargets: start 1.0; } } } void main() { !(print("main has been called.\n")); finiteStateMachine fsm = busyAI(); registerFSM(fsm); }