#include "avoidance.h" void avoidance::decide(int *dx, int *dy) const { struct gridMoves { int dx; //horizontal difference int dy; //vertical difference }; static const gridMoves m[] = { //clockwise from UL {-1, -1}, //up-left { 0, -1}, //up { 1, -1}, //up-right { 1, 0}, //right { 1, 1}, //right-down { 0, 1}, //down {-1, 1}, //down-left {-1, 0} //left }; size_t numMoves = sizeof(m)/sizeof(m[0]); getInitialDirection(dx, dy); //try initial move first, if that works, no need for other tests: if ((*dx == 0 && *dy == 0) || get(*dx, *dy) != avoidChar) { return; } size_t index = 0; //find where in the move list we are for(const gridMoves *p = m; p < m + numMoves; ++p, ++index) { if(p->dx == *dx && p->dy == *dy) { break; } } //test each grid move (ranked in order of similarity) to find //highest preference that is unobstructed by avoidChar /* visualize a grid of possible moves, if highest preference is up-left (0), rank of other possible moves is: 0 1 3 2 X 5 4 6 7 (choosing 1 vs 2, 3 vs 4, etc is arbitrary): m's index layout is 0 1 2 7 X 3 6 5 4 so for any arbitary start index, the next index to try is given by (index +or- tries + 8) % 8 to keep it in bounds */ for (size_t tries = 1; tries <= numMoves/2; ++tries) { size_t thisIndex = (index + tries + numMoves) % numMoves; *dx = m[thisIndex].dx; *dy = m[thisIndex].dy; if (get(*dx, *dy) != avoidChar) { return; } if (tries == numMoves/2) { //we've tested all possible moves by now //this guy is stuck, leave him there *dx = *dy = 0; return; } thisIndex = (index - tries + numMoves) % numMoves; *dx = m[thisIndex].dx; *dy = m[thisIndex].dy; if (get(*dx, *dy) != avoidChar) { return; } } }