270 lines · 4.9 KB · C
RawDownload
#include <u.h>#include <libc.h> #include "bt.h"#include "impl.h" static int btnodetick(BehaviorNode*, BehaviorState*, void*); void*btstatefor(BehaviorNode *node, BehaviorState *bs){	return &bs->states[node->id];} /* -1 on failure, >= 0 on success */static intbtcheckguard(BehaviorNode *node, BehaviorState *bs, void *agent){	int status; 	assert(node != nil);	assert(bs != nil); 	if(node->guard == nil)		return 0; 	/* check the guard of the guard */	if(btcheckguard(node->guard, bs, agent) < 0)		return -1; 	status = btnodetick(node->guard, bs, agent);	switch(status){	case TASKSUCCESS:		return 0;	case TASKFAIL:		return -1;	} 	abort();	return 0;} static inttickleaf(BehaviorNode *node, BehaviorState *bs, void *agent){	BehaviorLeaf *leaf; 	leaf = (BehaviorLeaf*)node; 	return leaf->action(leaf->ctx, agent);} static intticksequence(BehaviorNode *node, BehaviorState *bs, void *agent){	int status;	BehaviorBranch *branch;	BehaviorBranchState *state;	BehaviorNode *child; 	branch = (BehaviorBranch*)node;	state = btstatefor(node, bs); 	child = branch->children[state->childcurrent];	status = btnodetick(child, bs, agent); 	switch(status){	case TASKRUNNING:		return TASKRUNNING;	case TASKFAIL:		state->childcurrent = 0;		return TASKFAIL;	case TASKSUCCESS:		if(state->childcurrent == (branch->childcount - 1)){			state->childcurrent = 0;			return TASKSUCCESS;		} 		state->childcurrent++;		return TASKRUNNING;	} 	abort();	return 0;} static inttickpriority(BehaviorNode *node, BehaviorState *bs, void *agent){	int status;	BehaviorBranch *branch;	BehaviorBranchState *state;	BehaviorNode *child; 	branch = (BehaviorBranch*)node;	state = btstatefor(node, bs); 	child = branch->children[state->childcurrent];	status = btnodetick(child, bs, agent); 	switch(status){	case TASKSUCCESS:		state->childcurrent = 0;		return TASKSUCCESS;	case TASKRUNNING:		return TASKRUNNING;	case TASKFAIL:		if(state->childcurrent == (branch->childcount - 1)){			state->childcurrent = 0;			return TASKFAIL;		} 		state->childcurrent++;		return TASKRUNNING;	} 	abort();	return 0;} static inttickparallel(BehaviorNode *node, BehaviorState *bs, void *agent){	int i, state, success, failure;	BehaviorParallel *parallel;	BehaviorNode *child; 	success = failure = 0; 	parallel = (BehaviorParallel*)node; 	for(i = 0; i < parallel->branch.childcount; i++){		child = parallel->branch.children[i]; 		state = TASKFAIL;		if(btcheckguard(child, bs, agent) >= 0)			state = btnodetick(child, bs, agent); 		switch(state){		case TASKSUCCESS:			success++;			break;		case TASKFAIL:			failure++;			break;		case TASKRUNNING:			break;		default:			abort();		} 		if(success >= parallel->S){			btcancel((BehaviorNode*)parallel, bs, agent);			return TASKSUCCESS;		} 		if(failure >= parallel->F){			btcancel((BehaviorNode*)parallel, bs, agent);			return TASKFAIL;		}	} 	return TASKRUNNING;} static inttickdynguard(BehaviorNode *node, BehaviorState *bs, void *agent){	int i;	BehaviorBranch *branch;	BehaviorBranchState *state;	BehaviorNode *child, *torun; 	branch = (BehaviorBranch*)node;	state = btstatefor(node, bs);	torun = nil; 	for(i = 0; i < branch->childcount; i++){		child = branch->children[i];		if(btcheckguard(child, bs, agent) == 0){			torun = child;			break;		}	} 	if(state->childcurrent != -1 && torun != branch->children[state->childcurrent]){		btcancel(branch->children[state->childcurrent], bs, agent);		state->childcurrent = -1;	} 	if(torun == nil){		btcancel((BehaviorNode*)branch, bs, agent);		return TASKFAIL;	} 	if(state->childcurrent == -1){		state->childcurrent = i;	} 	i = btnodetick(torun, bs, agent);	switch(i){	case TASKSUCCESS:	case TASKFAIL:		state->childcurrent = -1;		btcancel((BehaviorNode*)branch, bs, agent);	} 	return i;} static inttickinvert(BehaviorNode *node, BehaviorState *bs, void *agent){	int state;	BehaviorBranch *branch;	BehaviorNode *child; 	branch = (BehaviorBranch*)node;	child = branch->children[0]; 	state = btnodetick(child, bs, agent); 	switch(state){	case TASKSUCCESS:		return TASKFAIL;	case TASKFAIL:		return TASKSUCCESS;	case TASKRUNNING:		return TASKRUNNING;	} 	abort();	return 0;} static int (*tickfns[])(BehaviorNode*, BehaviorState*, void*) = {[BT_LEAF]		tickleaf,[BT_SEQUENCE]	ticksequence,[BT_PRIORITY]	tickpriority,[BT_PARALLEL]	tickparallel,[BT_DYNGUARD]	tickdynguard,[BT_INVERT]		tickinvert,}; static intbtnodetick(BehaviorNode *node, BehaviorState *bs, void *agent){	BehaviorNodeState *state; 	assert(node != nil);	assert(node->type >= 0 && node->type < BT_MAXTYPE);	assert(node->type < nelem(tickfns));	assert(bs != nil); 	state = btstatefor(node, bs); 	state->status = tickfns[node->type](node, bs, agent); 	if(node->end != nil && (state->status == TASKFAIL || state->status == TASKSUCCESS))		node->end(agent); 	return state->status;} intbttick(Behavior *b, BehaviorState *bs, void *agent){	return btnodetick(b->root, bs, agent);}