Advertisement
Guest User

Untitled

a guest
Feb 8th, 2016
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.45 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <time.h>
  5. #include <unistd.h>
  6. #include <sys/select.h>
  7. #include <termios.h>
  8. #include <ctype.h>
  9.  
  10. // adjustable parameters
  11. #define POPULATION_SIZE 200 // total population size
  12. #define NUM_SURVIVORS 4 // number of survivors per generation (must be less than POPULATION_SIZE)
  13. #define GENOME_LEN 28 // number of loci in each genome (each locus is one character)
  14. #define MUTATION_RATE 0.01 // probability that a locus is mutated per generation
  15. #define FITNESS_THRESHOLD 28 // program stops when this fitness threshold is met or exceeded
  16. #define DISPLAY_INTERVAL 1 // display results every n generations, where n == DISPLAY_INTERVAL
  17. #define PAUSE_TIME 50000 // pause time in microseconds
  18. #define GENOMES_TO_DISPLAY 1 // in STEP_MODE, number of (the fittest) genomes to display at each step
  19. #define STEP_MODE 1 // if set, program will pause every n generations and display the genomes
  20. #define ENABLE_LATCHING 0 // if set, enable latching
  21. #define ENABLE_SELECTION 1 // if set, enable selection; otherwise, select survivors randomly
  22.  
  23. #define CHARSET_SIZE 27 // 26 uppercase letters plus the space character
  24. #define NUM_LINES 300 // number of lines in the program's display "window"
  25. #define CHARS_PER_LINE 120 // for each line in the "window"
  26.  
  27. // A genome consists of an array of loci plus the associated fitness value for each locus
  28. typedef struct {
  29. char locus[GENOME_LEN];
  30. int fitness;
  31. } genome_t;
  32.  
  33. genome_t target; // target phrase
  34. genome_t genome_array[POPULATION_SIZE]; // genomes of all members of the population
  35.  
  36. char weasel_to_ascii(char c) {
  37. switch(c) {
  38. case 0: return ' ';
  39. case 1: return 'A';
  40. case 2: return 'B';
  41. case 3: return 'C';
  42. case 4: return 'D';
  43. case 5: return 'E';
  44. case 6: return 'F';
  45. case 7: return 'G';
  46. case 8: return 'H';
  47. case 9: return 'I';
  48. case 10: return 'J';
  49. case 11: return 'K';
  50. case 12: return 'L';
  51. case 13: return 'M';
  52. case 14: return 'N';
  53. case 15: return 'O';
  54. case 16: return 'P';
  55. case 17: return 'Q';
  56. case 18: return 'R';
  57. case 19: return 'S';
  58. case 20: return 'T';
  59. case 21: return 'U';
  60. case 22: return 'V';
  61. case 23: return 'W';
  62. case 24: return 'X';
  63. case 25: return 'Y';
  64. case 26: return 'Z';
  65. }
  66. }
  67.  
  68. char ascii_to_weasel(char c) {
  69. switch(c) {
  70. case ' ': return 0;
  71. case 'A': return 1;
  72. case 'B': return 2;
  73. case 'C': return 3;
  74. case 'D': return 4;
  75. case 'E': return 5;
  76. case 'F': return 6;
  77. case 'G': return 7;
  78. case 'H': return 8;
  79. case 'I': return 9;
  80. case 'J': return 10;
  81. case 'K': return 11;
  82. case 'L': return 12;
  83. case 'M': return 13;
  84. case 'N': return 14;
  85. case 'O': return 15;
  86. case 'P': return 16;
  87. case 'Q': return 17;
  88. case 'R': return 18;
  89. case 'S': return 19;
  90. case 'T': return 20;
  91. case 'U': return 21;
  92. case 'V': return 22;
  93. case 'W': return 23;
  94. case 'X': return 24;
  95. case 'Y': return 25;
  96. case 'Z': return 26;
  97. }
  98. }
  99.  
  100. // Swap two genomes given their indices.
  101. void swap_genomes(int g1, int g2) {
  102. genome_t temp_genome;
  103. if (g1 == g2) {
  104. return;
  105. } else {
  106. temp_genome = genome_array[g1];
  107. genome_array[g1] = genome_array[g2];
  108. genome_array[g2] = temp_genome;
  109. }
  110. }
  111.  
  112. // Thoroughly and randomly scramble the population within the genome array.
  113. void scramble_genomes() {
  114. for (int i=0; i < 4*POPULATION_SIZE; i++) {
  115. swap_genomes(rand()%POPULATION_SIZE, rand()%POPULATION_SIZE);
  116. }
  117. }
  118.  
  119. // Calculate a genome's fitness by determining the number of loci at which
  120. // it matches the target.
  121. int fitness(genome_t *genome) {
  122. int matches = 0;
  123.  
  124. // scan the entire genome, counting the number of loci that match the target
  125. for (int i=0; i < GENOME_LEN; i++) {
  126. if (genome->locus[i] == target.locus[i]) ++matches;
  127. }
  128.  
  129. return matches;
  130. }
  131.  
  132. // Display a genome as a character string.
  133. void display_genome(genome_t *genome) {
  134. for (int i=0; i < GENOME_LEN; i++) {
  135. putchar(weasel_to_ascii(genome->locus[i]));
  136. }
  137. }
  138.  
  139. // Convert an ascii string to a Weasel genome
  140. void weaselize (char *ascii_str, genome_t *genome) {
  141. for (int i=0; i<GENOME_LEN; i++) {
  142. genome->locus[i] = ascii_to_weasel(ascii_str[i]);
  143. }
  144. }
  145.  
  146. // move cursor to the home position
  147. void cursor_home() {
  148. printf("\x1b[H");
  149. }
  150.  
  151. // overwrite everything on the screen with spaces
  152. void clear_screen() {
  153. cursor_home();
  154. for (int i=0; i < NUM_LINES; i++) {
  155. for (int j=0; j < CHARS_PER_LINE; j++) {
  156. putchar(' ');
  157. }
  158. printf("\n\r");
  159. }
  160. }
  161.  
  162. // Mutate 'old' genome, placing results in 'new'
  163. void mutate(genome_t *old, genome_t *new) {
  164. for (int i=0; i < GENOME_LEN; i++) {
  165. if ((double)rand()/(double)RAND_MAX < MUTATION_RATE && (!ENABLE_LATCHING || old->locus[i] != target.locus[i])) {
  166. new->locus[i] = (char)(rand()%CHARSET_SIZE); // mutate this locus
  167. } else {
  168. new->locus[i] = old->locus[i]; // don't mutate
  169. }
  170. }
  171. new->fitness = fitness(new);
  172. }
  173.  
  174. // Initialize a genome with a random string
  175. void init_genome_rand(genome_t *genome) {
  176. for (int i=0; i < GENOME_LEN; i++) {
  177. genome->locus[i] = (char)(rand()%CHARSET_SIZE);
  178. }
  179. genome->fitness = fitness(genome);
  180. }
  181.  
  182. // Comparison function for use by qsort() library routine
  183. int compare_fitness (const void * elem1, const void * elem2) {
  184. if (((genome_t *)elem2)->fitness > ((genome_t *)elem1)->fitness) return 1;
  185. if (((genome_t *)elem2)->fitness == ((genome_t *)elem1)->fitness) return 0;
  186. return -1;
  187. }
  188.  
  189. //
  190. // From http://stackoverflow.com/questions/448944/c-non-blocking-keyboard-input
  191. //
  192.  
  193. struct termios orig_termios;
  194.  
  195. void reset_terminal_mode()
  196. {
  197. tcsetattr(0, TCSANOW, &orig_termios);
  198. }
  199.  
  200. void set_conio_terminal_mode()
  201. {
  202. struct termios new_termios;
  203.  
  204. /* take two copies - one for now, one for later */
  205. tcgetattr(0, &orig_termios);
  206. memcpy(&new_termios, &orig_termios, sizeof(new_termios));
  207.  
  208. /* register cleanup handler, and set the new terminal mode */
  209. atexit(reset_terminal_mode);
  210. cfmakeraw(&new_termios);
  211. tcsetattr(0, TCSANOW, &new_termios);
  212. }
  213.  
  214. int kbhit()
  215. {
  216. struct timeval tv = { 0L, 0L };
  217. fd_set fds;
  218. FD_ZERO(&fds);
  219. FD_SET(0, &fds);
  220. return select(1, &fds, NULL, NULL, &tv);
  221. }
  222.  
  223. int getch()
  224. {
  225. int r;
  226. unsigned char c;
  227. if ((r = read(0, &c, sizeof(c))) < 0) {
  228. return r;
  229. } else {
  230. return c;
  231. }
  232. }
  233.  
  234. int main() {
  235.  
  236. long long generation = 0; // generation count
  237. int i;
  238. int selection_enabled = ENABLE_SELECTION;
  239. char ascii_target[GENOME_LEN+1];
  240. char c;
  241.  
  242. set_conio_terminal_mode();
  243.  
  244. printf("\n\n\n\n\r");
  245.  
  246. // set cursor to home position, clear screen, and rehome
  247. clear_screen();
  248. cursor_home();
  249.  
  250. // seed the random number generator with the current time
  251. srand(time(NULL));
  252.  
  253. // set up ascii version of initial fitness target
  254. ascii_target[0] = 'M';
  255. ascii_target[1] = 'E';
  256. ascii_target[2] = 'T';
  257. ascii_target[3] = 'H';
  258. ascii_target[4] = 'I';
  259. ascii_target[5] = 'N';
  260. ascii_target[6] = 'K';
  261. ascii_target[7] = 'S';
  262. ascii_target[8] = ' ';
  263. ascii_target[9] = 'I';
  264. ascii_target[10] = 'T';
  265. ascii_target[11] = ' ';
  266. ascii_target[12] = 'I';
  267. ascii_target[13] = 'S';
  268. ascii_target[14] = ' ';
  269. ascii_target[15] = 'L';
  270. ascii_target[16] = 'I';
  271. ascii_target[17] = 'K';
  272. ascii_target[18] = 'E';
  273. ascii_target[19] = ' ';
  274. ascii_target[20] = 'A';
  275. ascii_target[21] = ' ';
  276. ascii_target[22] = 'W';
  277. ascii_target[23] = 'E';
  278. ascii_target[24] = 'A';
  279. ascii_target[25] = 'S';
  280. ascii_target[26] = 'E';
  281. ascii_target[27] = 'L';
  282.  
  283. // set up weasel version of the fitness target
  284. weaselize(ascii_target, &target);
  285.  
  286. // randomly initialize the genomes of the entire population
  287. for (i=0; i < POPULATION_SIZE; i++) {
  288. init_genome_rand(&genome_array[i]);
  289. }
  290. printf("\n\n\rInitial Organism 0 Genome:\n\n\r");
  291. display_genome(&genome_array[0]);
  292. printf("\n\n\n\r");
  293.  
  294. while (genome_array[0].fitness < FITNESS_THRESHOLD) {
  295.  
  296. // preserve the survivors, but convert the rest into mutated copies of the survivors
  297. for (i=0; i < POPULATION_SIZE - NUM_SURVIVORS; i++) {
  298. mutate(&genome_array[i%NUM_SURVIVORS], &genome_array[i+NUM_SURVIVORS]);
  299. }
  300.  
  301. // now mutate the survivors themselves
  302. for (i=0; i<NUM_SURVIVORS; i++) {
  303. mutate(&genome_array[i], &genome_array[i]);
  304. }
  305.  
  306. if (selection_enabled) {
  307. // sort the genomes into descending order by fitness
  308. qsort(genome_array, POPULATION_SIZE, sizeof(genome_t), compare_fitness);
  309. } else {
  310. // randomly scramble the genome array
  311. scramble_genomes();
  312. }
  313.  
  314. ++generation;
  315.  
  316. // in step mode, pause and display all genomes periodically
  317. if (STEP_MODE && generation % DISPLAY_INTERVAL == 0) {
  318. clear_screen();
  319. cursor_home();
  320. printf("\n\rTarget Phrase: ");
  321. printf("%s", ascii_target);
  322. printf("\n\n\rGeneration: %lld\n\r", generation);
  323. printf("\n\rSelection: %s\n\n\r", selection_enabled ? "ON" : "OFF");
  324. for (i = 0; i < GENOMES_TO_DISPLAY; i++) {
  325. printf("Organism %d Fitness %d\n\n\r", i, genome_array[i].fitness);
  326. display_genome(&genome_array[i]);
  327. printf("\r\n\n\n");
  328. }
  329. usleep(PAUSE_TIME); // pause briefly before continuing
  330. }
  331.  
  332. if (!STEP_MODE && generation % DISPLAY_INTERVAL == 0) {
  333. printf("generation = %lld fitness = %d \n\r", generation, genome_array[0].fitness);
  334. }
  335.  
  336. if (kbhit()) { // keystroke detected
  337. switch(getch()) {
  338. case 'q': // quit the program
  339. exit(0);
  340.  
  341. case 'p': // pause until next keystroke
  342. printf("Paused: Hit any key to continue\r\n");
  343. while(!kbhit()){
  344. ;
  345. }
  346. (void)getch(); // consume character
  347. break;
  348.  
  349. case 's': // toggle selection on and off
  350. selection_enabled = !selection_enabled;
  351. break;
  352.  
  353. case 't': // set new target phrase
  354. printf("Enter new target phrase (spaces and letters only): ");
  355. fflush(stdout);
  356. i = 0;
  357. do {
  358. while (!kbhit()) { // wait for keystroke
  359. ;
  360. }
  361. c = toupper(getch());
  362. if (c == '\r') break;
  363. if (isalpha(c) || c == ' ') {
  364. putchar(c);
  365. fflush(stdout);
  366. ascii_target[i++] = c; // add character to target phrase
  367. }
  368. } while (ascii_target[i-1] != '\r' && i-1 < GENOME_LEN);
  369. for(; i<GENOME_LEN; i++) {
  370. ascii_target[i] = ' '; // pad remainder of target with spaces
  371. }
  372. weaselize(ascii_target, &target);
  373. // need to recompute fitness values because the target has changed
  374. for (i=0; i<POPULATION_SIZE; i++) {
  375. genome_array[i].fitness = fitness(&genome_array[i]);
  376. }
  377. break;
  378. }
  379. }
  380. }
  381.  
  382. printf("\n\n\rWinning generation = %lld fitness = %d \n\r", generation, genome_array[0].fitness);
  383. printf("\n\rWinning genome:\n\n\r");
  384. display_genome(&genome_array[0]);
  385. printf("\n\n\r");
  386. tcsetattr(0, TCSANOW, &orig_termios);
  387. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement