Chris Rossi'S AI Project
SIGMA

Contents
Domain
Illustration
Methods
Conclusions

Domain

SIGMA, Simple but Intelligent Gaming Movement Agent, was initially designed to make decisions for most games played in the first person, like Quake, Doom, etc. SIGMA was supposed to, on a VERY high level, get all items in a room, avoid and/or kill all enemies, pick the correct weapons to destroy each enemy, and get the agent to the room's exit. In actuality, this was a very high goal to reach, which is why the specifications for what SIGMA could do dwindled as the semester went on. In its final stages, SIGMA basically finds the best path to pick up all items in a room and get to the exit, while ignoring any other elements of the room.


Illustration

Since I do not have a graphics program to make a nifty little JPEG image, I will have to try my hand at ASCII graphics. SIGMA starts at the S node, and then it picks the nearest item and goes to that, then the next closest, and so on, till it gets all of the items, and then it heads for the exit node E, like so:

---------------------
|   |   |   |   | E |
---------------------
|I1 |   |   |   |   |
---------------------
|   |   |I2 |   |   |
---------------------
|   |   |   |   |I3 |
---------------------
|   |   |   | S |   |
---------------------

Methods

:- op(400,yfx,'#'). This line of code is used in the nodes to retain the heuristic value that is calculated for each of the items. There are mainly two blocks of code that actually run SIGMA.

getBest(Start#_,R,NewList,S) :-
		position(Start,A,B),
		getHead(R,H#F),
		getTail(R,T),
		position(H,C,D),
		F1 is (abs(C-A)+abs(D-B)),
	        makeList(H#F1,NewList,NewList1),
		getBest(Start#0,T,NewList1,S).
getBest(_#_,[],NewList,S) :-
	insertSort(NewList,NewList1),
	getHead(NewList1,H#F),
	getTail(NewList1,T),
	F1 is 0,
	search([H#F1|T],S).
The getBest method calculates the heuristic function by computing the distance between the current state and the next possible states and stores the possible states in a list. Then this list is sorted using a simple sorting algorithm, insert sort, as depicted here.
insertSort([],[]).
insertSort([X#F|Xs],XinYs) :-
	 insertSort(Xs,Ys),
	 insert(X#F,Ys,XinYs).

insert(X#F,[],[X#F]).
insert(X#F,[Y#F1|Ys],[X#F,Y#F1|Ys]) :- F =< F1.
insert(X#F,[Y#F1|Ys],[Y#F1|XinYs]) :- F > F1,
	 insert(X#F,Ys,XinYs).
After the list is sorted, getBest is run again on the first node in the list, which would be the best choice from the current state.

Conclusions

SIGMA presented a challenge that was kind of overwhelming for me to try to face. I had difficulty with the design of the states to include all of the different things I was planning on having SIGMA interpret, like inventory, traps, lighting, enemies, and the like. I am pleased that SIGMA works for the most part in finding paths from the start node to the end node. There are still some problems that need to be worked out. For instance, if the start is closer to the end than it is to the items, it will just go to the end instead of picking up all of the items first. There are also some gliches in the programming where the answer comes out with extra unanswered variables in the list, and end is not included in the list either. If anyone has any comments or would like the code to check out, maybe even just for fun, contact me at spicoli@trinityproductions.com.