Advertisement
Guest User

Untitled

a guest
Jan 10th, 2016
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.16 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 10 // total population size
  12. #define NUM_SURVIVORS 4 // number of survivors per generation (must be less than POP_SIZE)
  13. #define GENOME_LEN 13 // number of loci in each genome (each locus is one character)
  14. #define MUTATION_RATE 0.5 // probability that a genome is mutated per generation
  15. #define FITNESS_THRESHOLD 843503 // 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_SELECTION 1 // if set, enable selection; otherwise, select survivors randomly
  21.  
  22. #define NUM_LINES 300 // number of lines in the program's display "window"
  23. #define CHARS_PER_LINE 120 // for each line in the "window"
  24.  
  25. // A genome consists of a character string plus the associated fitness value
  26. typedef struct {
  27. char string[GENOME_LEN];
  28. int fitness;
  29. } genome_t;
  30.  
  31. genome_t genome_array[POPULATION_SIZE]; // genomes of all members of the population
  32.  
  33. // Swap two genomes given their indices.
  34. void swap_genomes(int g1, int g2) {
  35. genome_t temp_genome;
  36. if (g1 == g2) {
  37. return;
  38. } else {
  39. temp_genome = genome_array[g1];
  40. genome_array[g1] = genome_array[g2];
  41. genome_array[g2] = temp_genome;
  42. }
  43. }
  44.  
  45. // Thoroughly and randomly scramble the population within the genome array.
  46. void scramble_genomes() {
  47. for (int i=0; i < 4*POPULATION_SIZE; i++) {
  48. swap_genomes(rand()%POPULATION_SIZE, rand()%POPULATION_SIZE);
  49. }
  50. }
  51.  
  52. // Determine whether a character represents one of the four legal operators.
  53. int is_op(char c) {
  54. if (c=='+'||c=='-'||c=='*'||c=='/') {
  55. return 1;
  56. } else {
  57. return 0;
  58. }
  59. }
  60.  
  61. // Determine whether a genome contains a legal string.
  62. int is_legal(genome_t *genome) {
  63. if (is_op(genome->string[0])) {
  64. return 0;
  65. } else if (is_op(genome->string[GENOME_LEN-1])) {
  66. return 0;
  67. }
  68. else {
  69. for (int i = 0; i<GENOME_LEN-1; i++) {
  70. if (is_op(genome->string[i]) && is_op(genome->string[i+1])) {
  71. return 0;
  72. }
  73. }
  74. }
  75. return 1;
  76. }
  77.  
  78. // Split a string into two pieces, one to the left of the specified delimiter character and
  79. // one to the right. Discard the delimiter.
  80. void split(char *str, char delim, char *left, char *right) {
  81. int i = 0;
  82. while (str[i] != delim) {
  83. left[i] = str[i++];
  84. }
  85. left[i++] = '\0';
  86. int j = 0;
  87. while(str[i] != '\0') {
  88. right[j++] = str[i++];
  89. }
  90. right[j] = '\0';
  91. }
  92.  
  93. // Evaluate an expression involving integers and the four binary operators +, -, *, and /.
  94. int eval(char *str) {
  95. char left[GENOME_LEN+1];
  96. char right[GENOME_LEN+1];
  97. long num;
  98. if (strchr(str, '-') != NULL) { // subtraction has the lowest precedence
  99. split(str, '-', left, right);
  100. return (eval(left) - eval(right));
  101. } else if (strchr(str, '+') != NULL) {
  102. split(str, '+', left, right);
  103. return (eval(left) + eval(right));
  104. } else if (strchr(str, '/') != NULL) {
  105. split(str, '/', left, right);
  106. return (eval(left) / eval(right));
  107. } else if (strchr(str, '*') != NULL) {
  108. split(str, '*', left, right); // multiplication has the highest precedence
  109. return (eval(left) * eval(right));
  110. } else {
  111. sscanf(str, "%d", &num);
  112. return(num);
  113. }
  114. }
  115.  
  116. // Calculate a genome's fitness by evaluating its character string.
  117. int fitness(genome_t *genome) {
  118. return eval(genome->string);
  119. }
  120.  
  121. // Display a genome as a character string.
  122. void display_genome(genome_t *genome) {
  123. printf("%s", genome->string);
  124. }
  125.  
  126. // move cursor to the home position
  127. void cursor_home() {
  128. printf("\x1b[H");
  129. }
  130.  
  131. // overwrite everything on the screen with spaces
  132. void clear_screen() {
  133. cursor_home();
  134. for (int i=0; i < NUM_LINES; i++) {
  135. for (int j=0; j < CHARS_PER_LINE; j++) {
  136. putchar(' ');
  137. }
  138. printf("\n\r");
  139. }
  140. }
  141.  
  142. // Mutate genome by swapping two loci
  143. void transpose(genome_t *genome) {
  144. int idx1, idx2;
  145. int temp;
  146.  
  147. idx1 = rand()%GENOME_LEN;
  148. idx2 = rand()%GENOME_LEN;
  149. if (idx1 != idx2) {
  150. temp = genome->string[idx1];
  151. genome->string[idx1] = genome->string[idx2];
  152. genome->string[idx2] = temp;
  153. }
  154. }
  155.  
  156. // Mutate genome by moving a char from one location to another.
  157. void move_char(genome_t *genome) {
  158. char c;
  159. int old_pos, new_pos;
  160.  
  161. old_pos = rand()%GENOME_LEN;
  162. new_pos = rand()%GENOME_LEN;
  163. if (old_pos == new_pos) {
  164. return;
  165. }
  166. c = genome->string[old_pos];
  167. if (old_pos < new_pos) {
  168. for (int i=old_pos; i<=new_pos; i++) {
  169. genome->string[i] = genome->string[i+1];
  170. }
  171. } else {
  172. for (int i=old_pos; i>=new_pos; i--) {
  173. genome->string[i] = genome->string[i-1];
  174. }
  175. }
  176. genome->string[new_pos] = c;
  177. }
  178.  
  179. // Perform one of two types of mutation with 50% probability each.
  180. void mutate(genome_t *genome) {
  181. if (rand()%2) {
  182. transpose(genome);
  183. } else {
  184. move_char(genome);
  185. }
  186. }
  187.  
  188. // Copy old genome to new, mutating conditionally.
  189. void reproduce(genome_t *old, genome_t *new) {
  190. if ((double)rand()/(double)RAND_MAX < MUTATION_RATE) {
  191. do {
  192. for (int i=0; i < GENOME_LEN; i++) {
  193. new->string[i] = old->string[i];
  194. }
  195. mutate(new);
  196. } while (!is_legal(new));
  197. }
  198. new->fitness = fitness(new);
  199. }
  200.  
  201. // Initialize a genome randomly
  202. void init_genome_rand(genome_t *genome) {
  203. strcpy(genome->string, "123456789+-*/");
  204. for (int i=0; i < 200; i++) {
  205. mutate(genome);
  206. }
  207. while (!is_legal(genome)) {
  208. mutate(genome);
  209. }
  210. genome->fitness = fitness(genome);
  211. }
  212.  
  213. // Comparison function for use by qsort() library routine
  214. int compare_fitness (const void * elem1, const void * elem2) {
  215. if (((genome_t *)elem2)->fitness > ((genome_t *)elem1)->fitness) return 1;
  216. if (((genome_t *)elem2)->fitness == ((genome_t *)elem1)->fitness) return 0;
  217. return -1;
  218. }
  219.  
  220. //
  221. // From http://stackoverflow.com/questions/448944/c-non-blocking-keyboard-input
  222. //
  223.  
  224. struct termios orig_termios;
  225.  
  226. void reset_terminal_mode()
  227. {
  228. tcsetattr(0, TCSANOW, &orig_termios);
  229. }
  230.  
  231. void set_conio_terminal_mode()
  232. {
  233. struct termios new_termios;
  234.  
  235. /* take two copies - one for now, one for later */
  236. tcgetattr(0, &orig_termios);
  237. memcpy(&new_termios, &orig_termios, sizeof(new_termios));
  238.  
  239. /* register cleanup handler, and set the new terminal mode */
  240. atexit(reset_terminal_mode);
  241. cfmakeraw(&new_termios);
  242. tcsetattr(0, TCSANOW, &new_termios);
  243. }
  244.  
  245. int kbhit()
  246. {
  247. struct timeval tv = { 0L, 0L };
  248. fd_set fds;
  249. FD_ZERO(&fds);
  250. FD_SET(0, &fds);
  251. return select(1, &fds, NULL, NULL, &tv);
  252. }
  253.  
  254. int getch()
  255. {
  256. int r;
  257. unsigned char c;
  258. if ((r = read(0, &c, sizeof(c))) < 0) {
  259. return r;
  260. } else {
  261. return c;
  262. }
  263. }
  264.  
  265. int main() {
  266.  
  267. long long generation = 0; // generation count
  268. int i;
  269. int selection_enabled = ENABLE_SELECTION;
  270. char ascii_target[GENOME_LEN+1];
  271. char c;
  272.  
  273. set_conio_terminal_mode();
  274.  
  275. printf("\n\n\n\n\r");
  276.  
  277. // set cursor to home position, clear screen, and rehome
  278. clear_screen();
  279. cursor_home();
  280.  
  281. // seed the random number generator with the current time
  282. srand(time(NULL));
  283.  
  284. // randomly initialize the genomes of the entire population
  285. for (i=0; i < POPULATION_SIZE; i++) {
  286. init_genome_rand(&genome_array[i]);
  287. }
  288. printf("\n\n\rInitial Organism 0 Genome:\n\n\r");
  289. display_genome(&genome_array[0]);
  290. printf("\n\n\n\r");
  291.  
  292. while (genome_array[0].fitness < FITNESS_THRESHOLD) {
  293.  
  294. // preserve the survivors, but convert the rest into mutated copies of the survivors
  295. for (i=0; i < POPULATION_SIZE - NUM_SURVIVORS; i++) {
  296. reproduce(&genome_array[i%NUM_SURVIVORS], &genome_array[i+NUM_SURVIVORS]);
  297. }
  298.  
  299. if (selection_enabled) {
  300. // sort the genomes into descending order by fitness
  301. qsort(genome_array, POPULATION_SIZE, sizeof(genome_t), compare_fitness);
  302. } else {
  303. // randomly scramble the genome array
  304. scramble_genomes();
  305. }
  306.  
  307. ++generation;
  308.  
  309. // in step mode, pause and display all genomes periodically
  310. if (STEP_MODE && generation % DISPLAY_INTERVAL == 0) {
  311. clear_screen();
  312. cursor_home();
  313. printf("\n\n\rGeneration: %lld\n\r", generation);
  314. printf("\n\rSelection: %s\n\n\r", selection_enabled ? "ON" : "OFF");
  315. for (i = 0; i < GENOMES_TO_DISPLAY; i++) {
  316. printf("Organism %d Fitness %d\n\n\r", i, genome_array[i].fitness);
  317. display_genome(&genome_array[i]);
  318. printf("\r\n\n\n");
  319. }
  320. usleep(PAUSE_TIME); // pause briefly before continuing
  321. }
  322.  
  323. if (!STEP_MODE && generation % DISPLAY_INTERVAL == 0) {
  324. printf("generation = %lld fitness = %d \n\r", generation, genome_array[0].fitness);
  325. }
  326.  
  327. if (kbhit()) { // keystroke detected
  328. switch(getch()) {
  329. case 'q': // quit the program
  330. exit(0);
  331.  
  332. case 'p': // pause until next keystroke
  333. printf("Paused: Hit any key to continue\r\n");
  334. while(!kbhit()){
  335. ;
  336. }
  337. (void)getch(); // consume character
  338. break;
  339.  
  340. case 'r': // restart with a new set of randomized genomes
  341. for (i=0; i < POPULATION_SIZE; i++) {
  342. init_genome_rand(&genome_array[i]);
  343. }
  344. generation = 0;
  345. break;
  346.  
  347. case 's': // toggle selection on and off
  348. selection_enabled = !selection_enabled;
  349. break;
  350. }
  351. }
  352. }
  353.  
  354. printf("\n\n\rWinning generation = %lld fitness = %d \n\r", generation, genome_array[0].fitness);
  355. printf("\n\rWinning genome:\n\n\r");
  356. display_genome(&genome_array[0]);
  357. printf("\n\n\r");
  358. tcsetattr(0, TCSANOW, &orig_termios);
  359. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement