/* A "runner" AI for the BMD Game Author: Brian Go */ include "lib_fsm.bmd" include "stdlib.bmd" moveDirection currentDirection; void doNothing0 (point pos) { return; } string string_of_direction(moveDirection dir) { if(dir = moveDirection.North) { return "Heading North.\n"; } else if (dir = moveDirection.East) { return "Heading East.\n"; } else if (dir = moveDirection.South) { return "Heading South.\n"; } else if (dir = moveDirection.West) { return "Heading West.\n"; } else { return "Staying put.\n"; } } enum bombDeploymentPhase {Starting, Backtracking, Retracing, Turning, Done }; string string_of_deployment(bombDeploymentPhase phase) { if (phase = bombDeploymentPhase.Starting) { return "Starting\n"; } else if (phase = bombDeploymentPhase.Backtracking) { return "Backtracking\n"; } else if (phase = bombDeploymentPhase.Retracing) { return "Retracing\n"; } else if (phase = bombDeploymentPhase.Turning) { return "Turning\n"; } else if (phase = bombDeploymentPhase.Done) { return "Done\n"; } } bombDeploymentPhase currentBombDeploymentPhase; void resetBombDeployment () { currentBombDeploymentPhase = bombDeploymentPhase.Starting; return; } void doNothing1 () { return; } void chooseRandomDirection(point p) { moveDirection array [4] directions = {moveDirection.North, moveDirection.East, moveDirection.South, moveDirection.West}; float randresult = 0.0; !(rand(),randresult); currentDirection = directions [trunc (randresult * 3)]; } void reverseDirection() { if(currentDirection = moveDirection.North) { currentDirection = moveDirection.South; } else if(currentDirection = moveDirection.East) { currentDirection = moveDirection.West; } else if(currentDirection = moveDirection.South) { currentDirection = moveDirection.North; } else if(currentDirection = moveDirection.West) { currentDirection = moveDirection.East; } return; } moveDirection getRightTurn (moveDirection dir) { if(dir = moveDirection.North) { return moveDirection.East; } else if (dir = moveDirection.East) { return moveDirection.South; } else if (dir = moveDirection.South) { return moveDirection.West; } else if (dir = moveDirection.West) { return moveDirection.North; } else { return moveDirection.Void; } } moveDirection getLeftTurn (moveDirection dir) { if(dir = moveDirection.North) { return moveDirection.West; } else if (dir = moveDirection.East) { return moveDirection.North; } else if (dir = moveDirection.South) { return moveDirection.East; } else if (dir = moveDirection.West) { return moveDirection.South; } else { return moveDirection.Void; } } move movingMoveRequest(environment env) { currentBombDeploymentPhase = bombDeploymentPhase.Starting; move ret; ret.direction = currentDirection; ret.placeBomb = false; ret.detonate = false; return ret; } move deadEndMoveRequest(environment env) { reverseDirection(); move ret; ret.direction = currentDirection; ret.placeBomb = false; ret.detonate = false; return ret; } move rightCornerMoveRequest(environment env) { !(print(string_of_deployment(currentBombDeploymentPhase))); if(currentBombDeploymentPhase = bombDeploymentPhase.Starting) { currentBombDeploymentPhase = bombDeploymentPhase.Backtracking; move ret; ret.placeBomb = false; ret.detonate = false; reverseDirection(); ret.direction = currentDirection; reverseDirection(); return ret; } else if(currentBombDeploymentPhase = bombDeploymentPhase.Backtracking) { currentBombDeploymentPhase = bombDeploymentPhase.Retracing; move ret; ret.placeBomb = true; ret.detonate = true; ret.direction = currentDirection; return ret; } else if(currentBombDeploymentPhase = bombDeploymentPhase.Retracing) { currentBombDeploymentPhase = bombDeploymentPhase.Turning; move ret; ret.placeBomb = false; ret.detonate = false; currentDirection = getRightTurn(currentDirection); ret.direction = currentDirection; return ret; } else { currentBombDeploymentPhase = bombDeploymentPhase.Done; move ret; ret.placeBomb = false; ret.detonate = false; ret.direction = currentDirection; return ret; } } move leftCornerMoveRequest(environment env) { !(print(string_of_deployment(currentBombDeploymentPhase))); if(currentBombDeploymentPhase = bombDeploymentPhase.Starting) { currentBombDeploymentPhase = bombDeploymentPhase.Backtracking; move ret; ret.placeBomb = false; ret.detonate = false; reverseDirection(); ret.direction = currentDirection; return ret; } else if(currentBombDeploymentPhase = bombDeploymentPhase.Backtracking) { currentBombDeploymentPhase = bombDeploymentPhase.Retracing; move ret; ret.placeBomb = true; ret.detonate = true; reverseDirection(); ret.direction = currentDirection; return ret; } else if(currentBombDeploymentPhase = bombDeploymentPhase.Retracing) { currentBombDeploymentPhase = bombDeploymentPhase.Turning; move ret; ret.placeBomb = false; ret.detonate = false; currentDirection = getLeftTurn(currentDirection); ret.direction = currentDirection; return ret; } else { currentBombDeploymentPhase = bombDeploymentPhase.Done; move ret; ret.placeBomb = false; ret.detonate = false; ret.direction = currentDirection; return ret; } } bool isFree(point pos, fsmStateInformation info) { TileType array [] array [] map = info.latestEnvironment.map; TileType tile = map[pos.x][pos.y]; return ((tile != TileType.Block) && (tile != TileType.Brick)); } point getNextPosition(point pos, moveDirection dir){ int xoff = 0; int yoff = 0; if(dir = moveDirection.North) { yoff = -1; } else if (dir = moveDirection.East) { xoff = 1; } else if (dir = moveDirection.South) { yoff = 1; } else if (dir = moveDirection.West) { xoff = -1; } point newpos; newpos.x = pos.x + xoff; newpos.y = pos.y + yoff; return newpos; } bool alwaysTrue (fsmStateInformation info) { return true; } bool predIsBlocked (fsmStateInformation info) { return isFree(getNextPosition(info.latestPosition, currentDirection), info); } bool predNotBlocked (fsmStateInformation info) { return ~predIsBlocked(info); } bool predRightTurnMoveOption(fsmStateInformation info) { return isFree(getNextPosition(info.latestPosition, getRightTurn(currentDirection)), info); } bool predLeftTurnMoveOption(fsmStateInformation info) { return isFree(getNextPosition(info.latestPosition, getLeftTurn(currentDirection)), info); } bool predDeadEnd (fsmStateInformation info) { return (predIsBlocked(info) && ~predRightTurnMoveOption(info) && ~predLeftTurnMoveOption(info)); } bool isDoneBombPlanting (fsmStateInformation info) { return (currentBombDeploymentPhase = bombDeploymentPhase.Done); } stateMachine runnerAI { stateMachineInit: chooseRandomDirection; state start { onInit: resetBombDeployment; onMoveRequest: movingMoveRequest; onTeammateDeath: doNothing1; onBombDetonate: doNothing0; onDeath: doNothing1; stateTransition { transitionPredicates: alwaysTrue; transitionTargets: moving 1.0; } } state moving { onInit: resetBombDeployment; onMoveRequest: movingMoveRequest; onTeammateDeath: doNothing1; onBombDetonate: doNothing0; onDeath: doNothing1; stateTransition { transitionPredicates: predNotBlocked; transitionTargets: moving 1.0; } stateTransition { transitionPredicates: predIsBlocked, predDeadEnd; transitionTargets: stoppedAtDeadEnd 1.0; } stateTransition { transitionPredicates: predIsBlocked, predRightTurnMoveOption; transitionTargets: stoppedAtRightCorner 1.0; } stateTransition { transitionPredicates: predIsBlocked, predLeftTurnMoveOption; transitionTargets: stoppedAtLeftCorner 1.0; } } state stoppedAtDeadEnd { onInit: doNothing1; onMoveRequest: deadEndMoveRequest; onTeammateDeath: doNothing1; onBombDetonate: doNothing0; onDeath: doNothing1; stateTransition { transitionPredicates: alwaysTrue; transitionTargets: moving 1.0; } } state stoppedAtRightCorner { onInit: doNothing1; onMoveRequest: rightCornerMoveRequest; onTeammateDeath: doNothing1; onBombDetonate: doNothing0; onDeath: doNothing1; stateTransition { transitionPredicates: isDoneBombPlanting; transitionTargets: moving 1.0; } } state stoppedAtLeftCorner { onInit: doNothing1; onMoveRequest: leftCornerMoveRequest; onTeammateDeath: doNothing1; onBombDetonate: doNothing0; onDeath: doNothing1; stateTransition { transitionPredicates: isDoneBombPlanting; transitionTargets: moving 1.0; } } } void main() { finiteStateMachine fsm = runnerAI(); registerFSM(fsm); }