/* POTM ENTRY : Genetic_grouper */ /* Name : Jaco Cronje */ /* EMail: s9805027@student.up.ac.za */ /* Compile: g++ */ // Wow, my first POTM win !! // I discovered the "genetic_grouper" just 2 weeks // before the deadline, I couldn't believe my eyes // when I saw how well it worked. // If someone out there are going to take part // in the ACM programming contest in March 2000, at // Orlando. (Florida) please let me know. // Or if anyone live near Orlando, it would // be nice to meet you. It will be the first // time for me in USA. Then, when you maybe visit // South-Africa I can show you around and teach you // some afrikaans, and teach what braaivleis and biltong is ! // I'm 20 years old, just finished my 2nd year at the // University of Pretoria doing Computer Science, // and would like to have some contacts overseas. #include #include #include #include #include #include // a Position on the grid typedef struct aBest TBest; struct aBest { char xx,yy; }; // Node of a Tree to store all the words(500-) in. typedef struct aNode TNode; struct aNode { char ch; // 1 Character / Node int left,right; // Binary Tree bool isword; // The Path from the root to this node, is a word }; // Stores a word that was found in the grid typedef struct aRoute TRoute; struct aRoute { TBest pad[81]; int len,group; bool active; }; // Stores a complete solution of words typedef struct aSolution TSolution; struct aSolution { int npad,score; TRoute paaie[2081]; double amount; }; // Amount of gene's in the population // It takes a second or so to combine to gene's, so // I couldn't use a lot of gene's const int MAX_GENE = 8; // Time out const int MAX_TIME = 580; // bestsol = best_solution , asol = a_temporary_solution TSolution bestsol,asol; TSolution* gene[MAX_GENE]; // The gene's // Word paths used to combine to gene's TRoute paaie[5001]; // Binary Tree for quick searching of words in the grid TNode tree[51000]; // Stuff used in the recursive functions to store paths TBest best[81],route[81]; int nx,ny,ntree,bestlen,count,npad,bestcount,ngroup,zigi,total; char grid[81][27]; // Letters in the grid char used[81][27]; // Are the cell used ? char dt[81][27][9]; // Used to find the group's of words int map[81][27]; // Stuff used to find the best solution for a group // of 30 or less words. int grp[2083],deep[50][50],deep2[50][50]; int indx[50],nindex,score,bestscore; char bit1[50],bit2[50],deepbit[50]; // Picking a word that must be picked int tt[81][27][2]; string w; // Timer stuff static time_t Tstart,Tend; void fillup(); void emergancy(); void erec(int x,int y,int len,int pos) { // recursive function to find a random word in the grid if (x<0 || x>=nx || y<0 || y>=ny) return; if (used[x][y]) return; if (score==1) return; // Time out if needed, we could get stuck in here for to long zigi++; if (zigi>=100000) { time(&Tend); if (difftime(Tend,Tstart)>MAX_TIME) emergancy(); zigi = 0; } while (tree[pos].ch!=grid[x][y] && tree[pos].right!=-1) pos = tree[pos].right; if (tree[pos].right==-1 && tree[pos].ch!=grid[x][y]) return; route[len].xx = x; route[len].yy = y; if (tree[pos].isword) { if (score==2 || rand()%10<8) { score = 1; bestlen = len+1; return; } } if (tree[pos].left==-1) return; pos = tree[pos].left; used[x][y] = 1; char order[8]; for (int i=0;i<8;i++) order[i] = i; // Go in random directions if (score!=2) for (int i=0;i<4;i++) { int t1 = rand() % 8; int t2 = rand() % 8; char tmp_ = order[t1]; order[t1] = order[t2]; order[t2] = tmp_; } // Random directions for (int i=0;i<8;i++) switch (order[i]) { case 0 : erec(x+0,y+1,len+1,pos); break; case 1 : erec(x+1,y+1,len+1,pos); break; case 2 : erec(x-1,y+1,len+1,pos); break; case 3 : erec(x+0,y-1,len+1,pos); break; case 4 : erec(x+1,y-1,len+1,pos); break; case 5 : erec(x-1,y-1,len+1,pos); break; case 6 : erec(x+1,y+0,len+1,pos); break; case 7 : erec(x-1,y+0,len+1,pos); break; } used[x][y] = 0; } void asol_to_gene(int num) { // Copy the solution in "asol" to gene number "num" int flagie = 0; if (asol.score>=bestsol.score) { // Check if it is a better solution than the current best flagie = 0; if (asol.score==bestsol.score) { if (asol.npadnpad = asol.npad; gene[num]->score = asol.score; for (int i=0;ipaaie[i].len = asol.paaie[i].len; for (int k=0;kpaaie[i].pad[k].xx = asol.paaie[i].pad[k].xx; gene[num]->paaie[i].pad[k].yy = asol.paaie[i].pad[k].yy; } } } void gene_to_system(int num) { // Copy gene number "num" to the combining_system_memory for (int i=0;inpad;i++) { paaie[npad].len = gene[num]->paaie[i].len; paaie[npad].active = true; for (int k=0;kpaaie[i].len;k++) { paaie[npad].pad[k].xx = gene[num]->paaie[i].pad[k].xx; paaie[npad].pad[k].yy = gene[num]->paaie[i].pad[k].yy; } npad++; } } void asol_to_system() { // Copy asol to the combining_system_memory for (int i=0;i0;i--) { int x = rand() % nx; int y = rand() % ny; score = 0; erec(x,y,0,0); if (score==1) { asol.paaie[asol.npad].len = bestlen; for (int k=0;k bestscore) { memcpy(bit2,bit1,sizeof(bit1)); bestscore = score; } return; } // Time out zigi++; if (zigi>=100000) { time(&Tend); if (difftime(Tend,Tstart)>MAX_TIME) emergancy(); zigi = 0; } // Cool thingy, to remove unwanted recursion total = 0; for (int i=pos;i=nx || yy<0 || yy>=ny) return; if (dt[xx][yy][8]!='*') return; map[xx][yy] = ngroup; dt[xx][yy][8] = 0; if (dt[xx][yy][0]) fill(xx,yy-1); if (dt[xx][yy][1]) fill(xx+1,yy-1); if (dt[xx][yy][2]) fill(xx+1,yy); if (dt[xx][yy][3]) fill(xx+1,yy+1); if (dt[xx][yy][4]) fill(xx,yy+1); if (dt[xx][yy][5]) fill(xx-1,yy+1); if (dt[xx][yy][6]) fill(xx-1,yy); if (dt[xx][yy][7]) fill(xx-1,yy-1); } void removeMax(int gg) { // The group "gg" have to many words, so pick a random word // from the group int nmax,ntbl; int tbl[5000]; ntbl = 0; for (int i=0;ipaaie[i].len) break; } if (sum<=paaie[i].len) { paaie[i].active = false; for (int k=0;kx1) { dt[x1][y1][2] = '1'; dt[x2][y2][6] = '1'; } else { dt[x1][y1][6] = '1'; dt[x2][y2][2] = '1'; } } else if (y10); makeGroup(); if (ngroup==0) { fillup(); return; } for (int i=1;i<=ngroup;i++) { if (grp[i]>30) removeMax(i); else searchGRP(i); } time(&Tend); if (difftime(Tend,Tstart)>MAX_TIME) emergancy(); } while (true); } void solve() { int life = 0; int order[MAX_GENE]; int newpop[MAX_GENE]; TSolution* oldpop[MAX_GENE]; // Get random gene's to start with getsomething(); char mate[MAX_GENE]; int totalscore,lowscore; do { totalscore = 0; // get totalscore lowscore = 3000; for (int i=0;iscorescore; lowscore /= 2; for (int i=0;iscore-lowscore); // calculate amount. Pie slices gene[0]->amount = ( (gene[0]->score-lowscore)*1000/totalscore); for (int i=1;iamount = ( (gene[i]->score-lowscore)* 1000/totalscore) + gene[i-1]->amount; gene[MAX_GENE-1]->amount = 1000; // store old-generation pointers for (int i=0;iamount) { k=0; } else { for (k=1;k=gene[k-1]->amount && j<=gene[k]->amount) break; } order[k]++; newpop[i] = k; } // Deep copy's for (int i=0;iscore = oldpop[z]->score; gene[i]->npad = oldpop[z]->npad; for (int j=0;jnpad;j++) { gene[i]->paaie[j].len = oldpop[z]->paaie[j].len; for (int k=0;kpaaie[j].len;k++) { gene[i]->paaie[j].pad[k].xx = oldpop[z]->paaie[j].pad[k].xx; gene[i]->paaie[j].pad[k].yy = oldpop[z]->paaie[j].pad[k].yy; } } } // Delete old generation for (int i=0;iscore > gene[g1]->score) { g1 = i*2+1; g2 = i*2; } npad = 0; gene_to_system(g1); gene_to_system(g2); combine_them(); asol_to_gene(g2); npad = 0; gene_to_system(g1); random_to_asol(); asol_to_system(); combine_them(); asol_to_gene(g1); } // Remove the comments to see how the program are doing // for (int i=0;iscore; // cout << " : " << bestsol.score << endl; life++; if (life%3==0) { // Make sure that the best solution stays in the population npad = 0; best_to_system(); combine_them(); asol_to_gene(rand() % MAX_GENE); } } while (true); } void main(int argc,char* argv[]) { srand(time(NULL)); time(&Tstart); for (int i=0;i> ny >> nx; for (int y=0;y> grid[x][y]; while (!f.eof()) { f >> w; addWord(); } f.close(); bestsol.score = 0; bestsol.npad = 0; solve(); }