forked from stinaq/WEASEL
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathc.c
144 lines (112 loc) · 3.08 KB
/
c.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// For strdup to work
#define _POSIX_C_SOURCE 200809L
/**
Weasel implementaion
to compile:
[clang|gcc] -pipe -m64 -ansi -fPIC -g -O3 -fno-exceptions -fstack-protector \
-fvisibility=hidden -W -Wall -Wno-unused-parameter -Wno-unused-function \
-Wno-unused-label -Wpointer-arith -Wformat -Wreturn-type -Wsign-compare \
-Wmultichar -Wformat-nonliteral -Winit-self -Wuninitialized \
-Wno-deprecated -Wformat-security -Werror -std=c11 -c c.c
**/
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
const char* GENES = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
const char* PERFECT_GENES = "METHINKS IT IS LIKE A WEASEL";
const int MUTATION_FACTOR = 4; // percent
const int LITTER_SIZE = 100;
typedef struct {
char* genes;
} Weasel;
int
random_l(int limit) {
/**
return a random number between 0 and limit inclusive.
No skew version
**/
int divisor = RAND_MAX/(limit+1);
int result;
do {
result = rand() / divisor;
} while (result > limit);
return result;
}
char
random_gene() {
return GENES[random_l(strlen(GENES) - 1)];
}
int
init_weasel(Weasel* w, char* parent_genes) {
const int GENE_COUNT = strlen(PERFECT_GENES);
char gs[GENE_COUNT + 1];
if (parent_genes != NULL) {
for (int i = 0; i < GENE_COUNT; i++) {
if (random_l(100) < MUTATION_FACTOR) {
gs[i] = random_gene();
} else {
gs[i] = parent_genes[i];
}
}
} else {
for (int i = 0; i < GENE_COUNT; i++) {
gs[i] = random_gene();
}
}
gs[GENE_COUNT] = '\0';
w->genes = strdup(gs);
return 0;
}
int
weasel_procreate(Weasel* parent, Weasel* children) {
for (int i = 0; i < LITTER_SIZE; i++) {
init_weasel(&children[i], parent->genes);
}
return 0;
}
unsigned long
get_score(Weasel* w) {
const int GENE_COUNT = strlen(PERFECT_GENES);
int score = 0;
for (int i = 0; i < GENE_COUNT; i++) {
if (w->genes[i] == PERFECT_GENES[i]) { score++; }
}
return (unsigned long)score;
}
int
cmp_weasels(const void* a, const void* b) {
/**
finds out which weasel is the better suited.
negative result means weasel A was better
0 means they are equally good
positive means weasel B was better
parameters are (void *)s since the qsort
requires them to be such.
**/
Weasel* wa = (Weasel*)a; Weasel* wb = (Weasel*)b;
int a_score = get_score(wa);
int b_score = get_score(wb);
return b_score - a_score;
}
int
main(void) {
// seed the random
srand(time(NULL));
Weasel* w = (Weasel*) malloc(sizeof(Weasel));
Weasel* children = malloc(sizeof(Weasel) * LITTER_SIZE);
init_weasel(w, NULL);
int counter = 0;
while (get_score(w) != strlen(PERFECT_GENES)) {
printf("Genes: [%s], Score: %lu, Iteration: %i\n", w->genes, get_score(w), ++counter);
weasel_procreate(w, children);
qsort(children, LITTER_SIZE, sizeof(Weasel), cmp_weasels);
*w = children[0];
// free the memory used by the inferior weasels.
for (int i = 1; i < LITTER_SIZE; i++) {
free(children[i].genes);
}
}
printf("Winner: %s, after %i generations!\n", w->genes, counter);
return 0;
}