Last active
August 8, 2018 18:35
-
-
Save 01010111/79b7376dfdbed53a30f304d39e9f2195 to your computer and use it in GitHub Desktop.
Haxe GOAP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package util; | |
using util.Goap.Planner; | |
class Goap {} | |
class Planner | |
{ | |
public static function plan(agent:IGoapAgent):Null<GoapTask> | |
{ | |
var satisfactory_tasks = agent.get_available_tasks().get_satisfactory_tasks(); | |
if (satisfactory_tasks.length > 0) return satisfactory_tasks[0]; | |
return agent.find_best_next_step(); | |
} | |
static function find_best_next_step(agent:IGoapAgent):Null<GoapTask> | |
{ | |
var goal = [ENEMY_DEFEATED]; | |
var queue = agent.get_required_task_set(goal); | |
var task:GoapTask; | |
while(queue.length > 0) | |
{ | |
queue.sort((task1:GoapTask, task2:GoapTask) -> return task1.cost < task2.cost ? -1 : 1); | |
task = queue.shift(); | |
goal = agent.get_prerequisites(task); | |
if (goal.length == 0) return task; | |
for (task in agent.get_required_task_set(goal)) queue.push(task); | |
} | |
return null; | |
} | |
static function get_available_tasks(agent:IGoapAgent):Array<GoapTask> | |
{ | |
var available_tasks = []; | |
for (task in agent.job.tasks) | |
{ | |
var add = true; | |
for (prerequisite in task.prerequisites) add ? add = agent.state[prerequisite] : break; | |
if (add) available_tasks.push(task); | |
} | |
return available_tasks; | |
} | |
static function get_satisfactory_tasks(tasks:Array<GoapTask>):Array<GoapTask> | |
{ | |
var satisfactory_tasks = [ for (task in tasks) if (task.effects.indexOf(ENEMY_DEFEATED) >= 0) task ]; | |
satisfactory_tasks.sort((task1:GoapTask, task2:GoapTask) -> return task1.cost < task2.cost ? -1 : 1); | |
return satisfactory_tasks; | |
} | |
static function get_required_task_set(agent:IGoapAgent, requirements:Array<EGoapState>):Array<GoapTask> | |
{ | |
var required_task_set = []; | |
for (task in agent.job.tasks) for (requirement in requirements) if (task.effects.indexOf(requirement) >= 0) required_task_set.push(task); | |
return required_task_set; | |
} | |
static function get_prerequisites(agent:IGoapAgent, task:GoapTask):Array<EGoapState> | |
{ | |
var prerequisites = []; | |
for (prerequisite in task.prerequisites) if (!agent.state[prerequisite]) prerequisites.push(prerequisite); | |
return prerequisites; | |
} | |
} | |
class GoapJobs | |
{ | |
public static var JOBS:Map<EGoapJob, GoapJob> = [ | |
COMMS => { | |
name: COMMS, | |
tasks: [ | |
ATTACK => { name: ATTACK, prerequisites: [HAS_WEAPON, HAS_AMMO, ENEMY_SPOTTED, BACKUP_REQUESTED], effects: [ENEMY_DEFEATED], cost: 0 }, | |
REQUEST_BACKUP => { name: REQUEST_BACKUP, prerequisites: [HAS_WEAPON, HAS_AMMO, ENEMY_SPOTTED], effects: [BACKUP_REQUESTED], cost: 1 }, | |
HUNT => { name: HUNT, prerequisites: [HAS_WEAPON, HAS_AMMO, ENEMY_DETECTED], effects: [ENEMY_SPOTTED], cost: 2 }, | |
PATROL => { name: PATROL, prerequisites: [HAS_WEAPON, HAS_AMMO], effects: [ENEMY_DETECTED], cost: 3 }, | |
GET_AMMO => { name: GET_AMMO, prerequisites: [HAS_WEAPON], effects: [HAS_AMMO], cost: 4 }, | |
GET_WEAPON => { name: GET_WEAPON, prerequisites: [], effects: [HAS_WEAPON], cost: 5 }, | |
] | |
}, | |
SOLDIER => { | |
name: SOLDIER, | |
tasks: [ | |
ATTACK => { name: ATTACK, prerequisites: [HAS_WEAPON, HAS_AMMO, ENEMY_SPOTTED], effects: [ENEMY_DEFEATED], cost: 0 }, | |
HUNT => { name: HUNT, prerequisites: [HAS_WEAPON, HAS_AMMO, ENEMY_DETECTED, BACKUP_REQUESTED], effects: [ENEMY_SPOTTED], cost: 1 }, | |
REQUEST_BACKUP => { name: REQUEST_BACKUP, prerequisites: [HAS_WEAPON, HAS_AMMO, ENEMY_DETECTED], effects: [BACKUP_REQUESTED], cost: 2 }, | |
PATROL => { name: PATROL, prerequisites: [HAS_WEAPON, HAS_AMMO], effects: [ENEMY_DETECTED], cost: 3 }, | |
GET_AMMO => { name: GET_AMMO, prerequisites: [HAS_WEAPON], effects: [HAS_AMMO], cost: 4 }, | |
GET_WEAPON => { name: GET_WEAPON, prerequisites: [], effects: [HAS_WEAPON], cost: 5 }, | |
] | |
}, | |
BACKUP => { | |
name: BACKUP, | |
tasks: [ | |
ATTACK => { name: ATTACK, prerequisites: [HAS_WEAPON, HAS_AMMO, ENEMY_SPOTTED], effects: [ENEMY_DEFEATED], cost: 0 }, | |
FOLLOW => { name: FOLLOW, prerequisites: [HAS_WEAPON, HAS_AMMO], effects: [ENEMY_SPOTTED], cost: 1 }, | |
GET_AMMO => { name: GET_AMMO, prerequisites: [HAS_WEAPON], effects: [HAS_AMMO], cost: 2 }, | |
GET_WEAPON => { name: GET_WEAPON, prerequisites: [], effects: [HAS_WEAPON], cost: 3 }, | |
] | |
}, | |
ALLY => { | |
name: ALLY, | |
tasks: [ | |
ATTACK => { name: ATTACK, prerequisites: [HAS_WEAPON, HAS_AMMO, ENEMY_SPOTTED, WEAPONS_FREE], effects: [ENEMY_DEFEATED], cost: 0 }, | |
REQUEST_ENGAGEMENT => { name: REQUEST_ENGAGEMENT, prerequisites: [HAS_WEAPON, HAS_AMMO, ENEMY_SPOTTED], effects: [WEAPONS_FREE], cost: 1 }, | |
FOLLOW => { name: FOLLOW, prerequisites: [], effects: [ENEMY_SPOTTED], cost: 2 }, | |
HOLD => { name: HOLD, prerequisites: [], effects: [ENEMY_SPOTTED], cost: 3 }, | |
HUNT => { name: HUNT, prerequisites: [HAS_WEAPON, HAS_AMMO], effects: [ENEMY_SPOTTED], cost: 4 }, | |
GET_AMMO => { name: GET_AMMO, prerequisites: [HAS_WEAPON], effects: [HAS_AMMO], cost: 5 }, | |
GET_WEAPON => { name: GET_WEAPON, prerequisites: [], effects: [HAS_WEAPON], cost: 6 }, | |
] | |
}, | |
PLAYER => { | |
name: PLAYER, | |
tasks: [ FREE_PLAY => { name: FREE_PLAY, prerequisites: [], effects: [ENEMY_DEFEATED], cost: 0 } ] | |
} | |
]; | |
} | |
interface IGoapAgent | |
{ | |
public var job:GoapJob; | |
public var state:Map<EGoapState, Bool>; | |
public function set_state(state:EGoapState, bool:Bool):Void; | |
} | |
typedef GoapTask = | |
{ | |
name:EGoapTask, | |
prerequisites:Array<EGoapState>, | |
effects:Array<EGoapState>, | |
cost:Int, | |
} | |
typedef GoapJob = | |
{ | |
name: EGoapJob, | |
tasks: Map<EGoapTask, GoapTask>, | |
} | |
enum EGoapState | |
{ | |
HAS_AMMO; | |
HAS_WEAPON; | |
ENEMY_DETECTED; | |
ENEMY_SPOTTED; | |
ENEMY_DEFEATED; | |
BACKUP_REQUESTED; | |
WEAPONS_FREE; | |
} | |
enum EGoapTask | |
{ | |
PATROL; | |
HUNT; | |
HOLD; | |
FOLLOW; | |
ATTACK; | |
REQUEST_BACKUP; | |
REQUEST_ENGAGEMENT; | |
GET_WEAPON; | |
GET_AMMO; | |
FREE_PLAY; | |
} | |
enum EGoapJob | |
{ | |
COMMS; | |
SOLDIER; | |
BACKUP; | |
ALLY; | |
PLAYER; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment