utils.c (10885B)
1 /*** 2 * utils.c 3 * 4 * utility subroutines for tree 5 * 6 *** 7 * version 2 8 *** 9 * print_states_dot() now only prints one of the two links, 10 * using Jim's pointer trick. 11 * now outputs colored links (red for rotation, red for step) 12 ***/ 13 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include "primes.h" 17 #include "perm_gen.h" 18 19 // type definitions used later 20 typedef struct advance_node_type *advance_node; 21 typedef struct state_type *state; 22 23 // since the number of times you can advance the tiles is variable, 24 // links to the states that result from those changes will go into an 25 // array 26 struct advance_node_type { 27 int steps; // how far to advance 28 state leads_to; // what state you enter after making that move 29 advance_node next; 30 }; 31 32 // constructor for advance_node 33 advance_node new_advance_node(int i, advance_node next, state leads_to) { 34 advance_node self = (advance_node) malloc(sizeof(struct advance_node_type)); 35 if (self){ // don't do this if memory wasn't allocated. 36 self->steps = i; // set fields 37 self->next = next; 38 self->leads_to = NULL; 39 } 40 return self; 41 } 42 43 // 44 struct state_type { 45 link board; 46 state next; 47 state rotate; 48 advance_node advances; 49 }; 50 51 // constructor for single node 52 state new_state(link chain, state next) { 53 state self = (state) malloc(sizeof(struct state_type)); 54 if (self){ // don't do this if memory wasn't allocated. 55 self->board = chain; // set fields 56 self->next = next; 57 self->rotate = NULL; // set later 58 self->advances = NULL; // set later 59 } 60 return self; 61 } 62 63 // utilities 64 65 // compute the base signature of a chain of a given size 66 // i.e. if the board is size 3, the base sig is 67 // (first prime) * (second prime) * (3rd prime) 68 // 2*3*5 = 30 69 int base_signature(prime list) { 70 int product = 1; 71 while (list != NULL) { 72 product *= list->value; 73 list = list->next; 74 } 75 return product; 76 } 77 78 // compute the signature of a given chain 79 // i.e. if the chain is (0,1,1): 80 // sig = 2*3*3 = 18 81 int gen_sig (link chain, prime list) { 82 link first_chain = chain; 83 prime first_prime = list; 84 int product = 1; 85 while (chain != NULL) { 86 int i = chain->value; 87 list = first_prime; 88 //printf(" for %d:\n", chain->value); 89 while((list != NULL) && (i > 0)) { 90 i--; 91 list = list->next; 92 } 93 //printf(" prime is %d\n", list->value); 94 product *= list->value; 95 chain = chain->next; 96 } 97 return product; 98 } 99 100 // given the base signature of chain of length n, 101 // determine if a given chain contains duplicates 102 int no_dupes(link chain, int sig, prime primes) { 103 if (gen_sig(chain, primes) != sig) { 104 return 0; 105 } 106 return 1; 107 } 108 109 // given a chain and a distance, advance chain until that position 110 // fails for numbers higher than n-1, where n is the size of the chain 111 link advance(link chain, int r) { 112 link old_start = chain; // pointer to first 113 // move to the rth node 114 while (r > 0) { 115 r--; 116 chain = chain->next; 117 } 118 link new_start = chain; // this is the new start of the chain 119 // move to the end of the chain 120 while (chain->next != NULL) { 121 chain = chain->next; 122 } 123 chain->next = old_start; // connect old start to end 124 // add the null to the end of old chain segment 125 while (chain->next != new_start) { 126 chain = chain->next; 127 } 128 chain->next = NULL; 129 return new_start; 130 } 131 132 // given a chain and a wheel radius, spin the first r elements of the chain 133 link spin(link chain, int r) { 134 link old = chain; 135 // move to the rth node 136 while (r > 1) { 137 r--; 138 chain = chain->next; 139 } 140 link new_start = chain; 141 link broken = chain->next; // bit that is not spun 142 link end = broken; 143 // pull bits off start, add to end of broken 144 while (old->next != end) { 145 link tmp = old->next; 146 old->next = broken; 147 broken = old; 148 old = tmp; 149 } 150 new_start->next = broken; // reconnect broken bits to start 151 return new_start; 152 } 153 154 // print list of chains 155 int print_states(state first) { 156 printf(" list of states:\n"); 157 state tmp = first; 158 while (tmp != NULL) { 159 printf(" %p\n board: ", tmp); 160 link links = tmp->board; 161 while (links != NULL) { 162 printf("%d ", links->value); 163 links = links->next; 164 } 165 printf("\n"); 166 printf(" rotate: %p\n", tmp->rotate); 167 printf(" steps: "); 168 advance_node tmp_ad = tmp->advances; 169 while (tmp_ad != NULL) { 170 printf("%d->%p ", tmp_ad->steps, tmp_ad->leads_to); 171 tmp_ad = tmp_ad->next; 172 } 173 printf("\n"); 174 tmp = tmp->next; 175 } 176 return 0; 177 } 178 179 // radix addition 180 // returns a new chain 181 link radix_increment(link target, int base) { 182 link new = chain_cpy(target); 183 link marker = new; 184 while (marker != NULL) { 185 if (marker->value < (base - 1)) { 186 marker->value++; 187 return new; 188 } 189 marker->value = 0; 190 marker = marker->next; 191 } 192 return NULL; // not big enough 193 }; 194 195 // given n (number of links in chain), return list of possible advances 196 advance_node n_advances(int n) { 197 n--; 198 advance_node marker = new_advance_node(n, NULL, NULL); 199 while (n > 1) { 200 n--; 201 advance_node new_node = new_advance_node(n, marker, NULL); 202 marker = new_node; 203 } 204 return marker; 205 } 206 207 // given the number of links, create a list of all the chain permutations with 208 // that many links 209 state generate_perms(int n) { 210 //printf(" generating possible chains:\n"); 211 // list of the first n primes 212 prime primes = first_n_primes(n); 213 // base signature 214 int base_sig = base_signature(primes); 215 //printf(" base signature: %d\n", base_sig); 216 // empty chain list 217 state states = new_state(NULL, NULL); 218 states->advances = n_advances(n); 219 // first one is lowest possible number with all linksn_ 220 link lowest = new_chain(n); 221 link cur = lowest; 222 int c = n; 223 // fill in the first links 224 // i.e. 0 1 2 3 225 while (cur != NULL) { 226 c--; 227 cur->value = c; 228 cur = cur->next; 229 } 230 //printf(" lowest: "); 231 // print_chain(lowest); 232 //printf("\n"); 233 // highest possible is reverse of lowest 234 int k = 0; 235 link highest = new_chain(n); 236 cur = highest; 237 while (cur != NULL) { 238 cur->value = k; 239 cur = cur->next; 240 k++; 241 } 242 //printf(" highest: "); 243 // print_chain(highest); 244 //printf("\n"); 245 states->board = lowest; // first link in chain 246 state tmp_state = states; // generic marker version 247 link poss = chain_cpy(tmp_state->board); 248 //printf(" trying: (*success)\n"); 249 while (!chains_equal(tmp_state->board, highest)) { 250 poss = radix_increment(poss, n); 251 //printf(" "); 252 //print_chain(poss); 253 if (no_dupes(poss, base_sig, primes)) { 254 state add_state = new_state(chain_cpy(poss), NULL); 255 add_state->advances = n_advances(n); 256 tmp_state->next = add_state; 257 tmp_state = add_state; 258 //printf("*"); 259 } 260 //printf("\n"); 261 } 262 return states; 263 } 264 265 // given a list of states and a board, find the state with the board 266 state board_search(link query, state states) { 267 state marker = states; 268 while (marker != NULL) { 269 if (chains_equal(query, marker->board)) { 270 return marker; 271 } 272 marker = marker->next; 273 } 274 return NULL; 275 } 276 277 // given a state, pair it with it's rotated state 278 int link_rotations(state this_state, state states, int diameter) { 279 if (this_state->rotate != NULL) { 280 return 0; 281 } 282 link board = spin(chain_cpy(this_state->board), diameter); 283 state mate = board_search(board, states); 284 if (mate) { 285 this_state->rotate = mate; 286 mate->rotate = this_state; 287 return 1; 288 } 289 return 0; 290 } 291 292 // given a state and a step, pair it with it's complementary step 293 int link_steps(state this_state, state states, advance_node adv, int n) { 294 if (adv->leads_to != NULL) { 295 return 0; 296 } 297 link board = advance(chain_cpy(this_state->board), adv->steps); 298 state mate = board_search(board, states); 299 if (mate) { 300 adv->leads_to = mate; 301 int i = n - adv->steps; 302 advance_node tmp_adv = mate->advances; 303 while (tmp_adv->steps != i) { 304 tmp_adv = tmp_adv->next; 305 } 306 tmp_adv->leads_to = this_state; 307 return 1; 308 } 309 return 0; 310 } 311 312 // given a number of links and the wheel diameter, 313 // create the list of permutations and link them 314 state build_universe(int n, int d) { 315 state states = generate_perms(n); 316 state st_marker = states; 317 while (st_marker != NULL) { 318 link_rotations(st_marker, states, d); 319 advance_node adv_marker = st_marker->advances; 320 while (adv_marker->next != NULL) { 321 link_steps(st_marker, states, adv_marker, n); 322 adv_marker = adv_marker->next; 323 } 324 st_marker = st_marker->next; 325 } 326 return states; 327 } 328 329 // print board in dot-friend format 330 int print_board_dot(link board) { 331 printf("\""); 332 print_chain(board); 333 printf("\""); 334 return 1; 335 } 336 337 // print states in dot format 338 int print_states_dot(state states, int n) { 339 printf("graph T {\n"); 340 state st_marker = states; 341 while (st_marker != NULL) { 342 /*** 343 * if p1 < p2 344 * prevents duplicates 345 * (Jim's idea) 346 ***/ 347 // print rotate relationship 348 if (st_marker < st_marker->rotate) { 349 print_board_dot(st_marker->board); 350 printf(" -- "); 351 print_board_dot(st_marker->rotate->board); 352 printf(" [color=red];\n"); 353 } 354 // print each advance relationship 355 advance_node ad_marker = st_marker->advances; 356 while (ad_marker != NULL) { 357 if (st_marker < ad_marker->leads_to) { 358 print_board_dot(st_marker->board); 359 printf(" -- "); 360 print_board_dot(ad_marker->leads_to->board); 361 printf(" [color=blue];\n"); 362 } 363 ad_marker = ad_marker->next; 364 } 365 st_marker = st_marker->next; 366 } 367 printf("}\n"); 368 return 0; 369 } 370 371 372 int test_utils() { 373 printf("***general utility tests\n"); 374 prime test_prime = first_n_primes(3); 375 print_primes(test_prime); 376 int base = base_signature(test_prime); 377 printf(" base signature: %d\n", base); 378 link test_chain = new_chain(3); 379 test_chain->value = 0; 380 test_chain->next->value = 1; 381 test_chain->next->next->value = 2; 382 printf(" chain: "); 383 print_chain(test_chain); 384 printf("\n"); 385 printf(" chain signature: %d\n", gen_sig(test_chain, test_prime)); 386 printf(" no dupes? (expect 1): %d\n", no_dupes(test_chain, base, test_prime)); 387 link test_chain2 = advance(test_chain, 2); 388 printf(" advance chain 2: "); 389 print_chain(test_chain2); 390 printf("\n"); 391 link test_chain3 = spin(test_chain2, 2); 392 printf(" spin chain 2: "); 393 print_chain(test_chain3); 394 printf("\n"); 395 test_chain3 = radix_increment(test_chain3, 3); 396 printf(" add 1 radix 3: "); 397 print_chain(test_chain3); 398 printf("\n"); 399 test_chain3 = radix_increment(test_chain3, 3); 400 printf(" add 1 radix 3: "); 401 print_chain(test_chain3); 402 printf("\n"); 403 test_chain3 = radix_increment(test_chain3, 3); 404 printf(" add 1 radix 3: "); 405 print_chain(test_chain3); 406 printf("\n"); 407 test_chain3 = radix_increment(test_chain3, 3); 408 printf(" add 1 radix 3: "); 409 print_chain(test_chain3); 410 printf("\n"); 411 //////////////////////////////// 412 printf("***make the universe, pair some states\n"); 413 state test_state = generate_perms(3); 414 link_rotations(test_state, test_state, 2); 415 link_steps(test_state->next, test_state, test_state->next->advances->next, 3); 416 print_states(test_state); 417 /////////////////////////////// 418 printf("***make the universe, fill all states\n"); 419 print_states(build_universe(3, 2)); 420 printf("***output for dot\n"); 421 print_states_dot(build_universe(3, 2),3); 422 return 0; 423 } 424