Quote: Original post by frogtag
I've done some preliminary research into AI, specifically ANNs. But I don't really understand the practical uses of ANNs in game programming, in regards to its ability to potentially mimic human thinking. Okay, I get the concept that you can use it in character recognition, but that has utility potential, not say for instance how a NPC will react to a situation.
Can anyone give me some more practical usages in terms of NPC AI and/or direct me to some tutorials?
At the moment I don't see the point in an ANN unless your interest is purely ANN research!
In regards to its ability to mimic human thinking the most distinctive attribute of ANNs is their learning capacity. Where, how and why this can be useful is another story, but even though NN is somewhat of an 'alien-technology' to us it's not so terribly complicated.
--- "Hello World" ---
Tic-Tac-Toe, recursive algorithm
(plays almost perfect game, can not be beaten)
//-------------------------------------------------------------------#include <stdio.h>#include <stdlib.h>#define st(q) a&(1<<q)?'x':b&(1<<q)?'o':'.'#define win(q) !(q&7&&q&56&&q&448&&q&73&&q&146&&q&292&&q&273&&q&84)#define prt printf("\n %c %c %c\n %c %c %c\n %c %c %c Move[1-9]: ",st(0),st(1),st(2),st(3),st(4),st(5),st(6),st(7),st(8),t)static int i,j,m,a,b,t;int RecMove(int a, int b, int *m){ int i=0,e,k,n,c=5; if(win(~a)) c=4; else{ for(;i<9;i++) if(!(a&(k=1<<i)||b&k) && c>(e=5-RecMove(b|k,a,&n))) c=e, *m=i; if(c>4) c=3, c-=(c>1); } return c;} void main(){ BEGIN: m=a=b=t=0; printf("\n\n\n\n TIC TAC TOE --- New Game ---\n"); prt; do{ scanf("%2c",&m); a|= 1<<(m-'1'); if(win(~a)) prt, printf("You win!"), t=9; else RecMove(a,b, &m), b|= 1<<m, prt; if(win(~b)) printf("I win!"), t=9; }while(++t<5); goto BEGIN;} //Algorithm taken from: http://www.iwriteiam.nl/SigProgC.html//-------------------------------------------------------------------
Tic-Tac-Toe, ANN 9 outputs, 9x9 weights.
(can be beaten, can be tricked, can see only opponent)
//-------------------------------------------------------------------#include <stdio.h>#include <stdlib.h>#define st(q) a&(1<<q)?'x':b&(1<<q)?'o':'.'#define win(q) !(q&7&&q&56&&q&448&&q&73&&q&146&&q&292&&q&273&&q&84)#define prt printf("\n %c %c %c\n %c %c %c\n %c %c %c Move[1-9]: ",st(0),st(1),st(2),st(3),st(4),st(5),st(6),st(7),st(8),t)static int i,j,m,a,b,t,NodeOut[9], Wgt[9][9]={0,43,19,43,44,1,19,1,42,29,0,29,4,1,4,5,37,5,19,43,0,1,44,43,42,1,19,29,4,5,0,1,37,29,4,5,3,1,3,1,0,1,3,1,3,5,4,29,37,1,0,5,4,29,19,1,42,43,44,1,0,43,19,5,37,5,4,1,4,29,0,29,42,1,19,1,44,43,19,43,0};void NetMove(int *m){ for(i=0;i<9;i++) for(j=0;j<9;j++) if(a&(1<<i)) NodeOut[j]+= Wgt[j]; for(i=0,j=-9;i<9;i++){ if(j < NodeOut && !(a&(1<<i) || b&(1<<i))) j= NodeOut, *m=i; NodeOut= 0; }}void main(){ BEGIN: m=a=b=t=0; printf("\n\n\n\n TIC TAC TOE --- New Game ---\n"); prt; do{ scanf("%2c",&m); a|= 1<<(m-'1'); if(win(~a)) prt, printf("You win!"), t=9; else NetMove(&m), b|= 1<<m, prt; if(win(~b)) printf("I win!"), t=9; }while(++t<5); goto BEGIN;} //-------------------------------------------------------------------
It's not that bad, eh?
ANN looks like this, it can see only X's.
INPUT_X OUTPUT_O 1 2 3 -> 1 2 3 4 5 6 -> 4 5 6 7 8 9 -> 7 8 9Single layer perceptron, 9 nodes9 "wires" from input 1 to output 1,2,3...99 "wires" from input 2 to output 1,2,3...99 "wires" from input 3 to output 1,2,3...9. 9 "wires" from input 9 to output 1,2,3...9
There are many ways to train ANN and that's all well documented, all 2% that we know about it, so I'll try to talk about something a little bit different, something more direct and hopefully more insightful.
Quick example A,
to "teach" NN to play square '5' when opponent in on square '1' we modify "thickness" or weights of these nine connections coming from square '1', like this:
//in1 -> out1,out2,out3...Weights_1[9]={ 0,1,1, // X 2 3 x| | 1,9,1, // 4 5 6 -> |o| 1,1,1 // 7 8 9 | |}
Quick example B, to "teach" NN to watch for 3in-row when opponent plays square '3' we modify nine connections coming from square '3', something like this:
//in3 -> out1,out2,out3...Weights_3[9]={ 5,7,0, // 1 2 X | |x 1,9,7, // 4 5 6 -> |o| 8,1,5 // 7 8 9 | |}
Basically it means: "if opponent is on '3', the best move is square '5' then '7', good moves are '2' and '6', while not so good are squares '1' and '9'." Connections '4', '8' and '3', having a small value of 0-1, can be removed since they do not impact the computation, and that's how we optimize. This kind of network can even learn some chess based on these same principles, where you can program/teach ANN by directly setting its weights, pulling those neurons like some Despereaux. With some additional inputs it could learn specific chess moves for each figure, what to go for, what to run from, and who knows what else. You can use this in action games as well, say to make soldiers take cover at appropriate corner depending on where enemy is, and such.
Ok, I'll have to continue some other time, maybe I'll even manage to teach this X/O-ANN some new tricks, but considering its shallow brain and half-blindness this "creature" performs rather well, I think.
[EDIT]Quick example C,
"teach" NN to play couple of openings, this is how it all comes together:
Weights_1[9]={ 0,7,5, // X 2 3 x| | 7,9,1, // 4 5 6 -> |o| 5,1,8 // 7 8 9 | |}Weights_3[9]={ 5,7,0, // 1 2 X | |x 1,9,7, // 4 5 6 -> |o| 8,1,5 // 7 8 9 | |}(W1 + W3)00 14 00 [1 2 3] x| | x| |x x|o|x08 18 08 [4 5 6] |o| -> |o| -> |o|13 02 13 [7 8 9] | | | | | |
Tournament: 5,000 games - performance...
ANN vs RND REC vs RND ANN vs REC---------- ---------- ----------Won: 2800 Won: 4400 Won: 0Lost: 700 Lost: 0 Lost: 540Draw: 1500 Draw: 600 Draw: 4460time= 29s time= 44s time= 45sRND=random algorithm, REC=recursive algorithm
[Edited by - Victor-Victor on September 27, 2009 6:44:53 AM]