1 /* fullgen.c */
2 /* Aktuellste Version -- mit Symmetriebetrachtungen */
3 /* 12.9.1996: - zusaetzliche Option "pid" (fuer GenView)
4 17.7.1996: - Fehler-Exits durchnumeriert (fuer GenView)
5 - mehrere Symmetrien erlaubt
6 24.10.2000: - added code 8 for sparse6 output
7 and made some other insignificant changes */
8 /* 24.2.2011: S+12 -> S+13 in dualcode arraygroesse. Hier wird ab 1
9 gezaehlt... */
10 /* 6.10.2011: Fehler verbessert, der ab 136 Knoten Fullerene (eins bei 136) faelschlicherweise verwarf. */
11 /* 16.6. 2014: problem mit code 3 und mehreren knotenzahlen und gleichzeitig
12 output auf stdout geloest. */
13 /* 13.2.2016: Fehler bei Detektierung von Cs mit Fixkanten verbessert */
14 /* 23.2.2016: Den Effekt desselben Fehlers bei anderen Gruppen entfernt. */
15
16 #include<sys/types.h>
17 #include<unistd.h>
18 #include<stdlib.h>
19 #include<stdio.h>
20 #include<ctype.h>
21 #include<limits.h>
22 #include<sys/stat.h>
23 #include<string.h>
24
25 #ifndef NOTIMES
26 #include<time.h>
27 #include<sys/times.h>
28 #endif //NOTIMES
29
30 #define S 140 /* Maximale Anzahl der 6-Ecke */
31 #define N ((4*S)+20) /* Maximal moegliche Anzahl der Knoten */
32
33
34 #define aussen (N+2) /* so werden kanten nach aussen markiert */
35
36 #define infty LONG_MAX
37 #define FL_MAX UCHAR_MAX
38 #define KN_MAX USHRT_MAX
39 #define unbelegt FL_MAX
40 #define leer KN_MAX-1
41 #define f_leer FL_MAX-1
42 #define False 0
43 #define True 1
44 #define nil 0
45 #define reg 3
46 #define filenamenlaenge 200 /* sollte vorerst reichen */
47
48 #ifndef NOTIMES
49 #if !defined(CLK_TCK) && !defined(_SC_CLK_TCK)
50 #include <time.h>
51 #endif
52 #if !defined(CLK_TCK) && !defined(_SC_CLK_TCK)
53 #include <unistd.h>
54 #endif
55 #if !defined(CLK_TCK) && defined(_SC_CLK_TCK)
56 #define CLK_TCK sysconf(_SC_CLK_TCK)
57 #endif
58 #ifndef CLK_TCK
59 #define CLK_TCK 60 /* If the CPU time stated by the program appears
60 to be out by a constant ratio, the most likely
61 explanation is that the code got to this point but
62 60 is the wrong guess. Another common value is 100. */
63 #endif
64
65 #define time_factor CLK_TCK
66 #endif //NOTIMES
67
68 /*
69 the macro 'my_endianness' is a char value of 'b' for big-endian
70 and 'l' for little-endian machines
71 */
72 static unsigned short word = (((unsigned short) 'b') << 8) | 'l';
73 # define my_endianness (* (char *) &word)
74
75
76 /* weitere Konstanten (TH) fuer die Kennzeichnung der Symmetriegruppen: */
77 /* (Werte nicht veraendern - oder synchron dazu die Strings mit den
78 Bezeichnungen der Symmetriegruppen aendern) */
79 #define C1__ 1
80 #define C2__ 2
81 #define Ci__ 3
82 #define Cs__ 4
83 #define C3__ 5
84 #define D2__ 6
85 #define S4__ 7
86 #define C2v__ 8
87 #define C2h__ 9
88 #define D3__ 10
89 #define S6__ 11
90 #define C3v__ 12
91 #define C3h__ 13
92 #define D2h__ 14
93 #define D2d__ 15
94 #define D5__ 16
95 #define D6__ 17
96 #define D3h__ 18
97 #define D3d__ 19
98 #define T__ 20
99 #define D5h__ 21
100 #define D5d__ 22
101 #define D6h__ 23
102 #define D6d__ 24
103 #define Td__ 25
104 #define Th__ 26
105 #define I__ 27
106 #define Ih__ 28
107
108
109 /* konstante Strings zur Kennzeichnung der Symmetriegruppen: */
110
111 char symm_name[29][4] =
112 {{' ',' ',' ','\0'}, {'C','1',' ','\0'}, {'C','2',' ','\0'},
113 {'C','i',' ','\0'}, {'C','s',' ','\0'}, {'C','3',' ','\0'},
114 {'D','2',' ','\0'}, {'S','4',' ','\0'}, {'C','2','v','\0'},
115 {'C','2','h','\0'}, {'D','3',' ','\0'}, {'S','6',' ','\0'},
116 {'C','3','v','\0'}, {'C','3','h','\0'}, {'D','2','h','\0'},
117 {'D','2','d','\0'}, {'D','5',' ','\0'}, {'D','6',' ','\0'},
118 {'D','3','h','\0'}, {'D','3','d','\0'}, {'T',' ',' ','\0'},
119 {'D','5','h','\0'}, {'D','5','d','\0'}, {'D','6','h','\0'},
120 {'D','6','d','\0'}, {'T','d',' ','\0'}, {'T','h',' ','\0'},
121 {'I',' ',' ','\0'}, {'I','h',' ','\0'}};
122
123 /* Typ-Deklarationen: */
124
125 typedef char BOOL; /* von 0 verschieden entspricht True */
126
127 typedef unsigned short KNOTENTYP;
128 typedef unsigned char FLAECHENTYP; /* Bereich 1..252 */ /* DO NOT CHANGE ! Changes in the coding
129 and at several places where FL_MAX is used (as a sign !)
130 are necessary */
131
132 typedef KNOTENTYP GRAPH[N+1][3]; /* fuer schreibegraph und Isomorphietest */
133
134 /* Element der Adjazenztabelle: */
135
136
137 typedef struct BBiL {
138 struct BBiL *next_item;
139 FLAECHENTYP code[8];
140 } BBITEMLISTE; /* die BBItems -- d.h. Codes */
141
142 typedef struct BBiallocL {
143 struct BBiallocL *prev;
144 BBITEMLISTE *space;
145 } BBALLOCLISTE; /* die allozierten 1000er BBitemfelder */
146
147
148 typedef struct iL {
149 struct iL *next_item;
150 FLAECHENTYP code[5];
151 } ITEMLISTE; /* die Items -- d.h. Codes */
152
153
154 typedef struct BBsL {
155 int number_next;
156 BBITEMLISTE **items;
157 } BBSEQUENZLISTE; /* die verzweigung der liste nach der Sequenz */
158
159
160 typedef struct sL {
161 struct sL **next_level;
162 int number_next;
163 ITEMLISTE *items;
164 ITEMLISTE *last_item;
165 } SEQUENZLISTE; /* die verzweigung der liste nach der Sequenz */
166
167
168
169 typedef struct BBSL {
170 int total_items;
171 int total_maps;
172 BBSEQUENZLISTE *sechser[S+1];
173 } BBS_LISTE; /* die erste stufe der liste -- verzweigung nach Anzahl der 6-Ecke */
174
175
176 typedef struct SL {
177 int total_maps;
178 SEQUENZLISTE *sechser[S+1];
179 } S_LISTE; /* die erste stufe der liste -- verzweigung nach Anzahl der 6-Ecke */
180
181
182 typedef struct K {
183 KNOTENTYP ursprung; /* bei welchem knoten startet die kante */
184 KNOTENTYP name; /* Identifikation des Knotens, mit
185 dem Verbindung besteht */
186 long dummy; /* fuer alle moeglichen zwecke */
187 BOOL nostart;
188 BOOL noleft; /* fuer die Rekonstruktion: Keine Flaeche links hiervon */
189 BOOL noright; /* fuer die Rekonstruktion: Keine Flaeche rechts hiervon */
190 BOOL mirror_nostart;
191 KNOTENTYP mininame; /* jeweils fuer den minimalitaetstest */
192 struct K *prev; /* vorige Kante im Uhrzeigersinn */
193 struct K *next; /* naechste Kante im Uhrzeigersinn */
194 struct K *invers; /* die inverse Kante (in der Liste von "name") */
195 } KANTE;
196
197 typedef struct {
198 int laenge;
199 int sequenz[7]; /* die laenge der luecke. Konvention: Beendet durch "leer" */
200 KANTE *kanten[7];/* die letzten aussenkanten vor der sequenz */
201 char k_marks[7]; /* 1 wenn anfang einer kanonischen Sequenz, 0 sonst */
202 } SEQUENZ;
203
204
205 typedef struct le { FLAECHENTYP code[12];
206 struct le *smaller;
207 struct le *larger; } LISTENTRY;
208
209
210 /* "Ueberschrift" der Adjazenztabelle (Array of Pointers): */
211 typedef KANTE PLANMAP[N+1][3];
212 /* Jeweils 3 KANTEn */
213 /* ACHTUNG: 1. Zeile der Adjazenztabelle hat Index 0 -
214 wird fast nicht benutzt, N Zeilen auch ausreichend
215 In [0][0].name wird aber die knotenzahl gespeichert */
216
217
218 /*********************GLOBALE*VARIABLEN********************************/
219
220 /* Die folgenden Variablen werden von fast allen Programmteilen benutzt
221 oder werden aus anderen Gruenden global verwaltet. Trotzdem werden
222 sie in einigen Faellen auch an Funktionen uebergeben, um die
223 Parameterabhaengigkeit der Funktionen zu betonen */
224 /* Variablen-Deklarationen: */
225
226
227 int output; /* soll auf stdout geschrieben werden */
228 int knotenzahl; /* Knotenzahl des Graphen;
229 ergibt sich aus Eingabe; wird im Verlauf
230 der Konstruktion nicht geaendert */
231
232 long long int non_iso_graphenzahl[N+1];
233 long long int graphenzahl[N+1];
234
235 S_LISTE mapliste;
236 BBS_LISTE bbliste;
237
238 KANTE *F_eck_kanten[60]; /* eine liste aller kanten, so dass links davon ein
239 5-Eck liegt */
240 int anzahl_5ek; /* die momentane Anzahl der eingetragenen kanten */
241
242 int max_sechsecke,min_sechsecke;
243
244 FLAECHENTYP **lastcode[N]; /* wird bei codeart 3 gebraucht */
245 FLAECHENTYP last_code[12]; /* wird bei codeart 2 gebraucht */
246
247 int minbbl=N, maxbbl=0;
248 int minbrillenglas=N, maxbrillenglas=0;
249 int min_2_3_4=N;
250 int no_penta_spiral=0, no_hexa_spiral=0;
251
252 BOOL bblmark[N+1], brillenglasmark[N+1], zwei_3_4_mark[N+1];
253 BOOL do_bauchbinde,do_brille,do_sandwich;
254
255 LISTENTRY codeliste[N+1];
256
257 FILE *fil[N+1];
258 int write_header_fil[N+1];
259 int write_header_stdout=1;
260 FILE *logfile;
261 char logfilename[filenamenlaenge], no_penta_spiral_filename[filenamenlaenge], no_spiral_filename[filenamenlaenge];
262 char no_hexa_spiral_filename[filenamenlaenge];
263
264 BOOL quiet=0;
265 BOOL IPR=0, is_ipr=1;
266 BOOL to_stdout=0;
267 BOOL hexspi=0, spistat=0;
268 BOOL spiralcheck=0;
269 int codenumber, listenlaenge, mod=0, rest=0;
270 int spiralnumbers[12*S+120+1];
271
272 /* weitere globale Variablen (TH) fuer die Statistik der Symmetriegruppen: */
273
274 BOOL symstat=0; /* 1 -> Symmetriestatistik erstellen */
275 int symm_anz[29]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
276 /* symm_anz[i] enthaelt die Anzahl der gefundenen Fullerene, die die
277 Symmetrien der Symmetriegruppe mit der Nummer i besitzen */
278 char symm[29] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
279 int symm_len = 0;
280 /* Speicher fuer Nummern von Symmetriegruppen, die beruecksichtigt werden sollen
281 und die Anzahl der Eintraege im Array (0 => alle Gruppen beruecksichtigen) */
282 char symmstring[29*4]; /* Dateikennung, falls Symmetriegruppen gewaehlt */
283
284 /* Prototypen: */
285
286 void codiereplanar();
287 void common_history();
288 void schreibemap();
289 void schreibehistory();
290
291 /****************SCHREIBE_SYMMETRIESTATISTIK********TH*****/
292
schreibe_symmetriestatistik()293 void schreibe_symmetriestatistik()
294 { int i, j=0;
295 fprintf(stderr,"Symmetries:\n");
296 for (i=1; i<=28; i++) {
297 if (symm_anz[i]>0) {
298 fprintf(stderr," %s: %10d ",symm_name[i],symm_anz[i]);
299 j++;
300 if (j%4==0) {fprintf(stderr,"\n");}
301 }
302 }
303 if (j%4) {fprintf(stderr,"\n");}
304 }
305
306
307 /**********************CHECKSIZE_MARK_RETURN**************************************/
308
309 /* bestimmt die groesse der flaeche links von edge -- ist da keine gibt's Probleme
310 ausserdem setzt er fuer alle kanten, so dass diese flaeche links davon ist, dummy
311 auf mark. In nextedge wird die im Gegen-Uhrzeigersinn letzte unmarkierte Kante
312 (heisst: die letzte kante mit markierung < mark) zurueckgegeben -- und nil, wenn
313 sie nicht existiert. */
314
checksize_mark_return(KANTE * edge,int mark,KANTE ** nextedge)315 int checksize_mark_return(KANTE* edge, int mark, KANTE **nextedge)
316
317 {
318 KANTE *run;
319 int zaehler=1;
320
321 *nextedge=nil;
322 if (edge->dummy < mark) { *nextedge=edge->invers; edge->dummy=edge->invers->dummy=mark; }
323
324 for (run=edge->invers->next; run != edge; run=run->invers->next)
325 { if (run->dummy < mark) { *nextedge=run->invers; run->dummy=run->invers->dummy=mark; }
326 zaehler++; }
327 return(zaehler);
328 }
329
330
331
332 /**********************CHECKSIZE_MARK_RETURN_RIGHT**************************************/
333
334 /* bestimmt die groesse der flaeche rechts von edge -- sonst wie oben */
335
checksize_mark_return_right(KANTE * edge,int mark,KANTE ** nextedge)336 int checksize_mark_return_right(KANTE* edge, int mark, KANTE **nextedge)
337
338 {
339 KANTE *run;
340 int zaehler=1;
341
342 *nextedge=nil;
343 if (edge->dummy < mark) { *nextedge=edge->invers; edge->dummy=edge->invers->dummy=mark; }
344
345 for (run=edge->invers->prev; run != edge; run=run->invers->prev)
346 {if (run->dummy < mark) { *nextedge=run->invers; run->dummy=run->invers->dummy=mark; }
347 zaehler++;}
348 return(zaehler);
349 }
350
351
352
353
354 /************************GET_SPIRAL_CODE**********************************/
355
get_spiralcode(KANTE * edge,int minmark,FLAECHENTYP cmpcode[12],int sixgons)356 BOOL get_spiralcode ( KANTE *edge, int minmark, FLAECHENTYP cmpcode[12],
357 int sixgons)
358
359 /* entwickelt den Spiralcode, bei dem die erste Flaeche links von edge
360 liegt, die zweite rechts davon und die Entwicklung im Uhrzeigersinn
361 geht. Entwickelt wird solange der Code besser ist als cmpcode. Das
362 Resultat wird in cmpcode geschrieben, wenn es besser ist. Wenn ein
363 Code gefunden wird, der besser ist, als cmpcode, wird 1 zurueckgegeben,
364 sonst 0. Die aufrufende Funktion muss sicherstellen, dass alle Kanten
365 kante->dummy <= minmark erfuellen.
366 */
367
368 {
369 int mark, i;
370 KANTE *nextedge;
371 BOOL kleiner=0;
372 FLAECHENTYP code[12], zaehler;
373 int fuenfecke=0, sechsecke=0; /* zaehler fuer die wirklich eingefuegten Flaechen */
374 int stelle;
375
376 mark=minmark+1;
377
378 if (checksize_mark_return(edge, mark, &nextedge)==5)
379 { code[0]=1; stelle=0; fuenfecke=1; }
380 else { stelle= -1; sechsecke=1; }
381 if (checksize_mark_return_right( edge, mark, &nextedge)==5)
382 { stelle++; code[stelle]=2; fuenfecke++; } else sechsecke++;
383
384 for (i=0; (i<=stelle) && (!kleiner); i++)
385 { if (code[i]>cmpcode[i]) return(0);
386 if (code[i]<cmpcode[i]) kleiner=1; }
387
388 zaehler=3;
389
390 while (nextedge != nil)
391 { if (checksize_mark_return_right(nextedge, mark, &nextedge)==5)
392 { fuenfecke++;
393 stelle++; code[stelle]=zaehler;
394 if (!kleiner)
395 { if (zaehler>cmpcode[stelle]) { return(0); }
396 if (zaehler<cmpcode[stelle]) kleiner=1;
397 }
398 }
399 else sechsecke++;
400 zaehler++;
401 }
402
403 if ((fuenfecke<12) || (sechsecke < sixgons)) return(0);
404
405 for (i=0; i<12; i++) cmpcode[i]=code[i];
406 return(1);
407 }
408
409
410 /************************GET_SPIRAL_CODE_INV**********************************/
411
get_spiralcode_inv(KANTE * edge,int minmark,FLAECHENTYP cmpcode[12],int sixgons)412 BOOL get_spiralcode_inv ( KANTE *edge, int minmark, FLAECHENTYP cmpcode[12],
413 int sixgons)
414
415 /* entwickelt den Spiralcode, bei dem die erste Flaeche links von edge
416 liegt, die zweite rechts davon und die Entwicklung im GEGEN-Uhrzeigersinn
417 geht. Sonst wie oben */
418
419 {
420 int mark, i;
421 KANTE *nextedge;
422 BOOL kleiner=0;
423 FLAECHENTYP code[12], zaehler;
424 int fuenfecke=0, sechsecke=0; /* zaehler fuer die wirklich eingefuegten Flaechen */
425 int stelle;
426
427 mark=minmark+1;
428
429 if (checksize_mark_return( edge, mark, &nextedge)==5)
430 { code[0]=1; stelle=0; fuenfecke=1; }
431 else { stelle= -1; sechsecke=1; }
432 if (checksize_mark_return_right( edge, mark, &nextedge)==5)
433 { stelle++; code[stelle]=2; fuenfecke++; } else sechsecke++;
434
435 nextedge=edge->invers->prev;
436
437 for (i=0; (i<=stelle) && (!kleiner); i++)
438 { if (code[i]>cmpcode[i]) return(0);
439 if (code[i]<cmpcode[i]) kleiner=1; }
440
441 zaehler=3;
442
443 while (nextedge != nil)
444 {
445 if (checksize_mark_return( nextedge, mark, &nextedge)==5)
446 { fuenfecke++;
447 stelle++; code[stelle]=zaehler;
448 if (!kleiner)
449 { if (zaehler>cmpcode[stelle]) { return(0); }
450 if (zaehler<cmpcode[stelle]) kleiner=1;
451 }
452 }
453 else sechsecke++;
454 zaehler++;
455 }
456
457 if ((fuenfecke<12) || (sechsecke < sixgons)) return(0);
458
459 for (i=0; i<12; i++) cmpcode[i]=code[i];
460 return(1);
461 }
462
463
464 /************************VEGACODE*****************************/
465
vegacode(FILE * fil,PLANMAP map)466 void vegacode( FILE *fil, PLANMAP map )
467
468 {
469 static int erster_aufruf=1;
470 int i;
471
472 if (erster_aufruf)
473 { fprintf(fil,">>writegraph3d planar <<\n");
474 erster_aufruf=0; }
475
476 if (map[0][0].name >= 100)
477 {
478 for (i=1; i<=map[0][0].name; i++)
479 fprintf(fil,"%3d 0 0 0 %3d %3d %3d\n",i,map[i][0].name,map[i][1].name,map[i][2].name);
480 }
481 else
482 {
483 for (i=1; i<=map[0][0].name; i++)
484 fprintf(fil,"%2d 0 0 0 %2d %2d %2d\n",i,map[i][0].name,map[i][1].name,map[i][2].name);
485 }
486 fprintf(fil,"0\n");
487
488 }
489
490 /************************BELEGEDUMMIES************************/
491
belegedummies(KANTE * edge,int nummer)492 void belegedummies(KANTE *edge, int nummer)
493 /* belegt edge->dummy, edge->invers->pre->dummy, ... mit Nummer
494 -- einmal rund um die Flaeche */
495
496 {
497 KANTE *merke;
498
499 merke=edge; edge->dummy=nummer;
500 edge=edge->invers->prev;
501
502 while (edge != merke) { edge->dummy=nummer;
503 edge=edge->invers->prev; }
504 }
505
506
507 /************************DUALCODE*****************************/
508
dualcode(PLANMAP map)509 int dualcode( PLANMAP map )
510
511 {
512 /* berechnet das Dual und schreibt es als planarcode auf stdout */
513
514 int flaechenzahl, knotenzahl, codelaenge=1,i,j, nextnumber=2;
515 FLAECHENTYP code[(S+13)*7]; /* In main wird schon abgefangen, wenn das nicht in
516 unsigned char passt */
517 KANTE *startedge[S+13];
518 KANTE *run, *merke;
519 static int write_header=1;
520
521 if (write_header)
522 { write_header=0;
523 fprintf(stdout,">>planar_code %ce<<", my_endianness);
524 }
525
526
527 knotenzahl=map[0][0].name;
528 code[0]=flaechenzahl= 2 + (map[0][0].name / 2);
529
530
531 for (i=1; i<= knotenzahl; i++) for (j=0; j<3; j++) map[i][j].dummy=0;
532 /* dummy gibt die Nummer der Flaeche rechts der Kante an */
533
534 belegedummies(map[1],1);
535 startedge[1]=map[1];
536
537 for (i=1; i<=flaechenzahl; i++)
538 { merke=startedge[i];
539 if (merke->invers->dummy) { code[codelaenge]=merke->invers->dummy;
540 codelaenge++; }
541 else { code[codelaenge]= nextnumber; codelaenge++;
542 startedge[nextnumber]=merke->invers;
543 belegedummies(merke->invers,nextnumber);
544 nextnumber++; }
545 for (run=merke->invers->prev; run != merke; run=run->invers->prev)
546 { if (run->invers->dummy) { code[codelaenge]=run->invers->dummy;
547 codelaenge++; }
548 else { code[codelaenge]= nextnumber; codelaenge++;
549 startedge[nextnumber]=run->invers;
550 belegedummies(run->invers,nextnumber);
551 nextnumber++; }
552 }
553 code[codelaenge]=0; codelaenge++;
554 }
555
556 fwrite(code,sizeof(FLAECHENTYP),codelaenge,stdout);
557
558 return(codelaenge);
559 }
560
561 /*************************SPARSE6CODE*****************************/
562
563 int
sparse6code(PLANMAP map,FLAECHENTYP * code)564 sparse6code( PLANMAP map, FLAECHENTYP *code)
565 /* Make sparse6 code, including final '\n'. */
566 {
567 FLAECHENTYP *p;
568 int nb,i,j,lastj,x,k,r,rr,topbit;
569 int nv;
570 KANTE *merke, *lauf;
571
572 nv = map[0][0].name;
573
574 p = code;
575 *p++ = ':';
576
577 if (nv <= 62)
578 *p++ = 63 + nv;
579 else
580 {
581 *p++ = 63 + 63;
582 *p++ = 63 + 0;
583 *p++ = 63 + (nv >> 6);
584 *p++ = 63 + (nv & 0x3F);
585 }
586
587 for (i = nv-1, nb = 0; i != 0 ; i >>= 1, ++nb) {}
588 topbit = 1 << (nb-1);
589 k = 6;
590 x = 0;
591
592 lastj = 0;
593 for (j = 0; j < nv; ++j)
594 {
595 merke = lauf = map[j+1];
596 do
597 {
598 i = lauf->name - 1;
599 if (i <= j)
600 {
601 if (j == lastj)
602 {
603 x <<= 1;
604 if (--k == 0)
605 {
606 *p++ = 63 + x;
607 k = 6;
608 x = 0;
609 }
610 }
611 else
612 {
613 x = (x << 1) | 1;
614 if (--k == 0)
615 {
616 *p++ = 63 + x;
617 k = 6;
618 x = 0;
619 }
620 if (j > lastj+1)
621 {
622 for (r = 0, rr = j; r < nb; ++r, rr <<= 1)
623 {
624 if (rr & topbit) x = (x << 1) | 1;
625 else x <<= 1;
626 if (--k == 0)
627 {
628 *p++ = 63 + x;
629 k = 6;
630 x = 0;
631 }
632 }
633 x <<= 1;
634 if (--k == 0)
635 {
636 *p++ = 63 + x;
637 k = 6;
638 x = 0;
639 }
640 }
641 lastj = j;
642 }
643 for (r = 0, rr = i; r < nb; ++r, rr <<= 1)
644 {
645 if (rr & topbit) x = (x << 1) | 1;
646 else x <<= 1;
647 if (--k == 0)
648 {
649 *p++ = 63 + x;
650 k = 6;
651 x = 0;
652 }
653 }
654 }
655 lauf = lauf->next;
656 } while (lauf != merke);
657 }
658
659 if (k != 6) *p++ = 63 + ((x << k) | ((1 << k) - 1));
660
661 *p++ = '\n';
662 return p - code;
663 }
664
665 /*************************LONGCODE*****************************/
666
667 #define TWOBYTES(x) {codeF[zaehler]=(x)&0xFF; codeF[zaehler+1]=((x)>>8)&0xFF; zaehler += 2;}
668
longcode(PLANMAP map,FLAECHENTYP * codeF)669 int longcode( PLANMAP map, FLAECHENTYP *codeF )
670 {
671 /* Codiert die Einbettung in codeF und gibt die laenge des codes zurueck */
672 int i,zaehler;
673 KANTE *merke, *lauf;
674
675 if (map[0][0].name <= FL_MAX)
676 {
677 zaehler=1;
678 codeF[0]=map[0][0].name;
679 for(i=1;i<=map[0][0].name;i++)
680 { merke=map[i]; codeF[zaehler]=merke->name; zaehler++;
681 for(lauf=merke->next; lauf!=merke; lauf=lauf->next)
682 { codeF[zaehler]=lauf->name; zaehler++; }
683 codeF[zaehler]=0; zaehler++; }
684 }
685 else /* zu viele knoten fuer FLAECHENTYP */
686 {
687 zaehler=1;
688 codeF[0]=0;
689 TWOBYTES(map[0][0].name);
690 for(i=1;i<=map[0][0].name;i++)
691 { merke=map[i]; TWOBYTES(merke->name)
692 for(lauf=merke->next; lauf!=merke; lauf=lauf->next) TWOBYTES(lauf->name);
693 TWOBYTES(0);}
694 }
695 return(zaehler);
696 }
697
698
699
700 /*************************SPIRALCODE*******************************/
701
spiralcode(PLANMAP map,FLAECHENTYP code[12])702 BOOL spiralcode(PLANMAP map, FLAECHENTYP code[12])
703
704 /* berechnet irgendeinen Spiralcode von map und schreibt ihn in code.
705 Gibt 1 zurueck, wenn der gefunden wurde und 0 sonst. versucht zuerst
706 einen Code zu finden, der an einem 5-Eck startet. */
707
708 { int zaehler, i,j, mark, sixgons;
709 BOOL gefunden=0, hexgefunden=0;
710 FLAECHENTYP codeF[2*(81+8*S)];
711 FILE *fil2;
712 FLAECHENTYP dummycode[12];
713 FLAECHENTYP *dummy;
714 static int write_nopentaheader=1, write_nohexaheader=1;
715
716 /*schreibemap(map);*/
717
718 sixgons= (map[0][0].name - 20)/2;
719
720 for (i=1; i<=map[0][0].name; i++)
721 for (j=0; j<3; j++) { map[i][j].dummy=map[i][j].mininame=0; }
722 for (i=0; i<12; i++) code[i]=FL_MAX;
723
724
725 for (i=0; (i<60) && !gefunden; i++)
726 { gefunden= get_spiralcode ( F_eck_kanten[i], i, code, sixgons);
727 (F_eck_kanten[i])->mininame=1; }
728
729 mark=61;
730
731 for (i=0; (i<60) && !gefunden; i++)
732 { gefunden= get_spiralcode_inv ( F_eck_kanten[i], mark, code, sixgons);
733 mark++; }
734
735
736 if (!gefunden) { no_penta_spiral++;
737 zaehler=longcode(map,codeF);
738 fil2=fopen(no_penta_spiral_filename,"ab");
739 if (fil2==NULL) { fprintf(stderr,"Can't open %s\n",no_penta_spiral_filename);
740 exit(1); }
741 if (write_nopentaheader)
742 { write_nopentaheader=0;
743 fprintf(fil2,">>planar_code %ce<<", my_endianness);
744 }
745 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil2);
746 fclose(fil2);
747 }
748
749
750 if (!gefunden || hexspi)
751 {
752 if (!gefunden) dummy=code; else
753 { for (i=0; i<12; i++) dummycode[i]=FL_MAX; dummy=dummycode; }
754 for (i=1; (i<=map[0][0].name) && !hexgefunden; i++)
755 for (j=0; j<3 && !hexgefunden; j++)
756 if (!map[i][j].mininame)
757 { hexgefunden= get_spiralcode ( map[i]+j, mark, dummy, sixgons); mark++;
758 if (!hexgefunden)
759 { hexgefunden= get_spiralcode_inv ( map[i]+j, mark, dummy, sixgons); mark++; }
760 }
761 }
762
763 if (hexspi && !hexgefunden) { no_hexa_spiral++;
764 zaehler=longcode(map,codeF);
765 fil2=fopen(no_hexa_spiral_filename,"ab");
766 if (fil2==NULL) { fprintf(stderr,"Can't open %s\n",no_hexa_spiral_filename);
767 exit(1); }
768 if (write_nohexaheader)
769 { write_nohexaheader=0;
770 fprintf(fil2,">>planar_code %ce<<", my_endianness);
771 }
772 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil2);
773 fclose(fil2);
774 }
775
776
777
778 return(gefunden || hexgefunden);
779 }
780
781
782 /*************************MINSPIRALCODE*******************************/
783
minspiralcode(PLANMAP map,FLAECHENTYP code[12])784 BOOL minspiralcode(PLANMAP map, FLAECHENTYP code[12])
785
786 /* berechnet den minimalen Spiralcode von map und schreibt ihn in code.
787 Gibt 1 zurueck, wenn der gefunden wurde und 0 sonst. versucht zuerst
788 einen Code zu finden, der an einem 5-Eck startet. */
789
790 { int i,j, zaehler, mark, sixgons;
791 BOOL gefunden=0, hexgefunden=0;
792 FLAECHENTYP codeF[2*(81+8*S)];
793 FILE *fil2;
794 FLAECHENTYP dummycode[12];
795 FLAECHENTYP *dummy;
796 static int write_nopentaheader=1, write_nohexaheader=1;
797
798
799 /*schreibemap(map);*/
800
801 sixgons= (map[0][0].name - 20)/2;
802
803 for (i=1; i<=map[0][0].name; i++)
804 for (j=0; j<3; j++) { map[i][j].dummy=map[i][j].mininame=0; }
805 for (i=0; i<12; i++) code[i]=FL_MAX;
806
807
808
809 for (i=0; (i<60); i++)
810 { if (get_spiralcode ( F_eck_kanten[i], i, code, sixgons)) gefunden=1;
811 (F_eck_kanten[i])->mininame=1; }
812
813 mark=61;
814
815 for (i=0; (i<60); i++)
816 { if (get_spiralcode_inv ( F_eck_kanten[i], mark, code, sixgons)) gefunden=1;
817 mark++; }
818
819
820 if (!gefunden) { no_penta_spiral++;
821 zaehler=longcode(map,codeF);
822 fil2=fopen(no_penta_spiral_filename,"ab");
823 if (fil2==NULL) { fprintf(stderr,"Can't open %s\n",no_penta_spiral_filename);
824 exit(1); }
825 if (write_nopentaheader)
826 { write_nopentaheader=0;
827 fprintf(fil2,">>planar_code %ce<<", my_endianness);
828 }
829 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil2);
830 fclose(fil2);
831 }
832
833
834 if (!gefunden || hexspi) /* sonst waeren die neuen codes eh alle groesser */
835 {
836 if (!gefunden) dummy=code; else
837 { for (i=0; i<12; i++) dummycode[i]=FL_MAX; dummy=dummycode; }
838 for (i=1; (i<=map[0][0].name); i++)
839 for (j=0; j<3 ; j++)
840 if (!map[i][j].mininame)
841 { if (get_spiralcode ( map[i]+j, mark, dummy, sixgons)) hexgefunden=1; mark++;
842 if (get_spiralcode_inv ( map[i]+j, mark, dummy, sixgons)) hexgefunden=1; mark++;
843 }
844 }
845
846 if (hexspi && !hexgefunden) { no_hexa_spiral++;
847 zaehler=longcode(map,codeF);
848 fil2=fopen(no_hexa_spiral_filename,"ab");
849 if (fil2==NULL) { fprintf(stderr,"Can't open %s\n",no_hexa_spiral_filename);
850 exit(1); }
851 if (write_nohexaheader)
852 { write_nohexaheader=0;
853 fprintf(fil2,">>planar_code %ce<<", my_endianness);
854 }
855 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil2);
856 fclose(fil2);
857 }
858
859
860 return(gefunden || hexgefunden);
861 }
862
863
864
865 /*************************SPIRALSTATISTIC*******************************/
866
spiralstatistic(PLANMAP map)867 void spiralstatistic(PLANMAP map)
868
869 /* berechnet die Statistik, wieviele Spiralen es gibt */
870
871 { int zaehler=0, i,j, mark, sixgons;
872 FLAECHENTYP code[12];
873
874
875 /*schreibemap(map);*/
876
877 sixgons= (map[0][0].name - 20)/2;
878
879 for (i=1; i<=map[0][0].name; i++)
880 for (j=0; j<3; j++) { map[i][j].dummy=map[i][j].mininame=0; }
881 for (i=0; i<12; i++) code[i]=FL_MAX;
882
883 mark=1;
884
885 for (i=1; (i<=map[0][0].name); i++)
886 for (j=0; j<3; j++)
887 { code[0]=FL_MAX;
888 if (get_spiralcode ( map[i]+j, mark, code, sixgons)) zaehler++;
889 /*else fprintf(stderr,"no %d %d \n",i,map[i][j].name);*/
890 mark++;
891 code[0]=FL_MAX;
892 if (get_spiralcode_inv ( map[i]+j, mark, code, sixgons)) zaehler++;
893 /*else fprintf(stderr,"no inv %d %d \n",i,map[i][j].name); */
894 mark++;}
895
896 spiralnumbers[zaehler]++;
897
898 }
899
900
901 /*********************CODECMP_KN*****************************************/
902
codecmp_kn(KNOTENTYP * p1,KNOTENTYP * p2,int max)903 int codecmp_kn(KNOTENTYP *p1, KNOTENTYP *p2, int max)
904 {
905 max--;
906 while ((*p1==*p2) && max) { p1++; p2++; max--; }
907 return( (int)(*p1)-(int)(*p2) );
908 }
909
910 /*********************CODECMP*****************************************/
911
codecmp(FLAECHENTYP * p1,FLAECHENTYP * p2,int max)912 int codecmp(FLAECHENTYP *p1, FLAECHENTYP *p2, int max)
913 {
914 max--;
915 while ((*p1==*p2) && max) { p1++; p2++; max--; }
916 return( (int)(*p1)-(int)(*p2) );
917 }
918
919
920 /**************************IN_LISTE********************************/
921
in_liste(FLAECHENTYP * code,LISTENTRY * el)922 void in_liste(FLAECHENTYP *code, LISTENTRY *el)
923 /* schreibt code in die liste */
924 { int compare;
925 int n;
926
927
928 if (el->code[0]==0)
929 {
930 for (n=0; n<12; n++) (el->code)[n]= code[n];
931 el->smaller=(LISTENTRY *)malloc(sizeof(LISTENTRY));
932 (el->smaller->code)[0]=0;
933 el->larger=(LISTENTRY *)malloc(sizeof(LISTENTRY));
934 (el->larger->code)[0]=0;
935 if ((el->smaller==nil) || (el->larger==nil))
936 { fprintf(stderr,"Cannot allocate memory in \"in_liste\" \n");
937 exit(1); }
938 }
939
940 else {
941 compare=codecmp(code,el->code,12);
942 if (compare<0) in_liste(code,el->smaller);
943 else if (compare>0) in_liste(code,el->larger);
944 else { fprintf(stderr,"Dangerous error -- Two equal codes ! \n"); exit(2); }
945 }
946 }
947
948
949 /*********************AUSGABE***********************************/
950
ausgabe(LISTENTRY * liste,int knotenzahl,FLAECHENTYP ** lastcode)951 void ausgabe(LISTENTRY *liste,int knotenzahl,FLAECHENTYP **lastcode)
952
953 {
954 FLAECHENTYP i;
955
956 if ((liste->code)[0]==0) return;
957 ausgabe(liste->smaller,knotenzahl,lastcode);
958
959 for (i=0; (liste->code)[i]==(*lastcode)[i]; i++);
960 fwrite(&i,sizeof(FLAECHENTYP),1,fil[knotenzahl]);
961 fwrite((liste->code)+i,sizeof(FLAECHENTYP),12-i,fil[knotenzahl]);
962 *lastcode=liste->code;
963
964 ausgabe(liste->larger,knotenzahl,lastcode);
965 }
966
967 /********************LISTELEER********************************/
968
listeleer(LISTENTRY * liste)969 void listeleer(LISTENTRY *liste)
970 {
971 if ((liste->code)[0]==0) return;
972
973 listeleer(liste->smaller); free(liste->smaller);
974 listeleer(liste->larger); free(liste->larger);
975 }
976
977
978 /*************************CODIEREPLANAR*****************************/
979
codiereplanar(PLANMAP map)980 void codiereplanar( PLANMAP map )
981 {
982 /* Codiert die Einbettung, schreibt sie in das entsprechende file oder
983 auf stdout und gibt die laenge des codes zurueck */
984 int zaehler,knotenzahl;
985 FLAECHENTYP codeF[2*(81+8*S)];
986 FLAECHENTYP *codeFPZ, i;
987 static FLAECHENTYP dummycode[12]={UCHAR_MAX,UCHAR_MAX,UCHAR_MAX,0,0,0,0,0,0,0,0,0};
988 FILE *fil2;
989 BOOL test;
990 static int write_nospiheader=1;
991
992 knotenzahl=map[0][0].name;
993
994 if (spistat) spiralstatistic(map);
995
996 switch(codenumber)
997 {
998 case 0: {
999 if (spiralcheck)
1000 { test=spiralcode(map,codeF);
1001 if (!test)
1002 { zaehler=longcode(map,codeF);
1003 fil2=fopen(no_spiral_filename,"ab");
1004 if (fil2==NULL) { fprintf(stderr,"Can't open %s\n",no_spiral_filename);
1005 exit(1); }
1006 if (write_nospiheader)
1007 { write_nospiheader=0;
1008 fprintf(fil2,">>planar_code %ce<<", my_endianness);
1009 }
1010 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil2);
1011 fclose(fil2);
1012 }
1013 }
1014 break; }
1015 case 1: {
1016 if (spiralcheck)
1017 { test=spiralcode(map,codeF);
1018 if (!test)
1019 { zaehler=longcode(map,codeF);
1020 fil2=fopen(no_spiral_filename,"ab");
1021 if (fil2==NULL) { fprintf(stderr,"Can't open %s\n",no_spiral_filename);
1022 exit(1); }
1023 if (write_nospiheader)
1024 { write_nospiheader=0;
1025 fprintf(fil2,">>planar_code %ce<<", my_endianness);
1026 }
1027 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil2);
1028 fclose(fil2);
1029 }
1030 }
1031 zaehler=longcode(map,codeF);
1032 if (fil[knotenzahl]==stdout)
1033 { if (write_header_stdout)
1034 { write_header_stdout=0;
1035 fprintf(stdout,">>planar_code %ce<<", my_endianness);
1036 }
1037 }
1038 else
1039 { if (write_header_fil[knotenzahl])
1040 { write_header_fil[knotenzahl]=0;
1041 fprintf(fil[knotenzahl],">>planar_code %ce<<", my_endianness);
1042 }
1043 }
1044 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil[knotenzahl]);
1045 break; }
1046 case 2: { test=spiralcode(map,codeF);
1047 if (test) { for (i=0; codeF[i]==last_code[i]; i++);
1048 fwrite(&i,sizeof(FLAECHENTYP),1,fil[knotenzahl]);
1049 fwrite(codeF+i,sizeof(FLAECHENTYP),12-i,fil[knotenzahl]);
1050 for ( ; i<12; i++) last_code[i]=codeF[i];}
1051 else
1052 { zaehler=longcode(map,codeF);
1053 fil2=fopen(no_spiral_filename,"ab");
1054 if (fil2==NULL) { fprintf(stderr,"Can't open %s\n",no_spiral_filename);
1055 exit(1); }
1056 if (write_nospiheader)
1057 { write_nospiheader=0;
1058 fprintf(fil2,">>planar_code %ce<<", my_endianness);
1059 }
1060 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil2);
1061 fclose(fil2);
1062 }
1063 break; }
1064 case 3: {
1065 test=minspiralcode(map,codeF);
1066 if (test) { in_liste(codeF,codeliste+knotenzahl);
1067 if (graphenzahl[knotenzahl]%((long long int)listenlaenge)==0)
1068 {
1069 if (fil[knotenzahl]==stdout)
1070 codeFPZ = dummycode;
1071 else codeFPZ = *(lastcode[knotenzahl]);
1072 ausgabe(codeliste+(knotenzahl),knotenzahl,&codeFPZ);
1073 for (i=0; i<12; i++) (*(lastcode[knotenzahl]))[i]= codeFPZ[i];
1074 listeleer(codeliste+(knotenzahl));
1075 (codeliste[knotenzahl].code)[0]=0;
1076 }
1077 }
1078 else
1079 { zaehler=longcode(map,codeF);
1080 fil2=fopen(no_spiral_filename,"ab");
1081 if (fil2==NULL) { fprintf(stderr,"Can't open %s\n",no_spiral_filename);
1082 exit(1); }
1083 if (write_nospiheader)
1084 { write_nospiheader=0;
1085 fprintf(fil2,">>planar_code %ce<<", my_endianness);
1086 }
1087 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil2);
1088 fclose(fil2);
1089 }
1090 break; }
1091 case 4: {
1092 if (spiralcheck)
1093 { test=spiralcode(map,codeF);
1094 if (!test)
1095 { zaehler=longcode(map,codeF);
1096 fil2=fopen(no_spiral_filename,"ab");
1097 if (fil2==NULL) { fprintf(stderr,"Can't open %s\n",no_spiral_filename);
1098 exit(1); }
1099 if (write_nospiheader)
1100 { write_nospiheader=0;
1101 fprintf(fil2,">>planar_code %ce<<", my_endianness);
1102 }
1103 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil2);
1104 fclose(fil2);
1105 }
1106 }
1107 break; }
1108 case 5: {
1109 zaehler=longcode(map,codeF);
1110 if (fil[knotenzahl]==stdout)
1111 { if (write_header_stdout)
1112 { write_header_stdout=0;
1113 fprintf(stdout,">>planar_code %ce<<", my_endianness);
1114 }
1115 }
1116 else
1117 if (write_header_fil[knotenzahl])
1118 { write_header_fil[knotenzahl]=0;
1119 fprintf(fil[knotenzahl],">>planar_code %ce<<", my_endianness);
1120 }
1121 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil[knotenzahl]);
1122 test=spiralcode(map,codeF);
1123 if (!test)
1124 { zaehler=longcode(map,codeF);
1125 fil2=fopen(no_spiral_filename,"ab");
1126 if (fil2==NULL) { fprintf(stderr,"Can't open %s\n",no_spiral_filename);
1127 exit(1); }
1128 if (write_nospiheader)
1129 { write_nospiheader=0;
1130 fprintf(fil2,">>planar_code %ce<<", my_endianness);
1131 }
1132 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil2);
1133 fclose(fil2);
1134 }
1135 break; }
1136
1137 case 6: { vegacode(stdout,map);
1138 if (spiralcheck)
1139 { test=spiralcode(map,codeF);
1140 if (!test)
1141 { zaehler=longcode(map,codeF);
1142 fil2=fopen(no_spiral_filename,"ab");
1143 if (fil2==NULL) { fprintf(stderr,"Can't open %s\n",no_spiral_filename);
1144 exit(1); }
1145 if (write_nospiheader)
1146 { write_nospiheader=0;
1147 fprintf(fil2,">>planar_code %ce<<", my_endianness);
1148 }
1149 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil2);
1150 fclose(fil2);
1151 }
1152 }
1153 break; }
1154
1155 case 7: { dualcode(map);
1156 if (spiralcheck)
1157 { test=spiralcode(map,codeF);
1158 if (!test)
1159 { zaehler=longcode(map,codeF);
1160 fil2=fopen(no_spiral_filename,"ab");
1161 if (fil2==NULL) { fprintf(stderr,"Can't open %s\n",no_spiral_filename);
1162 exit(1); }
1163 if (write_nospiheader)
1164 { write_nospiheader=0;
1165 fprintf(fil2,">>planar_code %ce<<", my_endianness);
1166 }
1167 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil2);
1168 fclose(fil2);
1169 }
1170 }
1171 break; }
1172
1173 case 8: {
1174 if (spiralcheck)
1175 { test=spiralcode(map,codeF);
1176 if (!test)
1177 { zaehler=longcode(map,codeF);
1178 fil2=fopen(no_spiral_filename,"ab");
1179 if (fil2==NULL) { fprintf(stderr,"Can't open %s\n",no_spiral_filename);
1180 exit(1); }
1181 if (write_nospiheader)
1182 { write_nospiheader=0;
1183 fprintf(fil2,">>planar_code %ce<<", my_endianness);
1184 }
1185 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil2);
1186 fclose(fil2);
1187 }
1188 }
1189 zaehler=sparse6code(map,codeF);
1190 fwrite(codeF,sizeof(FLAECHENTYP),zaehler,fil[knotenzahl]);
1191 break; }
1192
1193 default: { fprintf(stderr,"Dangerous error in switch (codiereplanar) ! \n"); exit(3); }
1194 }
1195 }
1196
1197
1198
1199 /*******************INIT_MAP************************/
1200
init_map(PLANMAP map)1201 void init_map(PLANMAP map)
1202 {
1203 int i,j;
1204
1205 map[0][0].name=0;
1206
1207 for (i=1; i<=N; i++)
1208 {
1209 map[i][0].next= map[i]+1; map[i][0].prev= map[i]+2;
1210 map[i][1].next= map[i]+2; map[i][1].prev= map[i];
1211 map[i][2].next= map[i]; map[i][2].prev= map[i]+1;
1212
1213 for (j=0; j<3; j++)
1214 { map[i][j].ursprung=i;
1215 map[i][j].name=leer;
1216 map[i][j].invers=nil; }
1217 }
1218 }
1219
1220
1221 /********************BAUE_POLYGON*******************/
1222 /* Baut ein einzelnes leeres Polygon mit n Ecken (n>=3)
1223 und initialisiert map */
1224
baue_polygon(int n,PLANMAP map,KANTE ** marke)1225 void baue_polygon(int n, PLANMAP map, KANTE **marke )
1226 {
1227 int j;
1228
1229 if (n<3) { fprintf(stderr,"Error, no 2-gons allowed !\n"); return; }
1230
1231 /* sicherheitshalber erstmal loeschen und initialisieren */
1232
1233 init_map(map);
1234
1235 /* Immer: erster Eintrag zurueck, 2. nach aussen, dritter vor */
1236
1237 map[1][0].name=n; map[1][1].name=aussen; map[1][2].name=2;
1238 map[1][0].invers=map[n]+2; map[1][1].invers=nil; map[1][2].invers=map[2];
1239
1240 (*marke)=map[1]+1;
1241
1242 for (j=2; j<n; j++)
1243 {
1244 map[j][0].name=j-1; map[j][1].name=aussen; map[j][2].name=j+1;
1245 map[j][0].invers=map[j-1]+2; map[j][1].invers=nil; map[j][2].invers=map[j+1];
1246 }
1247
1248 map[n][0].name=n-1; map[n][1].name=aussen; map[n][2].name=1;
1249 map[n][0].invers=map[n-1]+2; map[n][1].invers=nil; map[n][2].invers=map[1];
1250
1251 map[0][0].name=n;
1252
1253 }
1254
1255 /**********************CHECKSIZE_RIGHT**************************************/
1256
1257 /* bestimmt die groesse der flaeche rechts von edge -- ist da keine gibt's Probleme */
1258
checksize_right(KANTE * edge)1259 int checksize_right( KANTE* edge)
1260 {
1261 KANTE *run;
1262 int zaehler=1;
1263
1264 for (run=edge->invers->prev; run != edge; run=run->invers->prev) zaehler++;
1265 return(zaehler);
1266 }
1267
1268
1269
1270
1271 /*********************ADD_POLYGON***********************************/
1272
add_polygon(int n,PLANMAP map,KANTE * start,KANTE ** lastout)1273 void add_polygon(int n, PLANMAP map, KANTE *start, KANTE **lastout)
1274 /* fuegt ein weiteres polygon einer Reihe an. Dabei ist n die groesse des polygons.
1275 Angefuegt wird immer an start. Die Marke wird nicht versetzt. Ueber lastout wird
1276 die letzte Aussenkante des Polygons zurueckgegeben. */
1277
1278
1279 {
1280 int new_tempknz, tempknz;
1281 KANTE *ende;
1282 int common_vertices;
1283
1284
1285 if (IPR && (n==5))
1286 {
1287 if (checksize_right(start->next)==5) is_ipr=0;
1288 for (ende=start->next->invers->next, common_vertices=2; ende->name != aussen;
1289 ende=ende->invers->next) { if (checksize_right(ende)==5) is_ipr=0;
1290 common_vertices++;
1291 }
1292 }
1293 else for (ende=start->next->invers->next, common_vertices=2; ende->name != aussen;
1294 ende=ende->invers->next) common_vertices++;
1295
1296
1297 if (n<common_vertices)
1298 { fprintf(stderr,"polygon to insert too small !\n");
1299 exit(4); }
1300
1301 /* es muessen also n-common_vertices knoten hinzugefuegt werden */
1302
1303 tempknz=map[0][0].name;
1304 new_tempknz=tempknz+n-common_vertices;
1305
1306 if (n-common_vertices==0) /* dann kommt kein knoten dazu */
1307 { start->name=ende->ursprung; start->invers=ende;
1308 ende->name=start->ursprung; ende->invers=start;
1309 *lastout=nil;
1310 return;
1311 }
1312
1313 if (n-common_vertices==1) /* dann kommt nur ein knoten dazu */
1314 {
1315 tempknz++;
1316 start->name=tempknz; start->invers=map[tempknz];
1317 map[tempknz][0].name=start->ursprung; map[tempknz][0].invers=start;
1318 map[tempknz][1].name=aussen; map[tempknz][1].invers=nil;
1319 map[tempknz][2].name=ende->ursprung; map[tempknz][2].invers=ende;
1320 ende->name=tempknz; ende->invers=map[tempknz]+2;
1321 *lastout=map[tempknz]+1;
1322 map[0][0].name=tempknz;
1323 return;
1324 }
1325
1326
1327 /* es bleibt: mindestens zwei neue knoten */
1328
1329 tempknz++;
1330 start->name=tempknz; start->invers=map[tempknz];
1331 map[tempknz][0].name=start->ursprung; map[tempknz][0].invers=start;
1332 map[tempknz][1].name=aussen; map[tempknz][1].invers=nil;
1333 map[tempknz][2].name=tempknz+1; map[tempknz][2].invers=map[tempknz+1];
1334
1335 for (tempknz++; tempknz<new_tempknz; tempknz++)
1336 { map[tempknz][0].name=tempknz-1; map[tempknz][0].invers=map[tempknz-1]+2;
1337 map[tempknz][1].name=aussen; map[tempknz][1].invers=nil;
1338 map[tempknz][2].name=tempknz+1; map[tempknz][2].invers=map[tempknz+1]; }
1339
1340 /* und nun noch den letzten knoten */
1341 map[tempknz][0].name=tempknz-1; map[tempknz][0].invers=map[tempknz-1]+2;
1342 map[tempknz][1].name=aussen; map[tempknz][1].invers=nil;
1343 map[tempknz][2].name=ende->ursprung; map[tempknz][2].invers= ende;
1344 ende->name=tempknz; ende->invers=map[tempknz]+2;
1345 *lastout=map[tempknz]+1;
1346 map[0][0].name=tempknz;
1347 }
1348
1349
1350 /**********************SEQUENZ_KANONISCH***********************************/
1351
sequenz_kanonisch(int sequenz[])1352 int sequenz_kanonisch( int sequenz[] )
1353 /* checkt, ob eine sequenz kanonisch ist, gibt 1 zurueck wenn ja, 0 sonst */
1354
1355 { int i,j, laenge, max;
1356 int longseq[14];
1357
1358
1359 max=sequenz[0]; j=1; /* j hier nur als merker */
1360 for (i=0; sequenz[i] != leer; i++) { longseq[i]=sequenz[i];
1361 if (longseq[i]==max) j=0;
1362 else if (longseq[i]>max) { return(0); }
1363 }
1364 if (j) return(1); /* der erste ist eindeutig, also die ganze sequenz */
1365
1366 laenge=i;
1367 for (j=0; j<laenge; i++, j++) longseq[i]=sequenz[j];
1368
1369 for (j=1; j<laenge; i++, j++)
1370 if (longseq[j]==max)
1371 { for (i=1; (i<laenge) && (longseq[j+i]==sequenz[i]) ; i++);
1372 if (longseq[j+i]>sequenz[i])
1373 { return(0); }
1374 }
1375 return(1);
1376 }
1377
1378
1379
1380 /***********************BERECHNE_SEQUENZ********************************/
1381
berechne_sequenz(SEQUENZ * sq,SEQUENZ altsq,int start,int f_ecke)1382 void berechne_sequenz(SEQUENZ *sq, SEQUENZ altsq, int start,int f_ecke)
1383 /* berechnet die neue sequenz startend bei der Kante start */
1384 /* geht fest davon aus, dass 2 mal nach innen hintereinander nicht vorkommt */
1385 /* zwei der Kanten-Eintraege koennen noch nicht belegt werden (die ersten beiden) */
1386 /* start ist der laufindex */
1387 {
1388 int i, j, k, laenge,alt_laenge;
1389 int *sequenz;
1390 int puffer[13];
1391 char *kan;
1392 KANTE **sqkanten;
1393 KANTE *kpuffer[13];
1394
1395
1396 sequenz=sq->sequenz;
1397 kan=sq->k_marks;
1398 sqkanten=sq->kanten;
1399
1400 alt_laenge=altsq.laenge;
1401 sq->laenge= alt_laenge-f_ecke;
1402 laenge=sq->laenge;
1403
1404 for (i=0; i<alt_laenge; i++) { puffer[i]=puffer[i+alt_laenge]=altsq.sequenz[i];
1405 kpuffer[i]=kpuffer[i+alt_laenge]=altsq.kanten[i]; }
1406
1407 if (puffer[start]==0) { fprintf(stderr,"Berechne_sequenz should not be called for 0-gaps ! \n");
1408 exit(5); }
1409
1410 if (f_ecke==0)
1411 { if (laenge==1) sequenz[0]=puffer[0]+1;
1412 else
1413 if (laenge==2)
1414 { if (puffer[start]>1) { sequenz[0]=puffer[start]-1; sequenz[1]=puffer[start+1]+2; }
1415 else { sequenz[1]=0; sequenz[0]=puffer[start+1]+2; }
1416 }
1417 else /* d.h. laenge > 2 */
1418 { if (puffer[start]>1)
1419 {
1420 sequenz[0]= puffer[start]-1;
1421 sequenz[1]= puffer[start+1]+1;
1422 sequenz[laenge-1]=puffer[start+laenge-1]+1;
1423 sqkanten[laenge-1]=kpuffer[start+laenge-1];
1424 for (j=2; j<laenge-1; j++) { sequenz[j]=puffer[start+j];
1425 sqkanten[j]=kpuffer[start+j]; }
1426 }
1427 else /* d.h. die luecke hat laenge 1 */
1428 {
1429 sequenz[laenge-1]= 0;
1430 sequenz[0]= puffer[start+1]+1;
1431 sequenz[laenge-2]=puffer[start+laenge-1]+1;
1432 sqkanten[laenge-2]=kpuffer[start+laenge-1];
1433 for (j=1; j<laenge-2; j++) { sequenz[j]=puffer[start+j+1];
1434 sqkanten[j]=kpuffer[start+j+1]; }
1435 }
1436 } /* ende laenge > 2 */
1437 } /* ende 0 Fuenfecke */
1438
1439 else
1440 if (f_ecke==1)
1441 { if (laenge==0) sequenz[0]=puffer[0]+1;
1442 else
1443 if (laenge==1) sequenz[0]=puffer[0]+puffer[1]+1;
1444 else
1445 if (laenge==2)
1446 { sequenz[0]=puffer[start] + puffer[start+1]; sequenz[1]=puffer[start+2]+1;
1447 sqkanten[1]=kpuffer[start+2];}
1448 else /* d.h. laenge > 2 */
1449 { sequenz[0]= puffer[start]+puffer[start+1];
1450 sequenz[laenge-1]=puffer[start+laenge]+1;
1451 sqkanten[laenge-1]=kpuffer[start+laenge];
1452 for (j=1; j<laenge-1; j++) { sequenz[j]=puffer[start+j+1];
1453 sqkanten[j]=kpuffer[start+j+1]; }
1454 }
1455 } /* ende 1 Fuenfecke */
1456
1457 else /* d.h. f_ecke==2 */
1458 { if (laenge==0) sequenz[0]=puffer[0]+puffer[1]+1;
1459 else { fprintf(stderr,"ERROR: Two 5-gons not leading to 0-Sequence !\n");
1460 exit(6); }
1461 } /* ende 2 Fuenfecke */
1462
1463 if (sequenz[0]==0) /* nur im Fall eines einzelnen 6-Ecks moeglich */
1464 { puffer[0]=sequenz[0];
1465 for (i=0; i<laenge-1; i++) sequenz[i]=sequenz[i+1]; sequenz[laenge-1]=puffer[0];
1466 for (i=1; i<laenge-1; i++) sqkanten[i]=sqkanten[i+1]; }
1467
1468
1469
1470 if (laenge==0) { sequenz[1]=leer; kan[0]=1; return; }
1471
1472 sequenz[laenge]=leer;
1473
1474 kan[0]=sequenz_kanonisch(sequenz);
1475
1476 for (i=1; i < laenge; i++)
1477 { for (j=i, k=0; j<laenge; j++, k++) puffer[k]=sequenz[j];
1478 for (j=0; j<i; j++, k++) puffer[k]=sequenz[j];
1479 puffer[k]=leer;
1480 kan[i]=sequenz_kanonisch(puffer);
1481 }
1482
1483 }
1484
1485
1486
1487
1488
1489
1490 /***********************BELEGE_SEQUENZ********************************/
1491
belege_sequenz(KANTE * start,SEQUENZ * sq)1492 void belege_sequenz( KANTE *start, SEQUENZ *sq)
1493 /* belegt die sequenz startend bei der Kante start */
1494 /* geht fest davon aus, dass 2 mal nach innen hintereinander nicht vorkommt */
1495
1496 {
1497 int i, j, k, zaehler, position;
1498 KANTE *run;
1499 int *sequenz;
1500 KANTE **seqkanten;
1501 int puffer[7];
1502 char *kan;
1503
1504
1505 sequenz=sq->sequenz;
1506 seqkanten=sq->kanten;
1507 kan=sq->k_marks;
1508
1509
1510 if (start->next->invers->next->name == aussen)
1511 { fprintf(stderr,"Achtung -- naechste Kante nicht nach innen -- FEHLER !\n");
1512 exit(7); }
1513
1514 for (i=0; i<7; i++) { sequenz[i]=leer; seqkanten[i]=nil; kan[i]=0;}
1515
1516 if (start->prev->invers->prev->name != aussen) /* d.h. vorige Kante nicht nach aussen, also nur
1517 Randlaenge zu bestimmen */
1518 { sq->laenge=0;
1519 for (run=start->next->invers->next->invers->next, zaehler=1; run != start;
1520 run=run->next->invers->next->invers->next) zaehler++;
1521 sequenz[0]=zaehler;
1522 seqkanten[0]=start;
1523 return;
1524 }
1525
1526 sq->laenge=0;
1527 zaehler=1;
1528 position=0;
1529 seqkanten[0]=start;
1530
1531
1532 for (run=start->next->invers->next->invers->next; run->next->invers->next->name < aussen;
1533 run=run->next->invers->next->invers->next) zaehler++;
1534 sequenz[0]=zaehler; position=1;
1535 if (run->next->invers->next != start) seqkanten[position]=run->next->invers->next;
1536 for (run=run->next->invers->next; run->next->invers->next->name >= aussen;
1537 run=run->next->invers->next)
1538 { sequenz[position]=0; position++;
1539 if (run->next->invers->next != start) seqkanten[position]=run->next->invers->next; }
1540 /* naechste Kante vor nicht-0-sequenz suchen */
1541
1542
1543 while (run != start)
1544 {
1545 for (zaehler=0; run->next->invers->next->name < aussen;
1546 run=run->next->invers->next->invers->next) zaehler++;
1547 sequenz[position]=zaehler; position++;
1548 if (run->next->invers->next != start) seqkanten[position]=run->next->invers->next;
1549 for (run=run->next->invers->next; run->next->invers->next->name >= aussen;
1550 run=run->next->invers->next) { sequenz[position]=0; position++;
1551 if (run->next->invers->next != start) seqkanten[position]=run->next->invers->next; }
1552
1553 }
1554
1555 sequenz[position]=leer; seqkanten[position]=nil;
1556 sq->laenge=position;
1557
1558 kan[0]=sequenz_kanonisch(sequenz);
1559
1560 for (i=1; sequenz[i] != leer; i++)
1561 { for (j=i, k=0; sequenz[j]!=leer; j++, k++) puffer[k]=sequenz[j];
1562 for (j=0; j<i; j++, k++) puffer[k]=sequenz[j];
1563 puffer[k]=leer;
1564 kan[i]=sequenz_kanonisch(puffer);
1565 }
1566
1567
1568
1569 }
1570
1571
1572 /**********************CHECKSIZE**************************************/
1573
1574 /* bestimmt die groesse der flaeche links von edge -- ist da keine gibt's Probleme */
1575
checksize(KANTE * edge)1576 int checksize(KANTE* edge)
1577 {
1578 KANTE *run;
1579 int zaehler=1;
1580
1581 for (run=edge->invers->next; run != edge; run=run->invers->next) zaehler++;
1582 return(zaehler);
1583 }
1584
1585
1586
1587 /*************************CODIERE***************************************/
1588 /* speziell fuer diese Flaechenstuecke. Sie werden ab der Marke von aussen
1589 in eine "Spirale" entwickelt. Die Eindeutigkeit ergibt sich nur zusammen
1590 mit der Sequenz. der "code" sind die stellen, an denen 5-Ecke vorkommen
1591
1592 Ein mieser sonderfall sind die 0-sequenzen. da kann nicht einfach nur abgewickelt
1593 werden. Die Codierung ist dort: erst die Anzahl der 6-Eck Schichten, dann die
1594 Anzahl der Spitzen, die man gegen den Uhrzeigersinn zurueckgehen muss, um ein
1595 5-Eck zu finden und dann erst kann normal fortgefahren werden. Die schichten werden
1596 spiralfoermig abgebaut.
1597
1598 laenge !=0 gilt nur fuer diese Situation. Dann ist laenge die anzahl der
1599 aussenkanten auf dem rand.
1600
1601 Im Falle von 6 Pentagonen wird 1 zurueckgegeben, wenn der entwickelte Code
1602 kleinstmoeglich ist und 0 sonst.
1603
1604 Fuer den miesen sonderfall wird der code aber (in der aufrufroutine) zum wegspeichern
1605 so geaendert, dass die zweite stelle immer die anzahl N der verschiedenen markierten
1606 Pflasterungen ist. die koennen dann erzeugt werden, indem 0 bis N Schritte zum ersten
1607 5-Eck zurueckgegangen wird bei der Rekonstruktion.
1608
1609 Die Anzahl der 6-Eck-Ringe ist immer 0 beim Aufruf.
1610
1611 */
1612
1613
codiere(PLANMAP map,FLAECHENTYP * code,KANTE * start,int codesize,int laenge)1614 int codiere(PLANMAP map, FLAECHENTYP *code, KANTE *start, int codesize, int laenge)
1615 {
1616 int i, j, stelle, zaehler, knotenzahl, flaechennumber, verschiebung, merkeknoten;
1617 /* zaehler zaehlt die Flaechengroesse, knotenzahl die zahl der restlichen knoten */
1618 int tempknz, laufzaehler, autozaehler, minitest;
1619 KANTE *run, *merke, *run2;
1620 FLAECHENTYP testcode[9];
1621
1622
1623 if (start->name != aussen) { fprintf(stderr,"Codiere must start at external edge !\n");
1624 exit(8); }
1625
1626 tempknz=map[0][0].name;
1627
1628 if (tempknz==5) { code[0]=1; return(1); }
1629
1630 for (i=1; i<=tempknz; i++) for (j=0; j<3; j++)
1631 if (map[i][j].name == aussen) map[i][j].dummy= infty; else map[i][j].dummy=0;
1632
1633 run=start; stelle=0; knotenzahl=tempknz;
1634
1635 if (laenge) /* d.h. 6-Fuenfecke-patch */
1636 { verschiebung=0;
1637 code[2]=unbelegt;
1638 code[0]=0; /*code[1]=verschiebung;*/ stelle=2;
1639 merkeknoten=knotenzahl;
1640 laufzaehler=1;
1641 /* Jetzt den minimalen Code ausrechnen: */
1642 for ( autozaehler=0, run2=start->prev;
1643 (verschiebung<laenge) && !autozaehler; verschiebung++, run2=run2->prev->invers->next->invers)
1644 if (checksize(run2)==5)
1645 {
1646 laufzaehler++;
1647 run=run2->next;
1648 stelle=2; knotenzahl=merkeknoten;
1649 flaechennumber=0;
1650 while (stelle<codesize)
1651 { flaechennumber++;
1652 zaehler=2;
1653 while (run->prev->invers->prev->dummy>=laufzaehler)
1654 run=run->prev->invers->prev; /* sicherstellen, dass davor
1655 keine aussenkanten sind */
1656 run->prev->invers->dummy=laufzaehler; run->next->invers->dummy=laufzaehler;
1657 run=run->next->invers->next; knotenzahl--;
1658 while (run->dummy>=laufzaehler)
1659 { zaehler++; knotenzahl--; run->prev->invers->dummy=laufzaehler;
1660 run->next->invers->dummy=laufzaehler;
1661 run=run->next->invers->next; }
1662 merke=run->next;
1663 run=run->prev;
1664 while (merke->dummy<laufzaehler)
1665 { zaehler++; merke=merke->invers->prev; }
1666 if (zaehler==5) { testcode[stelle]=flaechennumber; stelle++; }
1667 else if (zaehler!=6) { fprintf(stderr,"ERROR in CODIERE: No 5- or 6-Gon !\n"); exit(9); }
1668 if (knotenzahl==5) { testcode[stelle]=flaechennumber+1; stelle++; }
1669 } /* ende while */
1670 if ((minitest=codecmp(code+2,testcode+2,6))>0)
1671 { if (verschiebung) return(0);
1672 else { for (stelle=2; stelle<8; stelle++) code[stelle]=testcode[stelle]; }
1673 }
1674 if (minitest==0) autozaehler=1; /* verschiebung>=1 ist automatisch */
1675 } /* ende checksize==5 */
1676 if (autozaehler) code[1]=verschiebung-1;
1677 else code[1]=laenge;
1678 return(1);
1679 } /* ende if */
1680
1681
1682
1683 flaechennumber=0;
1684
1685
1686
1687 while (stelle<codesize)
1688 { flaechennumber++;
1689 zaehler=2;
1690 while (run->prev->invers->prev->dummy) run=run->prev->invers->prev; /* sicherstellen, dass davor
1691 keine aussenkanten sind */
1692 run->prev->invers->dummy=1; run->next->invers->dummy=1;
1693 run=run->next->invers->next; knotenzahl--;
1694 while (run->dummy)
1695 { zaehler++; knotenzahl--; run->prev->invers->dummy=1; run->next->invers->dummy=1;
1696 run=run->next->invers->next; }
1697 merke=run->next;
1698 run=run->prev;
1699 while (!(merke->dummy))
1700 { zaehler++; merke=merke->invers->prev; }
1701 if (zaehler==5) { code[stelle]=flaechennumber; stelle++; }
1702 else if (zaehler!=6) { fprintf(stderr,"ERROR in CODIERE(2): No 5- or 6-Gon !\n"); exit(10); }
1703 if (knotenzahl==5) { code[stelle]=flaechennumber+1; stelle++; }
1704 } /* ende while */
1705
1706 return(1);
1707
1708 }
1709
1710
1711
1712 /***********************BBITEMALLOC********************************************/
1713
bbitemalloc()1714 BBITEMLISTE *bbitemalloc()
1715 /* gibt immer die Adresse eines neuen bbitems zurueck */
1716 {
1717 static BBITEMLISTE *back=nil; /* back enthaelt immer den letzten, der zurueckgegeben
1718 wurde -- erst hochsetzen -- wichtig */
1719 static BBITEMLISTE *last=nil;
1720
1721 if (back==last) { back=(BBITEMLISTE *)malloc(sizeof(BBITEMLISTE)*1001);
1722 if (back==NULL) { fprintf(stderr,"Can not get more memory for bbitems"); exit(11); }
1723 last=back+1000;
1724 return(back); }
1725
1726 /* else */
1727 back++;
1728 return(back);
1729 }
1730
1731
1732 /***********************ITEMALLOC********************************************/
1733
itemalloc()1734 ITEMLISTE *itemalloc()
1735 /* gibt immer die Adresse eines neuen items zurueck */
1736 {
1737 static ITEMLISTE *back=nil; /* back enthaelt immer den letzten, der zurueckgegeben
1738 wurde -- erst hochsetzen -- wichtig */
1739 static ITEMLISTE *last=nil;
1740
1741 if (back==last) { back=(ITEMLISTE *)malloc(sizeof(ITEMLISTE)*1001);
1742 if (back==NULL) { fprintf(stderr,"Can not get more memory for items"); exit(12); }
1743 last=back+1000;
1744 return(back); }
1745
1746 /* else */
1747 back++;
1748 return(back);
1749 }
1750
1751
1752 /*******************PUT_IN_LISTE***********************************************/
1753
put_in_liste(int sechsecke,SEQUENZ sq,FLAECHENTYP * code,int codesize)1754 void put_in_liste(int sechsecke, SEQUENZ sq, FLAECHENTYP *code, int codesize )
1755 {
1756
1757 ITEMLISTE *item;
1758 SEQUENZLISTE *anfang;
1759 SEQUENZLISTE **puffer;
1760 int i,j, s_eintrag;
1761
1762 /*schreibesequenz(sq);*/
1763 /*schreibelistitems();*/
1764
1765 anfang=mapliste.sechser[sechsecke];
1766 mapliste.total_maps++;
1767 for (i=0; i<sq.laenge; i++)
1768 { s_eintrag=sq.sequenz[i];
1769 if (anfang->number_next <= s_eintrag)
1770 { puffer=anfang->next_level;
1771 anfang->next_level=(SEQUENZLISTE **)malloc((s_eintrag+1)*sizeof(SEQUENZLISTE *));
1772 if (anfang->next_level==NULL) { fprintf(stderr,"Can not get more memory"); exit(13); }
1773 for (j=0; j< anfang->number_next; j++) anfang->next_level[j]=puffer[j];
1774 for ( ; j <= s_eintrag; j++) anfang->next_level[j]=nil;
1775 anfang->number_next=s_eintrag+1;
1776 free(puffer);
1777 }
1778 if (anfang->next_level[s_eintrag]==nil)
1779 { anfang->next_level[s_eintrag]=(SEQUENZLISTE *)malloc(sizeof(SEQUENZLISTE));
1780 if (anfang->next_level[s_eintrag]==NULL) { fprintf(stderr,"Can not get more memory"); exit(14); }
1781 anfang=anfang->next_level[s_eintrag];
1782 anfang->next_level=nil; anfang->number_next=0;
1783 anfang->items=anfang->last_item=nil;
1784 }
1785 else anfang=anfang->next_level[s_eintrag];
1786 } /* ende for */
1787
1788 /* jetzt muesste anfang passend stehen zum Eintragen des Codes */
1789
1790 if (anfang->items==nil) item=anfang->items=anfang->last_item=itemalloc();
1791 else { item=anfang->last_item->next_item=itemalloc();
1792 anfang->last_item=item; }
1793 item->next_item=nil;
1794 for (j=0; j<codesize; j++) item->code[j]=code[j];
1795 }
1796
1797
1798 /*******************PUT_IN_BB_LISTE***********************************************/
1799
put_in_bb_liste(int sechsecke,SEQUENZ sq,FLAECHENTYP * code)1800 void put_in_bb_liste(int sechsecke, SEQUENZ sq, FLAECHENTYP *code)
1801 {
1802
1803 BBITEMLISTE *item, **puffer, *merke;
1804 BBSEQUENZLISTE *anfang;
1805 int j, s_eintrag;
1806
1807 /*schreibesequenz(sq);*/
1808 /*schreibelistitems();*/
1809
1810
1811
1812 anfang=bbliste.sechser[sechsecke];
1813 s_eintrag=sq.sequenz[0];
1814 if (anfang->number_next <= s_eintrag)
1815 { puffer=anfang->items;
1816 anfang->items=(BBITEMLISTE **)malloc((s_eintrag+1)*sizeof(BBITEMLISTE *));
1817 if (anfang->items==NULL) { fprintf(stderr,"Can not get more memory"); exit(15); }
1818 for (j=0; j< anfang->number_next; j++) { anfang->items[j]=puffer[j]; }
1819 for ( ; j <= s_eintrag; j++) { anfang->items[j]=nil; }
1820 anfang->number_next=s_eintrag+1;
1821 free(puffer);
1822 }
1823
1824 bbliste.total_items++;
1825 bbliste.total_maps += code[1];
1826
1827 if (anfang->items[s_eintrag]==nil) { item=anfang->items[s_eintrag]=bbitemalloc();
1828 item->next_item=nil; }
1829 else { merke=anfang->items[s_eintrag];
1830 item=anfang->items[s_eintrag]=bbitemalloc();
1831 item->next_item=merke; }
1832 if (item==NULL) { fprintf(stderr,"Can not get more memory"); exit(16); }
1833 for (j=0; j<8; j++) item->code[j]=code[j];
1834
1835 }
1836
1837
1838
1839
1840 /************************SCHREIBE_AUF************************************/
1841
schreibe_auf(PLANMAP map,SEQUENZ sq,int rest_sechsecke)1842 void schreibe_auf(PLANMAP map, SEQUENZ sq, int rest_sechsecke)
1843 /* codiert und schreibt eine markierte Pflasterung -- wird nur fuer
1844 bis zu 5 Fuenfecken aufgerufen */
1845 {
1846 int fuenfecke, sechsecke, i, codesize, pfadlaenge, non_nuller;
1847 FLAECHENTYP code[9];
1848
1849
1850 if ( !(do_sandwich || do_brille) ) return;
1851 if (IPR && (!is_ipr)) return;
1852
1853 fuenfecke=6-sq.laenge;
1854
1855 if (fuenfecke < 2) return; /* die werden bei der konstruktion nie gebraucht */
1856 for (i=non_nuller=0; i< sq.laenge; i++) if (sq.sequenz[i] != 0) non_nuller++;
1857 if (non_nuller >2) return; /* Bei jedem Patch der GEBRAUCHT wird, koennen nur
1858 an 2 Stellen Probleme auftreten */
1859
1860
1861 pfadlaenge=sq.laenge;
1862 for (i=0; i< sq.laenge; i++) pfadlaenge += (2*sq.sequenz[i]);
1863
1864 switch (fuenfecke)
1865 {
1866 case 5: { brillenglasmark[pfadlaenge]=1;
1867 break; }
1868
1869 case 4: { zwei_3_4_mark[pfadlaenge]=1;
1870 if (sq.sequenz[1]==0) /* dann kann es auch ein brillenglas sein */
1871 brillenglasmark[pfadlaenge]=1;
1872 break; }
1873 default: { zwei_3_4_mark[pfadlaenge]=1; }
1874 }
1875
1876 sechsecke=(map[0][0].name)-10+sq.laenge-sq.sequenz[0];
1877 for (i=1; i<sq.laenge; i++) sechsecke -= sq.sequenz[i];
1878 sechsecke=sechsecke/2; /* alles leicht aus Euler Formel */
1879
1880
1881 if (sechsecke+rest_sechsecke != max_sechsecke) { fprintf(stderr,"Error in 6-gon calculation (schreibe_auf) !\n");
1882 exit(17); }
1883
1884 codesize=fuenfecke;
1885 codiere(map, code, sq.kanten[0], fuenfecke,0);
1886
1887 put_in_liste(sechsecke, sq, code, codesize );
1888
1889 return;
1890 }
1891
1892 /*************************CHECK_MARK_UND_SCHREIBE***************************/
1893
1894 /* Ueberprueft, ob eine Einbettung mit 6 5-Ecken, also ohne
1895 Doppelte Aussenkanten, neu ist. Wenn ja, codiert und speichert sie die Einbettung
1896 und alle sich daraus durch hinzufuegen von 6-Eck-Ringen ergebenden */
1897
check_mark_und_schreibe(PLANMAP map,KANTE * first,int laenge,int rest_sechsecke)1898 void check_mark_und_schreibe(PLANMAP map, KANTE *first, int laenge, int rest_sechsecke)
1899 {
1900
1901
1902 SEQUENZ localsq;
1903 int sechsecke;
1904 FLAECHENTYP code[8];
1905
1906 if (!do_bauchbinde) return;
1907 if (IPR && (!is_ipr)) return;
1908
1909 localsq.laenge=0; localsq.sequenz[0]=laenge;
1910 localsq.kanten[0]=first;
1911
1912 sechsecke=((map[0][0].name)-10-laenge)/2;
1913 /* leicht aus Euler Formel */
1914
1915 if (sechsecke+rest_sechsecke != max_sechsecke)
1916 { fprintf(stderr,"Error in 6-gon calculation (check_mark_und_schreibe) !\n");
1917 exit(18); }
1918
1919 if (!codiere(map, code, first, 8, laenge)) return; /* nicht kanonisch */
1920 if (code[0] !=0) { fprintf(stderr," there was a hexagon ring.......\n"); exit(19); }
1921 put_in_bb_liste(sechsecke, localsq, code);
1922
1923 bblmark[laenge]=1;
1924
1925 /* neue ringe hinzufuegen */
1926 while (rest_sechsecke >= laenge)
1927 {
1928 rest_sechsecke -= laenge;
1929 sechsecke+= laenge;
1930 (code[0])++;
1931 put_in_bb_liste(sechsecke, localsq, code);
1932 }
1933
1934 return;
1935
1936 }
1937
1938
1939 /***************************BAUE_AUF**************************************/
1940
1941 /* die eigentliche konstruktionsroutine -- legt auf alle moeglichen arten eine
1942 neue reihe an */
1943
baue_auf(PLANMAP map,SEQUENZ sq,int sechsecke)1944 void baue_auf(PLANMAP map, SEQUENZ sq, int sechsecke)
1945 {
1946
1947 SEQUENZ localseq;
1948 int j, i, laenge;
1949 KANTE *naechste, *nextmark, *run;
1950 int anzahl, naechste_stelle, sql;
1951
1952
1953 if (IPR && (!is_ipr)) return;
1954
1955 sql=sq.laenge;
1956
1957 if (sql >=2)
1958 {
1959 for (i=0; i<sql && ((i==0) || !((sq.k_marks)[i])); i++)
1960 /* Schleife ueber alle moeglichen Startpunkte */
1961 {
1962 laenge=sq.sequenz[i];
1963 if (i==sql-1) naechste_stelle=0; else naechste_stelle=i+1;
1964 if (laenge==0)
1965 {
1966 /* da nie eine 0 am anfang einer kanonischen Sequenz stehen kann, kann die erste einer
1967 doppel-0 nie am ende stehen, also: */
1968 if ( (i<sql-1) && (sq.sequenz[i+1]==0) )
1969 {
1970 if (sechsecke >= 1)
1971 {
1972 naechste=sq.kanten[i];
1973 { add_polygon(6,map,naechste,&naechste); nextmark=naechste; }
1974 belege_sequenz(nextmark,&localseq);
1975 if (localseq.k_marks[0])
1976 { schreibe_auf(map,localseq,sechsecke-1);
1977 baue_auf(map, localseq, sechsecke-1); }
1978 /* aufraeumen: */
1979 (map[0][0].name) = (map[0][0].name) - 4;
1980 run=sq.kanten[i]; run->name=aussen; run->invers=nil;
1981 run=run->next->invers->next; run->name=aussen; run->invers=nil;
1982 } /* ende if ...*/
1983 naechste=sq.kanten[i];
1984 { add_polygon(5,map,naechste,&naechste); nextmark=naechste; }
1985 belege_sequenz(nextmark,&localseq);
1986 if (localseq.k_marks[0])
1987 { schreibe_auf(map,localseq,sechsecke);
1988 baue_auf(map, localseq, sechsecke); }
1989 /* aufraeumen: */
1990 is_ipr=1;
1991 (map[0][0].name) = (map[0][0].name) - 3;
1992 run=sq.kanten[i]; run->name=aussen; run->invers=nil;
1993 run=run->next->invers->next; run->name=aussen; run->invers=nil;
1994
1995 }
1996
1997 if (sq.laenge==2) /* nur dann oder im vorigen Fall muss auch an 0er angelegt werden */
1998 {
1999 /* In diesem Teil wird die Sequenz nicht a priori berechnet, sondern erst im nachhinein --
2000 das kostet zwar Zeit, ist aber einfacher und braucht nicht so wahnsinnig viele
2001 Fallunterscheidungen */
2002
2003 if (i != 1) { fprintf(stderr,"ERROR: i should be 1 !\n"); exit(26); }
2004 anzahl= 2 + sq.sequenz[0]; /* Bei laenge 0 muss der naechste mit aufgefuellt werden,
2005 um keine Doppel-Innenkanten zu erhalten */
2006
2007 /* erst nur 6-Ecke */
2008 if (sechsecke >= anzahl)
2009 {
2010 naechste=sq.kanten[i];
2011 if (anzahl==1) { add_polygon(6,map,naechste,&naechste); nextmark=naechste; }
2012 else {
2013 add_polygon(6,map,naechste,&naechste); nextmark=naechste->prev->invers->prev;
2014 for (j=1; j<anzahl; j++) add_polygon(6,map,naechste,&naechste); }
2015 belege_sequenz(nextmark,&localseq);
2016 if (localseq.k_marks[0])
2017 { schreibe_auf(map,localseq,sechsecke-anzahl);
2018 baue_auf(map, localseq, sechsecke-anzahl); }
2019 /* aufraeumen: */
2020 (map[0][0].name) = (map[0][0].name) - 2*anzahl -2;
2021 run=sq.kanten[i]; run->name=aussen; run->invers=nil;
2022 run=run->next->invers->next; run->name=aussen; run->invers=nil;
2023 for (j=2 ; j<anzahl; j++) { run=run->next->invers->next->invers->next;
2024 run->name=aussen; run->invers=nil; }
2025 } /* ende if ...*/
2026
2027
2028
2029 /* dann ein 5- und 6-Ecke */
2030 if (sechsecke >= anzahl-1)
2031 {
2032 naechste=sq.kanten[i];
2033 if (anzahl==1) { add_polygon(5,map,naechste,&naechste); nextmark=naechste; }
2034 else {
2035 add_polygon(6,map,naechste,&naechste); nextmark=naechste->prev->invers->prev;
2036 for (j=1; j<anzahl-1; j++) add_polygon(6,map,naechste,&naechste);
2037 add_polygon(5,map,naechste,&naechste); }
2038 belege_sequenz(nextmark,&localseq);
2039 if (localseq.k_marks[0])
2040 { schreibe_auf(map,localseq,sechsecke-anzahl+1);
2041 baue_auf(map, localseq, sechsecke-anzahl+1); }
2042 /* aufraeumen: */
2043 is_ipr=1;
2044 (map[0][0].name) = (map[0][0].name) - 2*anzahl-1;
2045 run=sq.kanten[i]; run->name=aussen; run->invers=nil;
2046 run=run->next->invers->next; run->name=aussen; run->invers=nil;
2047 for (j=2 ; j<anzahl; j++) { run=run->next->invers->next->invers->next;
2048 run->name=aussen; run->invers=nil; }
2049 } /* ende if ... */
2050
2051 /* dann eventuell zwei 5- und der Rest 6-Ecke um es zu 0-Sequenz zu machen */
2052 if (sechsecke >= anzahl-2)
2053 {
2054 naechste=sq.kanten[i];
2055 add_polygon(5,map,naechste,&naechste); nextmark=naechste->prev->invers->prev;
2056 for (j=1; j<anzahl-1; j++) add_polygon(6,map,naechste,&naechste);
2057 add_polygon(5,map,naechste,&naechste);
2058 belege_sequenz(nextmark,&localseq);
2059 check_mark_und_schreibe(map,nextmark,localseq.sequenz[0],sechsecke-anzahl+2);
2060
2061 /* aufraeumen: */
2062 is_ipr=1;
2063 (map[0][0].name) = (map[0][0].name) - 2*anzahl;
2064 run=sq.kanten[i]; run->name=aussen; run->invers=nil;
2065 run=run->next->invers->next; run->name=aussen; run->invers=nil;
2066 for (j=2; j<anzahl; j++) { run=run->next->invers->next->invers->next;
2067 run->name=aussen; run->invers=nil; }
2068
2069 } /* ende if */
2070 } /* ende if sq.laenge==2 */
2071 } /* ende laenge==0 */
2072
2073
2074 else /* d.h. laenge !=0 */
2075 {
2076
2077 /* ein sonderfall, wenn der naechste ein 0er ist (der erste aber nicht)--
2078 dann musss da noch ein 6-Eck mehr angefuegt werden: */
2079
2080 if ((sq.sequenz[naechste_stelle]==0) && (sql>2))
2081 {
2082 if (sechsecke >= laenge+1)
2083 {
2084 naechste=sq.kanten[i];
2085 add_polygon(6,map,naechste,&naechste); nextmark=naechste->prev->invers->prev;
2086 /* insgesamt laenge+1: */
2087 for (j=1; j<=laenge; j++) add_polygon(6,map,naechste,&naechste);
2088 belege_sequenz(nextmark,&localseq);
2089 if (localseq.k_marks[0])
2090 { schreibe_auf(map,localseq,sechsecke-laenge-1);
2091 baue_auf(map, localseq, sechsecke-laenge-1); }
2092 /* aufraeumen: */
2093 (map[0][0].name) = (map[0][0].name) - 2*laenge -4;
2094 run=sq.kanten[i]; run->name=aussen; run->invers=nil;
2095 for (j=0; j<laenge; j++) { run=run->next->invers->next->invers->next;
2096 run->name=aussen; run->invers=nil; }
2097 run=run->next->invers->next; run->name=aussen; run->invers=nil;
2098
2099 } /* ende if ...*/
2100 if (sechsecke >= laenge)
2101 {
2102 naechste=sq.kanten[i];
2103 add_polygon(6,map,naechste,&naechste); nextmark=naechste->prev->invers->prev;
2104 /* insgesamt laenge+1: */
2105 for (j=1; j<laenge; j++) add_polygon(6,map,naechste,&naechste);
2106 add_polygon(5,map,naechste,&naechste);
2107 belege_sequenz(nextmark,&localseq);
2108 if (localseq.k_marks[0])
2109 { schreibe_auf(map,localseq,sechsecke-laenge);
2110 baue_auf(map, localseq, sechsecke-laenge); }
2111 /* aufraeumen: */
2112 is_ipr=1;
2113 (map[0][0].name) = (map[0][0].name) - 2*laenge -3;
2114 run=sq.kanten[i]; run->name=aussen; run->invers=nil;
2115 for (j=0; j<laenge; j++) { run=run->next->invers->next->invers->next;
2116 run->name=aussen; run->invers=nil; }
2117 run=run->next->invers->next; run->name=aussen; run->invers=nil;
2118
2119 } /* ende if ...*/
2120 } /* ende sonderfall naechste_stelle==0-sequenz */
2121
2122
2123
2124 /* erst nur 6-Ecke */
2125 if (sechsecke >= laenge)
2126 {
2127 naechste=sq.kanten[i];
2128 berechne_sequenz(&localseq,sq,i,0);
2129 if (localseq.k_marks[0])
2130 {
2131 if (laenge==1) { add_polygon(6,map,naechste,&naechste); nextmark=naechste;
2132 localseq.kanten[0]=nextmark;
2133 localseq.kanten[localseq.laenge-1]=naechste->prev->invers->prev; }
2134 else {
2135 add_polygon(6,map,naechste,&naechste); nextmark=naechste->prev->invers->prev;
2136 for (j=1; j<laenge; j++) add_polygon(6,map,naechste,&naechste);
2137 localseq.kanten[0]=nextmark; localseq.kanten[1]=naechste; }
2138 if (localseq.k_marks[0])
2139 { schreibe_auf(map,localseq,sechsecke-laenge);
2140 baue_auf(map, localseq, sechsecke-laenge); }
2141 /* aufraeumen: */
2142 (map[0][0].name) = (map[0][0].name) - 2*laenge -1;
2143
2144 run=sq.kanten[i]; run->name=aussen; run->invers=nil;
2145 for (j=0; j<laenge; j++) { run=run->next->invers->next->invers->next;
2146 run->name=aussen; run->invers=nil; }
2147 }/* ende if kanonisch */
2148 } /* ende if ...*/
2149
2150
2151
2152 /* dann ein 5- und 6-Ecke */
2153 if (sechsecke >= laenge-1)
2154 {
2155 naechste=sq.kanten[i];
2156 berechne_sequenz(&localseq,sq,i,1);
2157 if (localseq.k_marks[0])
2158 {
2159 if (laenge==1) { add_polygon(5,map,naechste,&naechste); nextmark=naechste;
2160 localseq.kanten[0]=nextmark; }
2161 else {
2162 add_polygon(6,map,naechste,&naechste); nextmark=naechste->prev->invers->prev;
2163 for (j=1; j<laenge-1; j++) add_polygon(6,map,naechste,&naechste);
2164 add_polygon(5,map,naechste,&naechste);
2165 localseq.kanten[0]=nextmark; }
2166 if (localseq.k_marks[0])
2167 { schreibe_auf(map,localseq,sechsecke-laenge+1);
2168 baue_auf(map, localseq, sechsecke-laenge+1); }
2169 /* aufraeumen: */
2170 is_ipr=1;
2171 (map[0][0].name) = (map[0][0].name) - 2*laenge;
2172 run=sq.kanten[i]; run->name=aussen; run->invers=nil;
2173 for (j=0; j<laenge; j++) { run=run->next->invers->next->invers->next;
2174 run->name=aussen; run->invers=nil; }
2175 }/* ende if kanonisch */
2176 } /* ende if ... */
2177
2178 /* dann eventuell zwei 5- und der Rest 6-Ecke um es zu 0-Sequenz zu machen */
2179 if ((laenge>=2) && (sechsecke >= laenge-2) && (sq.laenge==2))
2180 {
2181 naechste=sq.kanten[i];
2182 berechne_sequenz(&localseq,sq,i,2);
2183 add_polygon(5,map,naechste,&naechste); nextmark=naechste->prev->invers->prev;
2184 for (j=1; j<laenge-1; j++) add_polygon(6,map,naechste,&naechste);
2185 add_polygon(5,map,naechste,&naechste);
2186 localseq.kanten[0]=nextmark;
2187 check_mark_und_schreibe(map,nextmark,localseq.sequenz[0],sechsecke-laenge+2);
2188
2189 /* aufraeumen: */
2190 is_ipr=1;
2191 (map[0][0].name) = (map[0][0].name) - 2*laenge + 1;
2192 run=sq.kanten[i]; run->name=aussen; run->invers=nil;
2193 for (j=0; j<laenge; j++) { run=run->next->invers->next->invers->next;
2194 run->name=aussen; run->invers=nil; }
2195 } /* ende if */
2196 }/* ende laenge != 0 */
2197 } /* ende for */
2198
2199 } /* ende if sequenzlaenge >=2 */
2200
2201 else /* d.h. sequenzlaenge==1 */
2202 {
2203 laenge=sq.sequenz[0];
2204
2205 /* erst nur 6-Ecke */
2206 if (laenge && (sechsecke >= (laenge+1)))
2207 {
2208 naechste=sq.kanten[0];
2209 berechne_sequenz(&localseq,sq,0,0);
2210 for (j=0; j<=laenge; j++) add_polygon(6,map,naechste,&naechste);
2211 nextmark=naechste;
2212 localseq.kanten[0]=nextmark;
2213 schreibe_auf(map,localseq,sechsecke-laenge-1);
2214 baue_auf(map, localseq, sechsecke-laenge-1);
2215 /* aufraeumen: */
2216 (map[0][0].name) = (map[0][0].name) - 2*laenge -3;
2217
2218 run=sq.kanten[0]; run->name=aussen; run->invers=nil;
2219 for (j=0; j<laenge; j++) { run=run->next->invers->next->invers->next;
2220 run->name=aussen; run->invers=nil; }
2221 } /* ende if */
2222
2223 /* dann ein 5- und 6-Ecke */
2224 if (laenge && (sechsecke >= laenge))
2225 {
2226 naechste=sq.kanten[0];
2227 berechne_sequenz(&localseq,sq,0,1);
2228 for (j=0; j<laenge; j++) add_polygon(6,map,naechste,&naechste);
2229 add_polygon(5,map,naechste,&naechste);
2230 nextmark=naechste;
2231 /* das ist zwar zwangslaeufig kanonisch, aber trotzdem: */
2232 localseq.kanten[0]=nextmark;
2233 check_mark_und_schreibe(map,nextmark,localseq.sequenz[0],sechsecke-laenge);
2234 /* aufraeumen: */
2235 is_ipr=1;
2236 (map[0][0].name) = (map[0][0].name) - 2*laenge -2;
2237 run=sq.kanten[0]; run->name=aussen; run->invers=nil;
2238 for (j=0; j<laenge; j++) { run=run->next->invers->next->invers->next;
2239 run->name=aussen; run->invers=nil; }
2240 } /* ende if */
2241
2242
2243 } /* ende else */
2244
2245 }
2246
2247 /***************************BAUE_PATCHES************************************/
2248
baue_patches(int sechsecke)2249 void baue_patches(int sechsecke)
2250 {
2251 PLANMAP map;
2252 SEQUENZ sq;
2253 KANTE *marke;
2254 int i;
2255
2256
2257 for (i=0; i<=N; i++) bblmark[i]=brillenglasmark[i]=zwei_3_4_mark[i]=0;
2258
2259
2260 /* Patches, die nur aus einer Flaeche bestehen, brauchen nicht betrachtet zu
2261 werden */
2262
2263 if (sechsecke >=2)
2264 /* zuerst Start mit 2 Sechsecken */
2265 {
2266 baue_polygon(6,map,&marke);
2267 add_polygon(6,map,marke,&marke);
2268 belege_sequenz(marke, &sq);
2269 schreibe_auf(map,sq,sechsecke-2);
2270 baue_auf( map, sq, sechsecke-2);
2271 }
2272
2273 if (sechsecke >=1)
2274 /* dann ein 5- und ein 6-Eck */
2275 {
2276 baue_polygon(5,map,&marke);
2277 add_polygon(6,map,marke,&marke);
2278 belege_sequenz( marke, &sq);
2279 schreibe_auf(map,sq,sechsecke-1);
2280 baue_auf( map, sq, sechsecke-1);
2281 }
2282
2283 /* dann zwei 5-Ecke */
2284 if (!IPR)
2285 {
2286 baue_polygon(5,map,&marke);
2287 add_polygon(5,map,marke,&marke);
2288 belege_sequenz( marke, &sq);
2289 schreibe_auf(map,sq,sechsecke);
2290 baue_auf( map, sq, sechsecke);
2291 }
2292
2293
2294 for (minbbl=1; bblmark[minbbl]==0; minbbl++);
2295 for (maxbbl=N; bblmark[maxbbl]==0; maxbbl--);
2296
2297 for (minbrillenglas=1; brillenglasmark[minbrillenglas]==0; minbrillenglas++);
2298 for (maxbrillenglas=N; brillenglasmark[maxbrillenglas]==0; maxbrillenglas--);
2299
2300 for (min_2_3_4=1; zwei_3_4_mark[min_2_3_4]==0; min_2_3_4++);
2301
2302
2303 }
2304
2305 /***********************INITIALIZE_LIST**********************************/
2306
initialize_list()2307 void initialize_list()
2308 {
2309 int j;
2310 SEQUENZLISTE *qq;
2311 BBSEQUENZLISTE *bbqq;
2312
2313 mapliste.total_maps=0;
2314
2315 for (j=0; j<=max_sechsecke; j++)
2316 {
2317 qq=(mapliste.sechser)[j]=(SEQUENZLISTE *)malloc(sizeof(SEQUENZLISTE));
2318 if (qq==NULL) { fprintf(stderr,"Can not get more memory"); exit(27); }
2319 qq->next_level=nil;
2320 qq->number_next=0;
2321 qq->items=qq->last_item=nil;
2322 }
2323
2324
2325 bbliste.total_items=bbliste.total_maps=0;
2326 for (j=0; j<=max_sechsecke; j++)
2327 {
2328 bbqq=(bbliste.sechser)[j]=(BBSEQUENZLISTE *)malloc(sizeof(BBSEQUENZLISTE));
2329 if (bbqq==NULL) { fprintf(stderr,"Can not get more memory"); exit(28); }
2330 bbqq->items=nil;
2331 bbqq->number_next=0;
2332 }
2333
2334
2335
2336
2337 }
2338
2339
2340
2341 /**********************ZAEHLE_KNOTEN*************************************/
2342
zaehle_knoten(PLANMAP map,KNOTENTYP knoten,BOOL mark[],int * patchknz)2343 void zaehle_knoten(PLANMAP map, KNOTENTYP knoten, BOOL mark[], int *patchknz)
2344
2345 /* zaehlt die knoten, belegt aber auch dummy */
2346
2347 {
2348 int j;
2349
2350 for (j=0; j<3; j++)
2351 if (map[knoten][j].mininame == aussen) map[knoten][j].dummy=infty;
2352 else { map[knoten][j].dummy=0;
2353 if (!mark[map[knoten][j].mininame])
2354 { (*patchknz)++;
2355 mark[map[knoten][j].mininame]=1;
2356 zaehle_knoten(map,map[knoten][j].mininame,mark,patchknz);
2357 }
2358 }
2359 }
2360
2361
2362
2363 /**********************REKO_BB_CODE***************************************/
2364 /* Rekonstruiert den minimalen Code eines 6-Eck-patches */
2365
reko_bb_code(PLANMAP map,KNOTENTYP * code,KNOTENTYP * spiegelcode,int laenge,KANTE * start,KANTE * ministart[],KANTE * spiegelministart[],int * patchknz)2366 void reko_bb_code(PLANMAP map, KNOTENTYP *code, KNOTENTYP *spiegelcode, int laenge,
2367 KANTE *start, KANTE *ministart[], KANTE *spiegelministart[], int *patchknz)
2368 {
2369 int i, j, stelle, zaehler, knotenzahl, flaechennumber, schichtenzaehler, verschiebung, merkeknoten;
2370 /* zaehler zaehlt die Flaechengroesse, knotenzahl die zahl der restlichen knoten */
2371 int laufzaehler;
2372 KANTE *run, *merke, *run2, *merke_run, *mstart;
2373 KNOTENTYP testcode[9];
2374 int mstartzaehler, test, k, laenge_2;
2375 BOOL mark[N+1];
2376
2377
2378 if (start->mininame != aussen) { fprintf(stderr,"Reko_BB_code must start at external edge !\n");
2379 exit(29); }
2380 for (i=0; i<8; i++) { code[i]=spiegelcode[i]=unbelegt; testcode[i]=0; }
2381
2382 mstartzaehler=0;
2383 for (i=0; i<7; i++) ministart[i]=spiegelministart[i]=nil;
2384
2385 for (i=1; i<=map[0][0].name; i++) mark[i]=0;
2386 mark[start->ursprung]=1; *patchknz=1;
2387
2388 zaehle_knoten(map,start->ursprung,mark,patchknz);
2389
2390 laenge_2 = laenge/2;
2391 run=start; knotenzahl=*patchknz;
2392
2393 verschiebung=schichtenzaehler=0;
2394
2395 while (!verschiebung)
2396 {for (i=1, run2=run->prev; (i<=laenge_2) && !verschiebung; i++, run2=run2->prev->invers->next->invers)
2397 /* muss bei 1 starten und nachher korrigiert werden, um den Abbruch bei 0 zu gewaehrleisten */
2398 { if (checksize(run2) == 5) { run=run2->next; verschiebung=i; } }
2399 if (!verschiebung) { schichtenzaehler++;
2400 knotenzahl -= laenge;
2401 run=run->prev->invers->next->invers;
2402 for (run2=run, i=0; i<laenge_2; i++,
2403 run2=run2->next->invers->next->invers->next)
2404 { run2->dummy=infty; }
2405 }
2406 } /* ende while */
2407 code[0]=schichtenzaehler; code[1]=0; /* verschiebung wird nicht betrachtet */ stelle=2;
2408 merkeknoten=knotenzahl;
2409 laufzaehler=1;
2410 /* Jetzt den minimalen Code ausrechnen: */
2411 for ( run2=run->prev; verschiebung<=laenge_2; verschiebung++, run2=run2->prev->invers->next->invers)
2412 if (checksize(run2)==5)
2413 { merke_run=run2->next;
2414 laufzaehler++;
2415 run=run2->next;
2416 stelle=2; knotenzahl=merkeknoten;
2417 flaechennumber=0;
2418 while (stelle<8)
2419 {
2420 flaechennumber++;
2421 zaehler=2;
2422 while (run->prev->invers->prev->dummy>=laufzaehler)
2423 run=run->prev->invers->prev; /* sicherstellen, dass davor
2424 keine aussenkanten sind */
2425 run->prev->invers->dummy=laufzaehler; run->next->invers->dummy=laufzaehler;
2426 run=run->next->invers->next; knotenzahl--;
2427 while (run->dummy>=laufzaehler)
2428 { zaehler++; knotenzahl--; run->prev->invers->dummy=laufzaehler;
2429 run->next->invers->dummy=laufzaehler;
2430 run=run->next->invers->next; }
2431 merke=run->next;
2432 run=run->prev;
2433 while (merke->dummy<laufzaehler)
2434 { zaehler++; merke=merke->invers->prev; }
2435 if (zaehler==5) { testcode[stelle]=flaechennumber; stelle++; }
2436 else if (zaehler!=6) { fprintf(stderr,"ERROR in REKO_BB_CODE: No 5- or 6-Gon !\n"); exit(30); }
2437 if (knotenzahl==5) { testcode[stelle]=flaechennumber+1; stelle++; }
2438 } /* ende while */
2439 if ((test=codecmp_kn(code+2,testcode+2,6))>=0)
2440 { if (test>0) { for (stelle=2; stelle<8; stelle++) code[stelle]=testcode[stelle];
2441 for (k=0; k<mstartzaehler; k++) ministart[k]=nil;
2442 mstartzaehler=0;}
2443 mstart=merke_run;
2444 for (k=0; k<schichtenzaehler; k++) mstart = mstart->invers->prev->invers->next;
2445 ministart[mstartzaehler]=mstart->prev->invers->next;
2446 mstartzaehler++;
2447 }
2448 } /* ende checksize==5 */
2449
2450
2451
2452 /* Jetzt den Spiegelcode */
2453
2454 for (i=1; i<=map[0][0].name; i++)
2455 if (mark[i])
2456 for (j=0; j<3; j++)
2457 { if (map[i][j].mininame==aussen) map[i][j].dummy=infty;
2458 else map[i][j].dummy=0; }
2459
2460 run=start; knotenzahl=*patchknz;
2461
2462 verschiebung=schichtenzaehler=mstartzaehler=0;
2463
2464 while (!verschiebung)
2465 {for (i=1, run2=run->prev; (i<=laenge_2) && !verschiebung; i++, run2=run2->invers->prev->invers->next)
2466 /* muss bei 1 starten und nachher korrigiert werden, um den Abbruch bei 0 zu gewaehrleisten */
2467 { if (checksize(run2) == 5) { run=run2->next; verschiebung=i; } }
2468 if (!verschiebung) { schichtenzaehler++;
2469 knotenzahl -= laenge;
2470 run=run->next->invers->prev->invers;
2471 for (run2=run, i=0; i<laenge_2; i++,
2472 run2=run2->prev->invers->prev->invers->prev)
2473 { run2->dummy=infty; }
2474 }
2475 } /* ende while */
2476 spiegelcode[0]=schichtenzaehler; spiegelcode[1]=0; /* verschiebung wird nicht betrachtet */ stelle=2;
2477 merkeknoten=knotenzahl;
2478 laufzaehler=1;
2479 /* Jetzt den minimalen Code ausrechnen: */
2480 for ( run2=run->prev; verschiebung<=laenge_2; verschiebung++, run2=run2->invers->prev->invers->next)
2481 if (checksize(run2)==5)
2482 { merke_run=run2->next;
2483 laufzaehler++;
2484 run=run2->next;
2485 stelle=2; knotenzahl=merkeknoten;
2486 flaechennumber=0;
2487 while (stelle<8)
2488 { flaechennumber++;
2489 zaehler=2;
2490 while (run->next->invers->next->dummy>=laufzaehler)
2491 run=run->next->invers->next; /* sicherstellen, dass davor
2492 keine aussenkanten sind */
2493 run->next->invers->dummy=laufzaehler; run->prev->invers->dummy=laufzaehler;
2494 run=run->prev->invers->prev; knotenzahl--;
2495 while (run->dummy>=laufzaehler)
2496 { zaehler++; knotenzahl--; run->next->invers->dummy=laufzaehler;
2497 run->prev->invers->dummy=laufzaehler;
2498 run=run->prev->invers->prev; }
2499 merke=run->prev;
2500 run=run->next;
2501 while (merke->dummy<laufzaehler)
2502 { zaehler++; merke=merke->invers->next; }
2503 if (zaehler==5) { testcode[stelle]=flaechennumber; stelle++; }
2504 else if (zaehler!=6) { fprintf(stderr,"ERROR in REKO_BB_CODE(2): No 5- or 6-Gon !\n"); exit(31); }
2505 if (knotenzahl==5) { testcode[stelle]=flaechennumber+1; stelle++; }
2506 } /* ende while */
2507 if ((test=codecmp_kn(spiegelcode+2,testcode+2,6))>=0)
2508 { if (test>0) { for (stelle=2; stelle<8; stelle++) spiegelcode[stelle]=testcode[stelle];
2509 for (k=0; k<mstartzaehler; k++) spiegelministart[k]=nil;
2510 mstartzaehler=0;}
2511 mstart=merke_run;
2512 for (k=0; k<schichtenzaehler; k++) mstart = mstart->invers->next->invers->prev;
2513 spiegelministart[mstartzaehler]=mstart->next->invers->prev;
2514 mstartzaehler++;
2515 }
2516 } /* ende checksize==5 */
2517
2518 return;
2519 }
2520
2521 /***********************BAUCHBINDE_REKO*******************************/
2522
2523 /* berechnet den minimalen Code, der sich aus der bei "anfangskante"
2524 beginnenden Bauchbinde ergibt */
2525 /* TH: Die Funktion wurde so geaendert, dass sie
2526 0 zurueckgibt, wenn code > minimaler Code (wie bisher)
2527 1 zurueckgibt, wenn code < minimaler Code (wie bisher)
2528 2 zurueckgibt, wenn code== minimaler Code fuer die
2529 Originalversion (Automorphismus existiert)
2530 4 zurueckgibt, wenn code== minimaler Code fuer die
2531 gespiegelte Version (Automorphismus existiert)
2532 6 zurueckgibt, wenn code== minimaler Code sowohl fuer die
2533 Originalversion als auch fuer die gespiegelte
2534 Version (Automorphismus existiert) */
2535
bauchbinde_reko(PLANMAP map,KNOTENTYP * code,KANTE * anfangskante)2536 int bauchbinde_reko(PLANMAP map,KNOTENTYP *code,KANTE *anfangskante)
2537 {
2538 int i,j,k, patchknz1, patchknz2, test, test2, test3, test4, returnwert;
2539 KANTE *run;
2540 KNOTENTYP code1[8], code2[8], spiegelcode1[8], spiegelcode2[8];
2541 KANTE *ministart1[7], *ministart2[7], *spiegelministart1[7], *spiegelministart2[7];
2542 KNOTENTYP *ucode, *lcode, *uscode, *lscode;
2543 KANTE **ustart, **lstart, **us_start, **ls_start;
2544 BOOL gleich, ende;
2545 BOOL j_gleich1, j_gleich2, j_gleich3, j_gleich4; /* TH */
2546 FLAECHENTYP c3, c11;
2547
2548
2549 c3=code[3]; c11=code[11];
2550 code[3]=code[11]=0;
2551
2552 for (i=1; i<=map[0][0].name; i++) for (j=0;j<3; j++) { map[i][j].dummy=0;
2553 map[i][j].mininame=map[i][j].name; }
2554
2555 for (i=1, run=anfangskante->invers->prev; i<code[0]; i+=2)
2556 { run->prev->mininame=aussen;
2557 run=run->invers->next->invers->prev; }
2558
2559 reko_bb_code(map, code1, spiegelcode1, code[0], anfangskante->invers->next, ministart1, spiegelministart1,
2560 &patchknz1);
2561
2562
2563 for (i=1, run=anfangskante->invers->prev; i<code[0]; i+=2)
2564 { run->prev->mininame=run->prev->name;
2565 run->invers->prev->mininame=aussen;
2566 run=run->invers->next->invers->prev; }
2567
2568 reko_bb_code(map, code2, spiegelcode2, code[0], anfangskante->next, ministart2, spiegelministart2,
2569 &patchknz2);
2570
2571
2572 if (patchknz2>patchknz1) { ucode=code2; uscode=spiegelcode2; lcode=code1; lscode=spiegelcode1;
2573 ustart=ministart2; lstart=ministart1; us_start=spiegelministart2;
2574 ls_start=spiegelministart1; gleich=0; }
2575 else if (patchknz2<patchknz1) { ucode=code1; uscode=spiegelcode1; lcode=code2; lscode=spiegelcode2;
2576 ustart=ministart1; lstart=ministart2; us_start=spiegelministart1;
2577 ls_start=spiegelministart2; gleich=0; }
2578 else /* d.h. beide patchknotenzahlen gleich */
2579 { test=codecmp_kn(code1,code2,8);
2580 if (test>0) { ucode=code1; lcode=code2; ustart=ministart1; lstart=ministart2; gleich=0; }
2581 else { if (test<0) { ucode=code2; lcode=code1; ustart=ministart2; lstart=ministart1; gleich=0; }
2582 else { ucode=code1; lcode=code2; ustart=ministart1; lstart=ministart2; /*vorerst*/ gleich=1;
2583 }
2584 }
2585 test=codecmp_kn(spiegelcode1,spiegelcode2,8);
2586 if (test>0) { uscode=spiegelcode1; lscode=spiegelcode2; us_start=spiegelministart1;
2587 ls_start=spiegelministart2; }
2588 else { if (test<0) { uscode=spiegelcode2; lscode=spiegelcode1; us_start=spiegelministart2;
2589 ls_start=spiegelministart1; }
2590 else { uscode=spiegelcode1; lscode=spiegelcode2; us_start=spiegelministart1; /*vorerst*/
2591 ls_start=spiegelministart2; }
2592 }
2593 }
2594
2595 j_gleich1 = j_gleich2 = 0; /* TH */
2596 if ((test=codecmp_kn(lcode,code+2,8)) < 0) {code[3]=c3; code[11]=c11; return(0);}
2597 else if (test==0)
2598 { if ((test2=codecmp_kn(ucode,code+10,8)) < 0) {code[3]=c3; code[11]=c11; return(0);}
2599 else if (test2==0) /* d.h. die verschiebung muss entscheiden */
2600 { for (i=0; ustart[i]!=nil; i++)
2601 { run=ustart[i]->next->invers->prev;
2602 j=ende=0;
2603 while (!ende)
2604 {
2605 for (k=0; lstart[k] != nil; k++) if (lstart[k]==run) ende=1;
2606 if (!ende) { j++; run=run->prev->invers->prev->invers->prev; }
2607 }
2608 if (j<code[18]) {code[3]=c3; code[11]=c11; return(0);}
2609 if (j==code[18]) {j_gleich1 = 1;} /* TH */
2610 }
2611 if (gleich) {
2612 for (i=0; lstart[i]!=nil; i++)
2613 { run=lstart[i]->next->invers->prev;
2614 j=ende=0;
2615 while (!ende)
2616 {
2617 for (k=0; ustart[k] != nil; k++) if (ustart[k]==run) ende=1;
2618 if (!ende) { j++; run=run->prev->invers->prev->invers->prev; }
2619 }
2620 if (j<code[18]) {code[3]=c3; code[11]=c11; return(0);}
2621 if (j==code[18]) {j_gleich2 = 1;} /* TH */
2622 }
2623 }
2624 else {j_gleich2 = 1;} /* TH */
2625 } /* ende test2==0 */
2626 } /* ende test==0 */
2627
2628
2629 /* nun fuer die gespiegelte version: */
2630
2631 j_gleich3 = j_gleich4 = 0; /* TH */
2632 if ((test3=codecmp_kn(lscode,code+2,8)) < 0) { code[3]=c3; code[11]=c11; return(0); }
2633 else if (test3==0)
2634 { if ((test4=codecmp_kn(uscode,code+10,8)) < 0) {code[3]=c3; code[11]=c11; return(0);}
2635 else if (test4==0) /* d.h. die verschiebung muss entscheiden */
2636 {
2637 for (i=0; us_start[i]!=nil; i++)
2638 { run=us_start[i]->prev->invers->next;
2639 j=ende=0;
2640 while (!ende)
2641 { for (k=0; ls_start[k] != nil; k++) if (ls_start[k]==run) ende=1;
2642 if (!ende) { j++; run=run->next->invers->next->invers->next; }
2643 }
2644 if (j<code[18]) {code[3]=c3; code[11]=c11; return(0);}
2645 if (j==code[18]) {j_gleich3 = 1;} /* TH */
2646 }
2647 if (gleich) {
2648 for (i=0; ls_start[i]!=nil; i++)
2649 { run=ls_start[i]->prev->invers->next;
2650 j=ende=0;
2651 while (!ende)
2652 { for (k=0; us_start[k] != nil; k++) if (us_start[k]==run) ende=1;
2653 if (!ende) { j++; run=run->next->invers->next->invers->next; }
2654 }
2655 if (j<code[18]) {code[3]=c3; code[11]=c11; return(0);}
2656 if (j==code[18]) {j_gleich4 = 1;}
2657 }
2658 }
2659 else {j_gleich4 = 1;} /* TH */
2660 } /* ende test2==0 */
2661 } /* ende test==0 */
2662
2663 code[3]=c3; code[11]=c11;
2664
2665 /* TH: Auswertung */
2666 returnwert = 1;
2667 if (test==0 && test2==0 && j_gleich1 && j_gleich2) {returnwert=2;}
2668 if (test3==0 && test4==0 && j_gleich3 && j_gleich4) {
2669 if (returnwert==1) {returnwert=4;} else {returnwert=6;}
2670 }
2671 return(returnwert);
2672
2673 }
2674
2675
2676
2677 /***********************SUCHESTART_REKO********************************/
2678
suchestart_reko(KANTE * start,int * fuenfecke)2679 KANTE *suchestart_reko( KANTE *start, int *fuenfecke)
2680 /* belegt eine sequenz und sucht die kanonische Kante mit dem kleinsten Namen
2681 arbeitet "invers", d.h. es wird als Innenrand gesehen, der gefuellt werden
2682 muss. Wird aufgerufen fuer Brille und Sandwich. Start muss eine Kante sein, die
2683 ins innere zeigt.
2684 Funktioniert wie suchestart, nur dass mininame statt name benutzt wird und die
2685 Anzahl der 5-Ecke auch berechnet wird */
2686
2687 {
2688 int i, j, k, zaehler, position, sqlaenge;
2689 KANTE *run;
2690 int sequenz[7];
2691 KANTE *seqkanten[7];
2692 int puffer[7];
2693 char kan[7];
2694
2695
2696
2697 while (start->next->invers->next->invers->next->mininame == aussen)
2698 start=start->next->invers->next->invers->next;
2699 /* Sucht 2 Kanten hintereinander nach aussen -- zu unterscheiden vom namen aussen, was
2700 auch nach innen heissen kann. Duerfte nur fuer bauchbinden eine Endlosschleife sein */
2701
2702 for (i=0; i<7; i++) { sequenz[i]=leer; seqkanten[i]=nil; kan[i]=0; }
2703
2704 sqlaenge=0;
2705 position=0;
2706 seqkanten[0]=start;
2707
2708
2709 for (zaehler=1, run=start;
2710 run->prev->invers->prev->invers->prev->mininame == aussen;
2711 run=run->prev->invers->prev->invers->prev) zaehler++;
2712 sequenz[0]=zaehler; position=1; seqkanten[1]=nil;
2713 for (run=run->prev->invers->prev->invers->prev->invers->prev; run->mininame != aussen;
2714 run=run->invers->prev)
2715 { sequenz[position]=0; position++; seqkanten[position]=nil; }
2716 /* naechste Kante vor nicht-0-sequenz suchen -- entsprechende innenkanten gibt es nicht
2717 und muessen sich dementsprechend auch nicht gemerkt werden */
2718
2719
2720 while (run != start)
2721 {
2722 seqkanten[position]=run;
2723 for (zaehler=1;
2724 run->prev->invers->prev->invers->prev->mininame == aussen;
2725 run=run->prev->invers->prev->invers->prev) { zaehler++; }
2726 sequenz[position]=zaehler; position++; seqkanten[position]=nil;
2727 for (run=run->prev->invers->prev->invers->prev->invers->prev; run->mininame != aussen;
2728 run=run->invers->prev)
2729 { sequenz[position]=0; position++; seqkanten[position]=nil; }
2730 }
2731
2732
2733 sequenz[position]=leer; seqkanten[position]=nil;
2734 sqlaenge=position;
2735
2736 *fuenfecke=6-sqlaenge;
2737
2738 kan[0]=sequenz_kanonisch(sequenz);
2739
2740
2741 for (i=0; sequenz[i] != leer; i++)
2742 { for (j=i, k=0; sequenz[j]!=leer; j++, k++) puffer[k]=sequenz[j];
2743 for (j=0; j<i; j++, k++) puffer[k]=sequenz[j];
2744 puffer[k]=leer;
2745 kan[i]=sequenz_kanonisch(puffer);
2746 }
2747
2748
2749
2750 for (i=0, run=nil; sequenz[i] != leer; i++)
2751 { if (kan[i])
2752 if ((run==nil) || (seqkanten[i]->dummy < run->dummy)) run=seqkanten[i];
2753 /* dummy ersetzt ursprung */
2754 }
2755
2756 /* Jetzt die vorige Innenkante suchen, um rechts davon dann einfuegen zu koennen */
2757 for (run=run->next->invers->next->invers->next; run->mininame != aussen; run=run->invers->next);
2758
2759
2760 return(run);
2761
2762 }
2763
2764 /**********************CHECKSIZE_AND_MARK**************************************/
2765
2766 /* bestimmt die groesse der flaeche links von edge -- ist da keine gibt's Probleme
2767 ausserdem setzt er fuer alle kanten, so dass diese flaeche links davon ist, dummy
2768 auf 1*/
2769
checksize_and_mark(KANTE * edge)2770 int checksize_and_mark( KANTE* edge)
2771 {
2772 KANTE *run;
2773 int zaehler=1;
2774
2775 edge->noleft=1;
2776 for (run=edge->invers->next; run != edge; run=run->invers->next) {run->noleft=1; zaehler++;}
2777 return(zaehler);
2778 }
2779
2780
2781
2782
2783 /**************************REKO_PATCH*****************************/
2784
reko_patch(KANTE * anfang,KNOTENTYP code[],int fuenfecke)2785 void reko_patch(KANTE *anfang,KNOTENTYP code[],int fuenfecke)
2786 {
2787 int i, position, zaehler, z2;
2788 KANTE *run, *merke;
2789
2790
2791 /* wenn bei einer kante hier noleft gesetzt ist, so heisst das, dass
2792 links davon keine Flaeche mehr ist. Bei den zur Brille gehoerenden Kanten
2793 ist das teilweise falsch --macht aber nichts */
2794
2795 for (i=0; i<=fuenfecke; i++) code[i]=0;
2796
2797 position=0; run=anfang;
2798 zaehler=1;
2799
2800 while (position<fuenfecke)
2801 {
2802 if (checksize_and_mark(run)==5) { code[position]=zaehler; position++;
2803 if (position==fuenfecke) return; }
2804 zaehler++;
2805 merke=run->invers; run=run->prev; z2=1;
2806 while ((merke != run) && (run->noleft) && (z2 <=6))
2807 { run=run->invers->prev; z2++; }
2808 if ((merke==run) && (run->noleft)) /* dann muss die letzte flaeche das letzte 5-eck sein */
2809 { code[position]=zaehler; position++;
2810 if (position<fuenfecke)
2811 { fprintf(stderr," ERROR in reko_patch ! Patch empty and missing 5-gon !\n"); exit(32); }
2812 }
2813 }
2814 }
2815
2816
2817
2818 /**********************BRILLE_REKO*******************************/
2819
2820 /* berechnet den minimalen Code, der sich aus der bei "anfangskante"
2821 beginnenden Brille ergibt */
2822 /* TH: Die Funktion wurde so geaendert, dass sie
2823 0 zurueckgibt, wenn code > minimaler Code (wie bisher)
2824 1 zurueckgibt, wenn code < minimaler Code (wie bisher)
2825 2 zurueckgibt, wenn code== minimaler Code (Automorphismus existiert) */
2826
brille_reko(PLANMAP map,KNOTENTYP * code,KANTE * anfangskante)2827 int brille_reko(PLANMAP map,KNOTENTYP *code,KANTE *anfangskante)
2828 {
2829 int i,j, l1, l2, l3, fuenfecke, vergleichsanfang, test;
2830 KANTE *run, *startkante1, *startkante2, *startkante3, *anfang;
2831 KNOTENTYP testcode[6];
2832
2833
2834 l1=code[2]; l3=code[3]; l2=code[0]-l1-l3;
2835
2836 for (i=1; i<=map[0][0].name; i++) for (j=0;j<3; j++) { map[i][j].dummy=map[i][j].noleft=0;
2837 map[i][j].mininame=1; }
2838
2839 /* markieren der Brille: */
2840
2841 anfangskante->mininame=anfangskante->noleft=anfangskante->invers->noleft=1;
2842 anfangskante->invers->mininame=l1;
2843
2844 for (i=1, run=anfangskante; i<code[0]; i++)
2845 { run=run->invers->prev;
2846 run->noleft=run->invers->noleft=1;
2847 run->mininame=i+1;
2848 run->dummy=run->prev->dummy=run->next->dummy=i;
2849 run->invers->mininame=i;
2850 if (i!=l1) run->prev->mininame=aussen;
2851 i++;
2852 if (i<code[0])
2853 {
2854 run=run->invers->next;
2855 run->noleft=run->invers->noleft=1;
2856 run->dummy=run->prev->dummy=run->next->dummy=i;
2857 run->mininame=i+1;
2858 run->invers->mininame=i;
2859 if (i!=l1) run->next->mininame=aussen;
2860 }
2861 }
2862
2863 /* reparieren: */ run->mininame=l1+l2;
2864
2865 if (l1%2) { startkante1=anfangskante->invers->next;
2866 startkante2=anfangskante->invers->prev->invers->prev; }
2867 else { startkante2=anfangskante->invers->next;
2868 startkante1=anfangskante->invers->prev->invers->prev; }
2869
2870 if (code[0]%2) /* d.h. der knoten, bei dem run ist, ist gerade */
2871 { if (l3%2) startkante3=run->next;
2872 else startkante3=run->prev->invers->prev; }
2873 else
2874 { if (l3%2) startkante3=run->prev;
2875 else startkante3=run->next->invers->next; }
2876
2877 vergleichsanfang=4;
2878 anfang=suchestart_reko( startkante1, &fuenfecke);
2879 reko_patch(anfang,testcode,fuenfecke);
2880 if ((test=codecmp_kn(testcode,code+vergleichsanfang,fuenfecke))<0) return(0);
2881 if (test>0) return(1);
2882 vergleichsanfang+=fuenfecke;
2883 anfang=suchestart_reko( startkante2, &fuenfecke);
2884 reko_patch(anfang,testcode,fuenfecke);
2885 if ((test=codecmp_kn(testcode,code+vergleichsanfang,fuenfecke))<0) return(0);
2886 if (test>0) return(1);
2887 vergleichsanfang+=fuenfecke;
2888 anfang=suchestart_reko( startkante3, &fuenfecke);
2889 reko_patch(anfang,testcode,fuenfecke);
2890 if ((test=codecmp_kn(testcode,code+vergleichsanfang,fuenfecke))<0) return(0);
2891 if (test==0) return(2);
2892 return(1);
2893 }
2894
2895 /***********************SUCHESTART_REKO_SP********************************/
2896
suchestart_reko_sp(KANTE * start,int * fuenfecke)2897 KANTE *suchestart_reko_sp( KANTE *start, int *fuenfecke)
2898 /* Wie suchestart_reko -- nur die spiegelversion */
2899
2900 {
2901 int i, j, k, zaehler, position, sqlaenge;
2902 KANTE *run;
2903 int sequenz[7];
2904 KANTE *seqkanten[7];
2905 int puffer[7];
2906 char kan[7];
2907
2908
2909
2910 while (start->prev->invers->prev->invers->prev->mininame == aussen)
2911 start=start->prev->invers->prev->invers->prev;
2912 /* Sucht 2 Kanten hintereinander nach aussen -- zu unterscheiden vom namen aussen, was
2913 auch nach innen heissen kann. Duerfte nur fuer bauchbinden eine Endlosschleife sein */
2914
2915 for (i=0; i<7; i++) { sequenz[i]=leer; seqkanten[i]=nil; kan[i]=0; }
2916
2917 sqlaenge=0;
2918 position=0;
2919 seqkanten[0]=start;
2920
2921
2922 for (zaehler=1, run=start;
2923 run->next->invers->next->invers->next->mininame == aussen;
2924 run=run->next->invers->next->invers->next) zaehler++;
2925 sequenz[0]=zaehler; position=1; seqkanten[1]=nil;
2926 for (run=run->next->invers->next->invers->next->invers->next; run->mininame != aussen;
2927 run=run->invers->next)
2928 { sequenz[position]=0; position++; seqkanten[position]=nil; }
2929 /* naechste Kante vor nicht-0-sequenz suchen -- entsprechende innenkanten gibt es nicht
2930 und muessen sich dementsprechend auch nicht gemerkt werden */
2931
2932
2933 while (run != start)
2934 {
2935 seqkanten[position]=run;
2936 for (zaehler=1;
2937 run->next->invers->next->invers->next->mininame == aussen;
2938 run=run->next->invers->next->invers->next) { zaehler++; }
2939 sequenz[position]=zaehler; position++; seqkanten[position]=nil;
2940 for (run=run->next->invers->next->invers->next->invers->next; run->mininame != aussen;
2941 run=run->invers->next)
2942 { sequenz[position]=0; position++; seqkanten[position]=nil; }
2943 }
2944
2945
2946 sequenz[position]=leer; seqkanten[position]=nil;
2947 sqlaenge=position;
2948
2949 *fuenfecke=6-sqlaenge;
2950
2951 kan[0]=sequenz_kanonisch(sequenz);
2952
2953
2954 for (i=0; sequenz[i] != leer; i++)
2955 { for (j=i, k=0; sequenz[j]!=leer; j++, k++) puffer[k]=sequenz[j];
2956 for (j=0; j<i; j++, k++) puffer[k]=sequenz[j];
2957 puffer[k]=leer;
2958 kan[i]=sequenz_kanonisch(puffer);
2959 }
2960
2961
2962
2963 for (i=0, run=nil; sequenz[i] != leer; i++)
2964 { if (kan[i])
2965 if ((run==nil) || (seqkanten[i]->dummy < run->dummy)) run=seqkanten[i];
2966 /* dummy ersetzt ursprung */
2967 }
2968
2969 /* Jetzt die vorige Innenkante suchen, um links (spiegel !!) davon dann einfuegen zu koennen */
2970 for (run=run->prev->invers->prev->invers->prev; run->mininame != aussen; run=run->invers->prev);
2971
2972 return(run);
2973
2974 }
2975
2976 /**********************CHECKSIZE_AND_MARK_SP**************************************/
2977
2978 /* bestimmt die groesse der flaeche rechts von edge -- ist da keine gibt's Probleme
2979 ausserdem setzt er fuer alle kanten, so dass diese flaeche rechts davon ist,
2980 noright auf 1 */
2981
checksize_and_mark_sp(KANTE * edge)2982 int checksize_and_mark_sp( KANTE* edge)
2983 {
2984 KANTE *run;
2985 int zaehler=1;
2986
2987 edge->noright=1;
2988 for (run=edge->invers->prev; run != edge; run=run->invers->prev) {run->noright=1; zaehler++;}
2989 return(zaehler);
2990 }
2991
2992
2993
2994
2995 /**************************REKO_PATCH_SP*****************************/
2996
reko_patch_sp(KANTE * anfang,KNOTENTYP code[],int fuenfecke)2997 void reko_patch_sp(KANTE *anfang,KNOTENTYP code[],int fuenfecke)
2998 {
2999 int i, position, zaehler, z2;
3000 KANTE *run, *merke;
3001
3002
3003 /* wenn bei einer kante hier noright gesetzt ist, so heisst das, dass
3004 rechts davon keine Flaeche mehr ist. Bei den zur Brille gehoerenden Kanten
3005 ist das teilweise falsch --macht aber nichts */
3006
3007 for (i=0; i<=fuenfecke; i++) code[i]=0;
3008
3009 position=0; run=anfang;
3010 zaehler=1;
3011
3012 while (position<fuenfecke)
3013 { if (checksize_and_mark_sp(run)==5) { code[position]=zaehler; position++;
3014 if (position==fuenfecke) return; }
3015 zaehler++;
3016 merke=run->invers; run=run->next; z2=1;
3017 while ((merke != run) && (run->noright) && (z2 <=6))
3018 { run=run->invers->next; z2++; }
3019 if ((merke==run) && (run->noright)) /* dann muss die letzte flaeche das letzte 5-eck sein */
3020 { code[position]=zaehler; position++;
3021 if (position<fuenfecke)
3022 { fprintf(stderr," ERROR in reko_patch_sp ! Patch empty and missing 5-gon !\n"); exit(33); }
3023 }
3024 }
3025 }
3026
3027
3028
3029 /***********************BRILLE_SP_REKO*******************************/
3030
3031 /* berechnet den minimalen Code, der sich aus der bei "anfangskante"
3032 beginnenden Brille ergibt -- allerdings unter der Voraussetzung,
3033 dass alles spiegelverkehrt gesehen wird */
3034 /* TH: Die Funktion wurde so geaendert, dass sie
3035 0 zurueckgibt, wenn code > minimaler Code (wie bisher)
3036 1 zurueckgibt, wenn code < minimaler Code (wie bisher)
3037 2 zurueckgibt, wenn code== minimaler Code (Automorphismus existiert) */
3038
brille_sp_reko(PLANMAP map,KNOTENTYP * code,KANTE * anfangskante)3039 int brille_sp_reko(PLANMAP map,KNOTENTYP *code,KANTE *anfangskante)
3040 {
3041 int i,j, l1, l2, l3, fuenfecke, vergleichsanfang, test;
3042 KANTE *run, *startkante1, *startkante2, *startkante3, *anfang;
3043 KNOTENTYP testcode[6];
3044
3045
3046
3047 l1=code[2]; l3=code[3]; l2=code[0]-l1-l3;
3048
3049 for (i=1; i<=map[0][0].name; i++) for (j=0;j<3; j++) { map[i][j].dummy=map[i][j].noright=0;
3050 map[i][j].mininame=1; }
3051
3052 /* markieren der Brille: */
3053
3054 anfangskante->mininame=anfangskante->noright=anfangskante->invers->noright=1;
3055 anfangskante->invers->mininame=l1;
3056
3057 for (i=1, run=anfangskante; i<code[0]; i++)
3058 { run=run->invers->next;
3059 run->noright=run->invers->noright=1;
3060 run->mininame=i+1;
3061 run->dummy=run->prev->dummy=run->next->dummy=i;
3062 run->invers->mininame=i;
3063 if (i!=l1) run->next->mininame=aussen;
3064 i++;
3065 if (i<code[0])
3066 {
3067 run=run->invers->prev;
3068 run->noright=run->invers->noright=1;
3069 run->dummy=run->prev->dummy=run->next->dummy=i;
3070 run->mininame=i+1;
3071 run->invers->mininame=i;
3072 if (i!=l1) run->prev->mininame=aussen;
3073 }
3074 }
3075
3076 /* reparieren: */ run->mininame=l1+l2;
3077
3078 if (l1%2) { startkante1=anfangskante->invers->prev;
3079 startkante2=anfangskante->invers->next->invers->next; }
3080 else { startkante2=anfangskante->invers->prev;
3081 startkante1=anfangskante->invers->next->invers->next; }
3082
3083 if (code[0]%2) /* d.h. der knoten, bei dem run ist, ist gerade */
3084 { if (l3%2) startkante3=run->prev;
3085 else startkante3=run->next->invers->next; }
3086 else
3087 { if (l3%2) startkante3=run->next;
3088 else startkante3=run->prev->invers->prev; }
3089
3090
3091 vergleichsanfang=4;
3092 anfang=suchestart_reko_sp( startkante1, &fuenfecke);
3093 reko_patch_sp(anfang,testcode,fuenfecke);
3094 if ((test=codecmp_kn(testcode,code+vergleichsanfang,fuenfecke))<0) return(0);
3095 if (test>0) return(1);
3096 vergleichsanfang+=fuenfecke;
3097 anfang=suchestart_reko_sp( startkante2, &fuenfecke);
3098 reko_patch_sp(anfang,testcode,fuenfecke);
3099 if ((test=codecmp_kn(testcode,code+vergleichsanfang,fuenfecke))<0) return(0);
3100 if (test>0) return(1);
3101 vergleichsanfang+=fuenfecke;
3102 anfang=suchestart_reko_sp( startkante3, &fuenfecke);
3103 reko_patch_sp(anfang,testcode,fuenfecke);
3104 if ((test=codecmp_kn(testcode,code+vergleichsanfang,fuenfecke))<0) return(0);
3105 if (test==0) return(2);
3106
3107 return(1);
3108 }
3109
3110
3111
3112 /***********************SANDWICH_REKO*******************************/
3113
3114 /* berechnet den minimalen Code, der sich aus dem bei "anfangskante"
3115 beginnenden Sandwich ergibt */
3116 /* TH: Die Funktion wurde so geaendert, dass sie
3117 0 zurueckgibt, wenn code > minimaler Code (wie bisher)
3118 1 zurueckgibt, wenn code < minimaler Code (wie bisher)
3119 2 zurueckgibt, wenn code== minimaler Code (Automorphismus existiert) */
3120
sandwich_reko(PLANMAP map,KNOTENTYP * code,KANTE * anfangskante)3121 int sandwich_reko(PLANMAP map,KNOTENTYP *code,KANTE *anfangskante)
3122 {
3123 int i,j, l1, l2, l1_p_l2, fuenfecke, vergleichsanfang, test;
3124 KANTE *run, *startkante1, *startkante2, *startkante3, *anfang;
3125 KNOTENTYP testcode[6];
3126
3127
3128 l1=code[2]; l2=code[3];
3129 l1_p_l2 = l1+l2;
3130
3131 for (i=1; i<=map[0][0].name; i++) for (j=0;j<3; j++) { map[i][j].dummy=map[i][j].noleft=0;
3132 map[i][j].mininame=1; }
3133
3134 /* markieren der Brille: */
3135
3136 anfangskante->mininame=anfangskante->noleft=anfangskante->invers->noleft=1;
3137 anfangskante->invers->mininame=l1_p_l2;
3138
3139 for (i=1, run=anfangskante; i<code[0]; i++)
3140 { run=run->invers->prev;
3141 run->noleft=run->invers->noleft=1;
3142 run->mininame=i+1;
3143 run->dummy=run->prev->dummy=run->next->dummy=i;
3144 run->invers->mininame=i;
3145 if (i != l1_p_l2) run->prev->mininame=aussen;
3146 i++;
3147 if (i<code[0])
3148 {
3149 run=run->invers->next;
3150 run->noleft=run->invers->noleft=1;
3151 run->dummy=run->prev->dummy=run->next->dummy=i;
3152 run->mininame=i+1;
3153 run->invers->mininame=i;
3154 if (i != l1_p_l2) run->next->mininame=aussen;
3155 }
3156 }
3157
3158 /* reparieren: */ run->mininame=l1;
3159
3160 /* l1 ist immer >= 3, also geht das folgende: */
3161
3162 if (l1_p_l2%2) { startkante1=anfangskante->invers->next;
3163 startkante3=startkante1->next->invers->prev;
3164 if (l2>1) startkante2=anfangskante->prev->invers->next;
3165 else /* dann ist l3 > 1 */
3166 startkante2=anfangskante->next->invers->prev; }
3167 else
3168 { startkante3=anfangskante->invers->next;
3169 startkante1=startkante3->next->invers->prev;
3170 if (l2>1) startkante2=anfangskante->next->invers->prev;
3171 else /* dann ist l3 > 1 */
3172 startkante2=anfangskante->prev->invers->next; }
3173
3174
3175 vergleichsanfang=4;
3176 anfang=suchestart_reko( startkante1, &fuenfecke);
3177 reko_patch(anfang,testcode,fuenfecke);
3178 if ((test=codecmp_kn(testcode,code+vergleichsanfang,fuenfecke))<0) return(0);
3179 if (test>0) return(1);
3180 vergleichsanfang+=fuenfecke;
3181 anfang=suchestart_reko( startkante2, &fuenfecke);
3182 reko_patch(anfang,testcode,fuenfecke);
3183 if ((test=codecmp_kn(testcode,code+vergleichsanfang,fuenfecke))<0) return(0);
3184 if (test>0) return(1);
3185 vergleichsanfang+=fuenfecke;
3186 anfang=suchestart_reko( startkante3, &fuenfecke);
3187 reko_patch(anfang,testcode,fuenfecke);
3188 if ((test=codecmp_kn(testcode,code+vergleichsanfang,fuenfecke))<0) return(0);
3189 if (test==0) return(2);
3190 return(1);
3191 }
3192
3193
3194 /***********************SANDWICH_REKO_SP*******************************/
3195
3196 /* berechnet den minimalen Code, der sich aus dem bei "anfangskante"
3197 beginnenden Sandwich ergibt, wenn man es spiegelt */
3198 /* TH: Die Funktion wurde so geaendert, dass sie
3199 0 zurueckgibt, wenn code > minimaler Code (wie bisher)
3200 1 zurueckgibt, wenn code < minimaler Code (wie bisher)
3201 2 zurueckgibt, wenn code== minimaler Code (Automorphismus existiert) */
3202
sandwich_reko_sp(PLANMAP map,KNOTENTYP * code,KANTE * anfangskante)3203 int sandwich_reko_sp(PLANMAP map,KNOTENTYP *code,KANTE *anfangskante)
3204 {
3205 int i,j, l1, l2, l1_p_l2, fuenfecke, vergleichsanfang, test;
3206 KANTE *run, *startkante1, *startkante2, *startkante3, *anfang;
3207 KNOTENTYP testcode[6];
3208
3209
3210 l1=code[2]; l2=code[3];
3211 l1_p_l2 = l1+l2;
3212
3213 for (i=1; i<=map[0][0].name; i++) for (j=0;j<3; j++) { map[i][j].dummy=map[i][j].noright=0;
3214 map[i][j].mininame=1; }
3215
3216 /* markieren der Brille: */
3217
3218 anfangskante->mininame=anfangskante->noright=anfangskante->invers->noright=1;
3219 anfangskante->invers->mininame=l1_p_l2;
3220
3221 for (i=1, run=anfangskante; i<code[0]; i++)
3222 { run=run->invers->next;
3223 run->noright=run->invers->noright=1;
3224 run->mininame=i+1;
3225 run->dummy=run->prev->dummy=run->next->dummy=i;
3226 run->invers->mininame=i;
3227 if (i != l1_p_l2) run->next->mininame=aussen;
3228 i++;
3229 if (i<code[0])
3230 {
3231 run=run->invers->prev;
3232 run->noright=run->invers->noright=1;
3233 run->dummy=run->prev->dummy=run->next->dummy=i;
3234 run->mininame=i+1;
3235 run->invers->mininame=i;
3236 if (i != l1_p_l2) run->prev->mininame=aussen;
3237 }
3238 }
3239
3240 /* reparieren: */ run->mininame=l1;
3241
3242 /* l1 ist immer >= 3, also geht das folgende: */
3243
3244 if (l1_p_l2%2) { startkante1=anfangskante->invers->prev;
3245 startkante3=startkante1->prev->invers->next;
3246 if (l2>1) startkante2=anfangskante->next->invers->prev;
3247 else /* dann ist l3 > 1 */
3248 startkante2=anfangskante->prev->invers->next; }
3249 else
3250 { startkante3=anfangskante->invers->prev;
3251 startkante1=startkante3->prev->invers->next;
3252 if (l2>1) startkante2=anfangskante->prev->invers->next;
3253 else /* dann ist l3 > 1 */
3254 startkante2=anfangskante->next->invers->prev; }
3255
3256
3257 vergleichsanfang=4;
3258 anfang=suchestart_reko_sp( startkante1, &fuenfecke);
3259 reko_patch_sp(anfang,testcode,fuenfecke);
3260 if ((test=codecmp_kn(testcode,code+vergleichsanfang,fuenfecke))<0) return(0);
3261 if (test>0) return(1);
3262 vergleichsanfang+=fuenfecke;
3263 anfang=suchestart_reko_sp( startkante2, &fuenfecke);
3264 reko_patch_sp(anfang,testcode,fuenfecke);
3265 if ((test=codecmp_kn(testcode,code+vergleichsanfang,fuenfecke))<0) return(0);
3266 if (test>0) return(1);
3267 vergleichsanfang+=fuenfecke;
3268 anfang=suchestart_reko_sp( startkante3, &fuenfecke);
3269 reko_patch_sp(anfang,testcode,fuenfecke);
3270 if ((test=codecmp_kn(testcode,code+vergleichsanfang,fuenfecke))<0) return(0);
3271 if (test==0) return(2);
3272
3273 return(1);
3274 }
3275
3276
3277
3278 /*********************bilde_f*****TH***********************************/
3279
3280 /* Die Funktion bilde_f bildet den kompletten Automorphismus f, der
3281 die Kante k1 in die Kante k2 ueberfuehrt. Dabei muss der Automorphismus
3282 ordnungserhaltend sein, es muss sich also um eine Drehung handeln.
3283 Das Fulleren, auf dem der Automorphismus berechnet wird, besitzt anz
3284 Ecken. Es wird ein einfacher Backtrackingalgorithmus verwendet.
3285 Bei der Anwendung dieser Funktion ist nicht der gesamte Automorphismus
3286 interessant, sondern nur eine Auswahl von Ecken, deren Bilder errechnet
3287 werden sollen. Versuche, durch eine geschickte Auswahl der Ecken,
3288 deren Bildpunkte errechnet werden, eine Laufzeitverbesserung zu erhalten,
3289 schlagen fehl. */
3290
3291 /* Die folgende Prozedur enthaelt den Rekursionsschritt */
3292
bilde_f_rek(KNOTENTYP * f,KANTE * k1,KANTE * k2)3293 void bilde_f_rek(KNOTENTYP *f, KANTE *k1, KANTE *k2) {
3294 KNOTENTYP u;
3295 k1 = k1->invers->prev;
3296 k2 = k2->invers->prev; /* k1 und k2 im Gleichschritt nach rechts */
3297 u = k1->name; /* von u wird der Funktionswert f[u] berechnet */
3298 if (!(f[u])) { /* Funktionswert noch nicht bekannt */
3299 f[u] = k2->name;
3300 bilde_f_rek(f,k1,k2); /* von u ausgehend weitere Funktionswerte ermitteln */
3301 }
3302 k1 = k1->prev; /* k1 und k2 im Gleichschritt nach links */
3303 k2 = k2->prev; /* denn: (k->invers->prev)->prev = k->invers->next */
3304 u = k1->name;
3305 if (!(f[u])) {
3306 f[u] = k2->name;
3307 bilde_f_rek(f,k1,k2);
3308 }
3309 }
3310
3311 /* Die folgende Prozedur enthaelt den Rekursionsanfang */
3312
bilde_f(KNOTENTYP * f,KANTE * k1,KANTE * k2,KNOTENTYP anz)3313 void bilde_f(KNOTENTYP *f, KANTE *k1, KANTE *k2, KNOTENTYP anz) {
3314 KNOTENTYP i;
3315 for (i=1; i<=anz; i++) {f[i] = 0;} /* Funktionstabelle loeschen */
3316 f[k1->ursprung] = k2->ursprung;
3317 f[k1->name] = k2->name; /* k1 wird auf k2 abgebildet */
3318 bilde_f_rek(f,k1,k2);
3319 }
3320
3321 /*********************bilde_f_sp*****TH***********************************/
3322
3323 /* Die Funktion bilde_f_sp bildet den kompletten Automorphismus f, der
3324 die Kante k1 in die Kante k2 ueberfuehrt. Dabei darf der Automorphismus
3325 NICHT ordnungserhaltend sein, es muss sich also um eine Spiegelung oder
3326 Drehspiegelung handeln. Dies ist der einzige Unterschied zu bilde_f. */
3327
3328 /* Die folgende Prozedur enthaelt den Rekursionsschritt */
3329
bilde_f_sp_rek(KNOTENTYP * f,KANTE * k1,KANTE * k2)3330 void bilde_f_sp_rek(KNOTENTYP *f, KANTE *k1, KANTE *k2) {
3331 KNOTENTYP u;
3332 k1 = k1->invers->prev;
3333 k2 = k2->invers->next; /* k1 und k2 spiegelverkehrt nach rechts und links */
3334 u = k1->name; /* von u wird der Funktionswert f[u] berechnet */
3335 if (!(f[u])) { /* Funktionswert noch nicht bekannt */
3336 f[u] = k2->name;
3337 bilde_f_sp_rek(f,k1,k2); /* von u ausgehend weitere Funktionswerte ermitteln */
3338 }
3339 k1 = k1->prev; /* k1 und k2 spiegelverkehrt nach links und rechts */
3340 k2 = k2->next; /* denn: (k->invers->next)->next = k->invers->prev */
3341 u = k1->name;
3342 if (!(f[u])) {
3343 f[u] = k2->name;
3344 bilde_f_sp_rek(f,k1,k2);
3345 }
3346 }
3347
3348 /* Die folgende Prozedur enthaelt den Rekursionsanfang */
3349
bilde_f_sp(KNOTENTYP * f,KANTE * k1,KANTE * k2,KNOTENTYP anz)3350 void bilde_f_sp(KNOTENTYP *f, KANTE *k1, KANTE *k2, KNOTENTYP anz) {
3351 KNOTENTYP i;
3352 for (i=1; i<=anz; i++) {f[i] = 0;} /* Funktionstabelle loeschen */
3353 f[k1->ursprung] = k2->ursprung;
3354 f[k1->name] = k2->name; /* k1 wird auf k2 abgebildet */
3355 bilde_f_sp_rek(f,k1,k2);
3356 }
3357
3358
3359 /*********************bilde_f_und_g_sp*****TH***********************************/
3360
3361 /* Die Funktion bilde_f_und_g_sp bildet die komplette Funktion f, die die Kante
3362 k1 in die Kante k2 ueberfuehrt, und simultan die Funktion g, die die Kante
3363 k2 in die Kante k1 ueberfuehrt. Beide Funktionen sind NICHT ordnungserhaltend.
3364 Die Funktion prueft, ob g die Umkehrfunktion von f ist. Ist sie es, so liefert
3365 bild_f_und_g_sp den Wert 1, andernfalls den Wert 0.
3366 Das Fulleren, auf dem die Funktion berechnet wird, besitzt anz Ecken.
3367 Die Inhalte des Arrays g, die in der vorliegenden Funktion berechnet werden,
3368 werden in der uebergeordneten Prozedur minitest nicht gebraucht. Deshalb waere es
3369 eigentlich nicht notwendig, einen Zeiger auf dieses Array zu uebergeben. Es wuerde
3370 ausreichen, das Array innerhalb der Funktion bilde_f_und_g_sp lokal zu definieren.
3371 Da die Funktion aber haeufig aufgerufen wird, wuerde dies viel Zeit in Anspruch
3372 nehmen. */
3373
3374 /* Die folgende Prozedur enthaelt den Rekursionsschritt */
3375
bilde_f_und_g_sp_rek(KNOTENTYP * f,KNOTENTYP * g,KANTE * k1,KANTE * k2)3376 BOOL bilde_f_und_g_sp_rek(KNOTENTYP *f, KNOTENTYP *g, KANTE *k1, KANTE *k2) {
3377 KNOTENTYP u,v;
3378 k1 = k1->invers->prev;
3379 k2 = k2->invers->next; /* k1 und k2 spiegelverkehrt nach rechts und links */
3380 u = k1->name; /* von u wird der Funktionswert f[u] berechnet */
3381 v = k2->name;
3382 if (!(f[u])) { /* Funktionswert noch nicht bekannt */
3383 f[u] = v;
3384 if (g[v]) {return(0);} /* Widerspruch gefunden */
3385 g[v] = u;
3386 if (!bilde_f_und_g_sp_rek(f,g,k1,k2)) {return(0);} /* weitere Funktionswerte: Widerspruch? */
3387 }
3388 else {
3389 if (!(g[v])) {return(0);} /* Widerspruch gefunden. Diese Abfrage koennte aber auch
3390 entfallen, denn wenn ein Wert von g noch nicht festgelegt
3391 ist, obwohl der zugehoerige Wert von f bereits feststeht, so wird an anderer Stelle ein
3392 Wert von g zuviel festgelegt sein, obwohl der zugehoerige Wert von f noch nicht feststeht */
3393 }
3394 k1 = k1->prev; /* k1 und k2 spiegelverkehrt nach links und rechts */
3395 k2 = k2->next; /* denn: (k->invers->next)->next = k->invers->prev */
3396 u = k1->name;
3397 v = k2->name;
3398 if (!(f[u])) {
3399 f[u] = v;
3400 if (g[v]) {return(0);}
3401 g[v] = u;
3402 if (!bilde_f_und_g_sp_rek(f,g,k1,k2)) {return(0);}
3403 }
3404 else {
3405 if (!(g[v])) {return(0);}
3406 }
3407 return(1); /* keinen Widerspruch festgestellt */
3408 }
3409
3410 /* Die folgende Prozedur enthaelt den Rekursionsanfang */
3411
bilde_f_und_g_sp(KNOTENTYP * f,KNOTENTYP * g,KANTE * k1,KANTE * k2,KNOTENTYP anz)3412 BOOL bilde_f_und_g_sp(KNOTENTYP *f, KNOTENTYP *g, KANTE *k1, KANTE *k2, KNOTENTYP anz) {
3413 KNOTENTYP i;
3414 for (i=1; i<=anz; i++) {f[i]=0; g[i]=0;} /* Funktionstabellen loeschen */
3415 f[k1->ursprung] = k2->ursprung;
3416 f[k1->name] = k2->name; /* f: k1 wird auf k2 abgebildet */
3417 g[k2->ursprung] = k1->ursprung;
3418 g[k2->name] = k1->name; /* g: k2 wird auf k1 abgebildet */
3419 return(bilde_f_und_g_sp_rek(f,g,k1,k2));
3420 }
3421
3422 /*********************bilde_f_und_g********TH***********************************/
3423
3424 /* Die Funktion bilde_f_und_g bildet die komplette Funktion f, die die Kante
3425 k1 in die Kante k2 ueberfuehrt, und simultan die Funktion g, die die Kante
3426 k2 in die Kante k1 ueberfuehrt. Beide Funktionen sind ordnungserhaltend.
3427 Die Funktion prueft, ob g die Umkehrfunktion von f ist. Ist sie es, so liefert
3428 bild_f_und_g den Wert 1, andernfalls den Wert 0.
3429 Weitere Anmerkungen siehe bilde_f_und_g_sp. */
3430
3431 /* Die folgende Prozedur enthaelt den Rekursionsschritt */
3432
bilde_f_und_g_rek(KNOTENTYP * f,KNOTENTYP * g,KANTE * k1,KANTE * k2)3433 BOOL bilde_f_und_g_rek(KNOTENTYP *f, KNOTENTYP *g, KANTE *k1, KANTE *k2) {
3434 KNOTENTYP u,v;
3435 k1 = k1->invers->prev;
3436 k2 = k2->invers->prev; /* k1 und k2 im Gleichschritt nach rechts und links */
3437 u = k1->name; /* von u wird der Funktionswert f[u] berechnet */
3438 v = k2->name;
3439 if (!(f[u])) { /* Funktionswert noch nicht bekannt */
3440 f[u] = v;
3441 if (g[v]) {return(0);} /* Widerspruch gefunden */
3442 g[v] = u;
3443 if (!bilde_f_und_g_rek(f,g,k1,k2)) {return(0);} /* weitere Funktionswerte: Widerspruch? */
3444 }
3445 else {
3446 if (!(g[v])) {return(0);} /* Widerspruch gefunden. Diese Abfrage koennte aber auch
3447 entfallen, denn wenn ein Wert von g noch nicht festgelegt
3448 ist, obwohl der zugehoerige Wert von f bereits feststeht, so wird an anderer Stelle ein
3449 Wert von g zuviel festgelegt sein, obwohl der zugehoerige Wert von f noch nicht feststeht */
3450 }
3451 k1 = k1->prev; /* k1 und k2 spiegelverkehrt nach links und rechts */
3452 k2 = k2->prev; /* denn: (k->invers->prev)->prev = k->invers->next */
3453 u = k1->name;
3454 v = k2->name;
3455 if (!(f[u])) {
3456 f[u] = v;
3457 if (g[v]) {return(0);}
3458 g[v] = u;
3459 if (!bilde_f_und_g_rek(f,g,k1,k2)) {return(0);}
3460 }
3461 else {
3462 if (!(g[v])) {return(0);}
3463 }
3464 return(1); /* keinen Widerspruch festgestellt */
3465 }
3466
3467 /* Die folgende Prozedur enthaelt den Rekursionsanfang */
3468
bilde_f_und_g(KNOTENTYP * f,KNOTENTYP * g,KANTE * k1,KANTE * k2,KNOTENTYP anz)3469 BOOL bilde_f_und_g(KNOTENTYP *f, KNOTENTYP *g, KANTE *k1, KANTE *k2, KNOTENTYP anz) {
3470 KNOTENTYP i;
3471 for (i=1; i<=anz; i++) {f[i]=0; g[i]=0;} /* Funktionstabellen loeschen */
3472 f[k1->ursprung] = k2->ursprung;
3473 f[k1->name] = k2->name; /* f: k1 wird auf k2 abgebildet */
3474 g[k2->ursprung] = k1->ursprung;
3475 g[k2->name] = k1->name; /* g: k2 wird auf k1 abgebildet */
3476 return(bilde_f_und_g_rek(f,g,k1,k2));
3477 }
3478
3479
3480 /************************MINITEST***********TH***************************/
3481
minitest(PLANMAP map,KNOTENTYP * code)3482 int minitest(PLANMAP map, KNOTENTYP *code)
3483
3484 /* WICHTIG: Bei der bauchbinde muss auch ueberprueft werden, ob sie wirklich
3485 minimal gebaut ist. Moeglich: Verdrehen und hinterher ist das Spiegelbild
3486 mit der gleichen Binde kleiner verklebt. (Beispiele schon mit 32 Knoten)
3487
3488 Hier werden nur Pfade betrachtet, an denen mindestens ein 5-Eck liegt.
3489
3490 Zu einer 5-Eck-Kante gehoert der Pfad, der entsteht, wenn man zur vorigen
3491 Kante (prev) geht und dann wechselnd weiter, bis es nicht mehr geht (d.h. man
3492 muesste eine bereits benutzte Kante nochmal benutzen). (Eigentlich gehoert er zu
3493 dem Winkel aud dieser und der vorigen Kante des 5-Ecks.) Dann geht man in die andere
3494 Richtung weiter, bis es nicht mehr geht. Aber auch in der anderen Reihenfolge
3495 muss der Pfad konstruiert werden, da die Orientierung schon durch andere
3496 Festlegungen bestimmt wurde.
3497
3498 Akzeptiert werden nur Graphen, bei denen der Weg zu einem 5-Eck korrespondiert,
3499 d.h. aus einer 5-Eck-Kante konstruiert werden kann (im normal ODER im
3500 Spiegel-modus). Jeder Graph hat so einen Weg. Fuer die Minimalitaet werden
3501 auch nur solche Pfade betrachtet. Das ist etwas anderes, als dass nur ein 5-Eck
3502 am Weg liegt. (BSP: Sandwich mit 5-Eck am Stueck l2.)
3503
3504
3505 Obwohl viele Pfade sowohl in normalem, als auch im Mirror-Modus konstruiert
3506 werden koennen, gibt es auch Pfade, die nur in einem Modus konstruiert
3507 werden koennen.
3508
3509
3510 /<
3511 Kante/ \
3512 / \
3513 < --------------> dazugehoerige erste Richtung
3514
3515
3516 Anmerkung: Wenn eine 5-Eck-Kante zu einem Endpunkt des Pfades fuehrt, so hat dasselbe
3517 Fuenfeck auch einen Winkel mit dem Pfad gemeinsam (sonst haette man eine Bauchbinde).
3518
3519 */
3520
3521
3522 {
3523 int i, j, ii, m_laenge, ms_laenge, knoten_auf_pfad;
3524 int l1, l2, l3, ll1, ll2, ll3, edgemark, middle, lower_border;
3525 KANTE *miniliste[120], *mini_spiegel[120];
3526 KANTE *run, *start, *merke_1, *merke_2;
3527 long mark[N+1];
3528 int zaehler, stelle_1, stelle_2, pfadlaenge;
3529 KNOTENTYP cpcode[20];
3530 int test, runzaehler;
3531 BOOL rekonstruiert;
3532 int minierg[120]; /* fuer Bauchbinden */
3533
3534 rekonstruiert=0;
3535 if (code[1]==1) knoten_auf_pfad=code[0]; else knoten_auf_pfad=code[0]-1;
3536 /* die knoten auf dem Pfad sind immer mit 1..k_a_p nummeriert */
3537
3538
3539 test=1;
3540 m_laenge=ms_laenge=0;
3541
3542 for (i=1; i<=map[0][0].name; i++) { mark[i]=0;
3543 for(j=0;j<3;j++)
3544 { run=map[i]+j;
3545 run->dummy=run->mininame=0;
3546 }
3547 }
3548
3549
3550 l1=code[2];
3551 if (code[1]==2) { l3=code[3]; l2=code[0]-l1-l3; }
3552 else { l2=code[3]; l3=code[0]-l1-l2; }
3553
3554 if (code[1]==1) { rekonstruiert=1; /* Bei bauchbinden ist das immer der Fall */
3555 for (i=0; (i<60); i++)
3556 { run=F_eck_kanten[i];
3557 run->nostart=run->mirror_nostart=0; }
3558 }
3559 else if (code[1]==2) /* muss irgendwo am Pfad liegen */
3560 { for (i=0; (i<60) && !rekonstruiert; i++)
3561 { run=F_eck_kanten[i];
3562 if (run->ursprung <= knoten_auf_pfad) rekonstruiert=1;
3563 run->nostart=run->mirror_nostart=0; }
3564 for (; i<60 ; i++) { run=F_eck_kanten[i];
3565 run->nostart=run->mirror_nostart=0; }
3566 }
3567 else /* d.h. code[1]==3 -- also sandwich */
3568 { for (i=0; (i<60) && !rekonstruiert; i++)
3569 { run=F_eck_kanten[i];
3570 if (run->ursprung <= knoten_auf_pfad)
3571 {
3572 if (run->prev->name==run->ursprung-1)
3573 {
3574 if ((run->ursprung <=l1) || (run->ursprung >= l1+l2)) rekonstruiert=1;
3575 else { if (run->prev->name==l1)
3576 { if ((l2+l3) % 2) rekonstruiert=1; }
3577 else
3578 if (run->name==l1+l2)
3579 { if ((l1+l2) % 2) rekonstruiert=1; }
3580 }
3581 } /* ende "die beiden kanten liegen in laufrichtung */
3582 else
3583 if (run->prev->name==run->ursprung+1) /* d.h. entgegen der Laufrichtung */
3584 { if ((run->ursprung <=l1) || (run->ursprung >= l1+l2)) rekonstruiert=1;
3585 else { if (run->prev->name==l1+l2)
3586 { if ((l1+l2) % 2) rekonstruiert=1; }
3587 else
3588 if (run->name==l1)
3589 { if ((l2+l3) % 2) rekonstruiert=1; }
3590 }
3591 } /* ende "die beiden kanten liegen entgegen der laufrichtung */
3592 } /* ende if auf pfad */
3593 run->nostart=run->mirror_nostart=0; } /* ende for */
3594 for (; i<60 ; i++) { run=F_eck_kanten[i];
3595 run->nostart=run->mirror_nostart=0; }
3596 } /* ende sandwich */
3597
3598
3599 if (!rekonstruiert) { return(0); }
3600
3601
3602 /* Jetzt die Kanten markieren, bei denen man den Originalpfad rekonstruieren wuerde,
3603 dabei werden 6-Eck-Kanten einfach mitmarkiert */
3604 if (code[1]!=1)
3605 {
3606 /* Von stelle_1 bis ende kann in Richtung auf 1 rekonstruiert werden. Von 1 bis stelle_2 kann in Richtung
3607 aufs ende rekonstruiert werden. Die stellen geben die position des valenz 2 knotens in dem
3608 winkel an. Beachten: bei "invers" ist der valenz-2-knoten immer um eins groesser ? */
3609
3610
3611 if (code[1]==2) { if (l1%2) stelle_1=l1-1; else stelle_1=l1;
3612 if (l3%2) stelle_2=l1+l2+1; else stelle_2=l1+l2; }
3613 else /* d.h. sandwich */
3614 { if ((l1+l2)%2) stelle_1=l1+l2-1; else stelle_1=l1+l2;
3615 if ((l2+l3)%2) stelle_2=l1+1; else stelle_2=l1; }
3616
3617 map[1][0].nostart=1;
3618 for (run=map[1][2].invers->next, zaehler=2; zaehler < code[0]; zaehler+=2)
3619 { if (zaehler<=stelle_2) { run->mirror_nostart=1;
3620 if (zaehler<stelle_2) run->invers->nostart=1; }
3621 if (zaehler>=stelle_1-1)
3622 { if (zaehler>=stelle_1) run->nostart=1;
3623 if (zaehler<knoten_auf_pfad) run->invers->mirror_nostart=1; }
3624 run=run->invers->prev->invers->next;
3625 }
3626
3627 /* Da jetzt aber die letzte Kante nicht als Startkante markiert werden kann, da dieser Pfad ja nicht
3628 mehr konstruiert wird, muss das nachgeholt werden: */
3629 if (l1==l3)
3630 { if (knoten_auf_pfad % 2) { mini_spiegel[0]=map[knoten_auf_pfad][2].invers; ms_laenge=1; }
3631 else { miniliste[0]=map[knoten_auf_pfad][1].invers; m_laenge=1; }
3632 }
3633 }
3634
3635
3636 /* Jetzt ans konstruieren: */
3637
3638 edgemark=1;
3639
3640 for (i=0; i<60; i++) /* for ueber alle kanten, von denen links ein 5-Eck ist */
3641 {
3642 start=F_eck_kanten[i];
3643
3644 if (! start->nostart)
3645 {
3646 middle= 2*N*edgemark;
3647 lower_border=middle-N;
3648
3649 mark[start->ursprung]=middle;
3650 runzaehler=middle-1;
3651
3652 start->dummy=start->invers->dummy=edgemark;
3653 run=start->prev;
3654 run->dummy=run->invers->dummy=edgemark;
3655 run=run->invers->next;
3656 pfadlaenge=2;
3657
3658 /* nach rechts laufen: */
3659 while (run->dummy < edgemark) /* neue kante */
3660 { mark[run->ursprung]=runzaehler; runzaehler--;
3661 pfadlaenge++;
3662 run->dummy=run->invers->dummy=edgemark;
3663 merke_1=run; /* letzte neue kante */
3664 run=run->invers->prev;
3665 if (run->dummy < edgemark)
3666 { mark[run->ursprung]=runzaehler; runzaehler--;
3667 pfadlaenge++;
3668 run->dummy=run->invers->dummy=edgemark;
3669 merke_1=run;
3670 run=run->invers->next; }
3671 }
3672
3673 /* nach links laufen: */
3674
3675 run=start->invers->prev;
3676 runzaehler=middle+1;
3677 if (mark[run->ursprung]<lower_border) mark[run->ursprung]=runzaehler;
3678 /* kann (z.b. bei bauchbinde) vor der schleife noetig
3679 sein */
3680 merke_2=start;
3681 while (run->dummy < edgemark) /* neue kante */
3682 { mark[run->ursprung]=runzaehler; runzaehler++;
3683 pfadlaenge++;
3684 run->dummy=run->invers->dummy=edgemark;
3685 merke_2=run; /* letzte neue kante */
3686 run=run->invers->next;
3687 if (run->dummy < edgemark)
3688 { mark[run->ursprung]=runzaehler; runzaehler++;
3689 pfadlaenge++;
3690 run->dummy=run->invers->dummy=edgemark;
3691 merke_2=run;
3692 run=run->invers->prev; }
3693 }
3694
3695 /* Jetzt auswerten, was fuer ein pfad gebaut wurde */
3696
3697 if (pfadlaenge<code[0]) return(0);
3698 cpcode[0]=pfadlaenge;
3699 if (merke_1==merke_2->invers->prev->invers) cpcode[1]=1;
3700 else if (mark[merke_1->name]<mark[merke_2->name]) cpcode[1]=2;
3701 else cpcode[1]=3;
3702
3703
3704 /* zuerst zum markieren der in zukunft nicht mehr zu testenden Kanten (Winkel): */
3705 switch(cpcode[1])
3706 {
3707 case 1: {
3708 for (j=0, run=start; j<pfadlaenge; j+=2)
3709 { run->nostart=run->mirror_nostart=1;
3710 run=run->invers;
3711 run->nostart=run->mirror_nostart=1;
3712 run=run->prev->invers->next; }
3713 break;
3714 }
3715 case 2: { ll1=mark[merke_1->name]-mark[merke_1->ursprung]+1;
3716 ll3=mark[merke_2->ursprung]-mark[merke_2->name]+1;
3717 if (ll1 >= ll3) { cpcode[2]=ll1; cpcode[3]=ll3; }
3718 else { cpcode[2]=ll3; cpcode[3]=ll1; }
3719 if (ll1%2) stelle_1=mark[merke_1->name]-1; else stelle_1=mark[merke_1->name];
3720 if (ll3%2) stelle_2=mark[merke_2->name]+1; else stelle_2=mark[merke_2->name];
3721 break; }
3722 case 3: { ll1=mark[merke_2->name]-mark[merke_1->ursprung]+1;
3723 ll3=mark[merke_2->ursprung]-mark[merke_1->name]+1;
3724 ll2=pfadlaenge-ll1-ll3;
3725 if (ll1>=ll3) { cpcode[2]=ll1; cpcode[3]=ll2; }
3726 else { cpcode[2]=ll3; cpcode[3]=ll2; }
3727 if ((ll1+ll2)%2) stelle_1=mark[merke_1->name]-1; else stelle_1=mark[merke_1->name];
3728 if ((ll2+ll3)%2) stelle_2=mark[merke_2->name]+1; else stelle_2=mark[merke_2->name];
3729 break; }
3730 default: { fprintf(stderr,"Dangerous error in switch (minitest) !\n"); exit(34); }
3731 } /* ende switch */
3732
3733
3734 if (cpcode[1]==1) { if ((test=codecmp_kn(code,cpcode,2))>0) return(0); }
3735 else { if ((test=codecmp_kn(code,cpcode,4))>0) return(0); }
3736
3737
3738 if (code[1]!=1) /* fuer bauchbinden wurde in switch schon markiert */
3739 {
3740 /* Von stelle_1 bis ende kann in Richtung auf den Anfang rekonstruiert werden. Von 1 bis stelle_2 kann
3741 in Richtung aufs ende rekonstruiert werden */
3742
3743 if (mark[merke_1->ursprung]%2)
3744 { merke_1->nostart=1;
3745 for (run=merke_1->prev->invers->next, zaehler=mark[merke_1->ursprung]+1;
3746 zaehler <= mark[merke_2->ursprung]; zaehler+=2)
3747 { if (zaehler<=stelle_2) { run->mirror_nostart=1;
3748 if (zaehler<stelle_2) run->invers->nostart=1; }
3749 if (zaehler>=stelle_1-1) { if (zaehler>=stelle_1) run->nostart=1;
3750 if (zaehler<mark[merke_2->ursprung]) run->invers->mirror_nostart=1; }
3751 run=run->invers->prev->invers->next;
3752 }
3753 }
3754 else /* d.h. mark[merke_1->ursprung] gerade */
3755 {
3756 for (run=merke_1->next, zaehler=mark[merke_1->ursprung];
3757 zaehler <= mark[merke_2->ursprung]; zaehler+=2)
3758 { if (zaehler<=stelle_2) { run->mirror_nostart=1;
3759 if (zaehler<stelle_2) run->invers->nostart=1; }
3760 if (zaehler>=stelle_1-1) { if (zaehler>=stelle_1) run->nostart=1;
3761 if (zaehler<mark[merke_2->ursprung]) run->invers->mirror_nostart=1; }
3762 run=run->invers->prev->invers->next;
3763 }
3764 }
3765 } /* ende code[1] != 1 und damit ende des markierens */
3766
3767 /* jetzt eventuell neue Kanten in die Listen: */
3768 if (test==0)
3769 {
3770 if (code[1]==1) { miniliste[m_laenge]=start; m_laenge++; }
3771 else { if (ll1>=ll3)
3772 { if (mark[merke_1->ursprung]%2)
3773 { miniliste[m_laenge]=merke_1->invers; m_laenge++; }
3774 else
3775 { mini_spiegel[ms_laenge]=merke_1->invers; ms_laenge++; }
3776 }
3777 if (ll3>=ll1)
3778 { if (mark[merke_2->ursprung]%2)
3779 { mini_spiegel[ms_laenge]=merke_2->invers; ms_laenge++; }
3780 else
3781 { miniliste[m_laenge]=merke_2->invers; m_laenge++; }
3782 }
3783 } /* ende else */
3784 }
3785 edgemark++;
3786 } /* ende if (!start->nostart) */
3787
3788
3789
3790 /* nun in die andere Richtung zuerst */
3791
3792
3793 if (! start->mirror_nostart)
3794 {
3795
3796 middle= 2*N*edgemark;
3797 lower_border=middle-N;
3798
3799 mark[start->ursprung]=middle;
3800 runzaehler=middle-1;
3801
3802 start->dummy=start->invers->dummy=edgemark;
3803 run=start->prev;
3804 run->dummy=run->invers->dummy=edgemark;
3805 pfadlaenge=2;
3806
3807 /* nach links laufen: */
3808 run=start->invers->prev;
3809 while (run->dummy < edgemark) /* neue kante */
3810 { mark[run->ursprung]=runzaehler; runzaehler--;
3811 pfadlaenge++;
3812 run->dummy=run->invers->dummy=edgemark;
3813 merke_1=run; /* letzte neue kante */
3814 run=run->invers->next;
3815 if (run->dummy < edgemark)
3816 { mark[run->ursprung]=runzaehler; runzaehler--;
3817 pfadlaenge++;
3818 run->dummy=run->invers->dummy=edgemark;
3819 merke_1=run;
3820 run=run->invers->prev; }
3821 }
3822
3823 /* nach rechts laufen: */
3824
3825 run=start->prev->invers->next;
3826 runzaehler=middle+1;
3827 if (mark[run->ursprung]<lower_border) mark[run->ursprung]=runzaehler;
3828 /* kann (z.b. bei bauchbinde) vor der schleife noetig
3829 sein */
3830 merke_2=start->prev;
3831 while (run->dummy < edgemark) /* neue kante */
3832 { mark[run->ursprung]=runzaehler; runzaehler++;
3833 pfadlaenge++;
3834 run->dummy=run->invers->dummy=edgemark;
3835 merke_2=run; /* letzte neue kante */
3836 run=run->invers->prev;
3837 if (run->dummy < edgemark)
3838 { mark[run->ursprung]=runzaehler; runzaehler++;
3839 pfadlaenge++;
3840 run->dummy=run->invers->dummy=edgemark;
3841 merke_2=run;
3842 run=run->invers->next; }
3843 }
3844
3845 /* Jetzt auswerten, was fuer ein pfad gebaut wurde */
3846
3847 if (pfadlaenge<code[0]) return(0);
3848 cpcode[0]=pfadlaenge;
3849 if (merke_1==merke_2->invers->next->invers) cpcode[1]=1;
3850 else if (mark[merke_1->name]<mark[merke_2->name]) cpcode[1]=2;
3851 else cpcode[1]=3;
3852
3853 /* zuerst zum markieren der in zukunft nicht mehr zu testenden Kanten (Winkel): */
3854 switch(cpcode[1])
3855 {
3856 case 1: { fprintf(stderr,"ERROR: BAUCHBINDEN should not be possible in mirror modus \n");
3857 exit(35);
3858 break;
3859 }
3860 case 2: { ll1=mark[merke_1->name]-mark[merke_1->ursprung]+1;
3861 ll3=mark[merke_2->ursprung]-mark[merke_2->name]+1;
3862 if (ll1 >= ll3) { cpcode[2]=ll1; cpcode[3]=ll3; }
3863 else { cpcode[2]=ll3; cpcode[3]=ll1; }
3864 if (ll1%2) stelle_1=mark[merke_1->name]-1; else stelle_1=mark[merke_1->name];
3865 if (ll3%2) stelle_2=mark[merke_2->name]+1; else stelle_2=mark[merke_2->name];
3866 break; }
3867 case 3: { ll1=mark[merke_2->name]-mark[merke_1->ursprung]+1;
3868 ll3=mark[merke_2->ursprung]-mark[merke_1->name]+1;
3869 ll2=pfadlaenge-ll1-ll3;
3870 if (ll1>=ll3) { cpcode[2]=ll1; cpcode[3]=ll2; }
3871 else { cpcode[2]=ll3; cpcode[3]=ll2; }
3872 if ((ll1+ll2)%2) stelle_1=mark[merke_1->name]-1; else stelle_1=mark[merke_1->name];
3873 if ((ll2+ll3)%2) stelle_2=mark[merke_2->name]+1; else stelle_2=mark[merke_2->name];
3874 break; }
3875 default: { fprintf(stderr,"Dangerous error in switch (minitest mirror) !\n"); exit(36); }
3876 } /* ende switch */
3877
3878 if ((test=codecmp_kn(code,cpcode,4))>0) return(0);
3879
3880
3881 /* Von stelle_1 bis ende kann in Richtung auf den Anfang rekonstruiert werden. Von 1 bis stelle_2 kann
3882 in Richtung aufs ende rekonstruiert werden */
3883
3884 if ((mark[merke_1->ursprung]%2)==0) /* umgekehrter laufsinn als bei der anderen entwicklungsrichtung */
3885 { merke_1->nostart=1;
3886 for (run=merke_1->prev->invers->next, zaehler=mark[merke_1->ursprung]+1;
3887 zaehler <= mark[merke_2->ursprung]; zaehler+=2)
3888 { if (zaehler<=stelle_2) { run->mirror_nostart=1;
3889 if (zaehler<stelle_2) run->invers->nostart=1; }
3890 if (zaehler>=stelle_1-1) { if (zaehler>=stelle_1) run->nostart=1;
3891 if (zaehler<mark[merke_2->ursprung]) run->invers->mirror_nostart=1; }
3892 run=run->invers->prev->invers->next;
3893 }
3894 }
3895 else /* d.h. mark[merke_1->ursprung] ungerade */
3896 {
3897 for (run=merke_1->next, zaehler=mark[merke_1->ursprung];
3898 zaehler <= mark[merke_2->ursprung]; zaehler+=2)
3899 { if (zaehler<=stelle_2) { run->mirror_nostart=1;
3900 if (zaehler<stelle_2) run->invers->nostart=1; }
3901 if (zaehler>=stelle_1-1) { if (zaehler>=stelle_1) run->nostart=1;
3902 if (zaehler<mark[merke_2->ursprung]) run->invers->mirror_nostart=1; }
3903 run=run->invers->prev->invers->next;
3904 }
3905 }
3906 /* ende des markierens */
3907
3908 /* jetzt eventuell neue Kanten in die Listen: */
3909 if (test==0)
3910 { if (ll1>=ll3) /* jeweils vertauscht zum nicht-mirror-fall */
3911 { if (mark[merke_1->ursprung]%2)
3912 { mini_spiegel[ms_laenge]=merke_1->invers; ms_laenge++; }
3913 else
3914 { miniliste[m_laenge]=merke_1->invers; m_laenge++; }
3915 }
3916 if (ll3>=ll1)
3917 { if (mark[merke_2->ursprung]%2)
3918 { miniliste[m_laenge]=merke_2->invers; m_laenge++; }
3919 else
3920 { mini_spiegel[ms_laenge]=merke_2->invers; ms_laenge++; }
3921 }
3922 } /* ende test==0 */
3923 edgemark++;
3924 } /* ende if (!start->mirror_nostart) */
3925
3926 } /* ende for ueber alle 5-Eck-Kanten */
3927
3928
3929
3930 /* TH: ab hier ist alles massiv veraendert */
3931 /* Nun wird geprueft, ob der uebergebene Code der kleinstmoegliche ist. */
3932
3933 if (code[1]==1) /* Bauchbinde */
3934 { i=0;
3935 while (i<m_laenge)
3936 { if ((test = bauchbinde_reko(map,code,miniliste[i]))==0) return(0);
3937 if (test==1) {miniliste[i] = miniliste[m_laenge-1]; m_laenge--;}
3938 else {minierg[i] = test; i++;}
3939 }
3940 i=0;
3941 while (i<m_laenge && minierg[i]==4) {i++;}
3942 if (i==m_laenge) {fprintf(stderr,"Es fehlt Originalbauchbinde!\n"); exit(37);}
3943 test = minierg[0]; minierg[0] = minierg[i]; minierg[i] = test;
3944 run = miniliste[0]; miniliste[0] = miniliste[i]; miniliste[i] = run;
3945 /* Nun befindet sich im ersten Listeneintrag ein Pfad, der durch Drehung des
3946 Originals zustande kommt oder selbst das Original ist. Es gilt dann fuer den
3947 Wert von minierg[i]:
3948 2 = es gibt eine Drehung zwischen Bauchbinde 0 (erster Listeneintrag) und Bauchbinde i
3949 4 = es gibt eine Spiegelung/Drehspiegelung zwischen Bauchbinde 0 und Bcc Thauchbinde i
3950 6 = es gibt eine Drehung und eine Spiegelung zwischen Bauchbinde 0 und Bauchbinde i */
3951 }
3952 else {
3953
3954 /* Es koennen doppelte Eintraege in der miniliste vorkommen. Diese werden geloescht. */
3955 for (i=0; i<m_laenge-1; i++) {
3956 ii=i+1;
3957 while (ii<m_laenge) {
3958 if (miniliste[i]==miniliste[ii]) {miniliste[ii] = miniliste[m_laenge-1]; m_laenge--;}
3959 else {ii++;}
3960 }
3961 }
3962 for (i=0; i<ms_laenge-1; i++) {
3963 ii=i+1;
3964 while (ii<ms_laenge) {
3965 if (mini_spiegel[i]==mini_spiegel[ii]) {mini_spiegel[ii] = mini_spiegel[ms_laenge-1]; ms_laenge--;}
3966 else {ii++;}
3967 }
3968 }
3969
3970 if (code[1]==2) /* Brille */
3971 { i=0;
3972 while (i<m_laenge) {
3973 if ((test = brille_reko(map,code,miniliste[i]))==0) return(0);
3974 if (test==1) {miniliste[i]=miniliste[m_laenge-1]; m_laenge--;}
3975 else {i++;}
3976 }
3977 i=0;
3978 while (i<ms_laenge) {
3979 if ((test = brille_sp_reko(map,code,mini_spiegel[i]))==0) return(0);
3980 if (test==1) {mini_spiegel[i]=mini_spiegel[ms_laenge-1]; ms_laenge--;}
3981 else {i++;}
3982 }
3983 } /* if */
3984 else /* d.h. (code[1]==3) d.h. Sandwich */
3985 { i=0;
3986 while (i<m_laenge) {
3987 if ((test = sandwich_reko(map,code,miniliste[i]))==0) return(0);
3988 if (test==1) {miniliste[i]=miniliste[m_laenge-1]; m_laenge--;}
3989 else {i++;}
3990 }
3991 i=0;
3992 while (i<ms_laenge) {
3993 if ((test = sandwich_reko_sp(map,code,mini_spiegel[i]))==0) return(0);
3994 if (test==1) {mini_spiegel[i]=mini_spiegel[ms_laenge-1]; ms_laenge--;}
3995 else {i++;}
3996 }
3997 } /* else */
3998 } /* else */
3999
4000
4001 if (!symstat) return(1); /* 1 ist hier ein beliebiger Rueckgabewert ungleich 0 */
4002
4003
4004 /* Nun wird versucht, die Symmetriegruppe des erzeugten Fullerens herauszufinden */
4005
4006 { /* Klammer zur Abgrenzung der neuen Variablen */
4007 KNOTENTYP f[N+1]; /* f[x] enthaelt den Bildknoten von Knoten x */
4008 KNOTENTYP e1,e2,e3;
4009 char ordnung[32]; /* Ordnung einer Drehung */
4010 /* Es treten maximal 31 Drehungen auf (bei Ih__ und I__). Zwar werden bei Bauchbinden
4011 zwischenzeitlich einige Drehungen mehrfach gespeichert, jedoch nicht bei I__ und Ih__,
4012 da diese Abbildungen keine Sechserdrehungen enthalten. 32 reicht also als Obergrenze. */
4013 BOOL dreh;
4014 KANTE *k1, *k2;
4015 int jj,ord,n,n2;
4016 BOOL geloescht, gefunden, alt;
4017 char symm_ord; /* Gesamtordnung der Symmetriegruppe */
4018
4019 /* zunaechst bei Brillen und Sandwiches */
4020
4021 if (code[1]!=1) { /* keine Bauchbinde */
4022 KNOTENTYP f1[24][12],f2[24][12]; /* speichert Abbildung der ersten beiden Ecken eines Pfades */
4023
4024 symm_ord = m_laenge + ms_laenge + 1; /* Ordnung der Symmetriegruppe */
4025 switch (symm_ord) { /* eindeutige Symmetriegruppe ? */
4026 case 1: return(C1__);
4027 case 3: return(C3__);
4028 case 10: return(D5__);
4029 case 60: return(I__);
4030 case 120: return(Ih__);
4031 }
4032
4033 /* Teil 1: Nun werden alle Drehungen untersucht und die Zahl und die Art der
4034 Drehungen ermittelt */
4035
4036 n = 0; /* n: laufende Nummer des aktuellen Automorphismus */
4037 while (m_laenge>0) { /* Liste mit Drehungen durchforsten und dabei aufloesen */
4038 k1 = map[1][0].invers;
4039 k2 = miniliste[0]; /* es wird immer der erste Pfad in der Liste betrachtet */
4040 bilde_f(&f[0],k1,k2,map[0][0].name);
4041 /* Automorphismus, bei dem k1 auf k2 abgebildet wird, wird gebildet */
4042
4043 /* Nun wird betrachtet: Wie werden die Ecken e1 und e2 abgebildet und nach
4044 wie vielen Schritten werden wieder e1 und e2 erreicht (Ordnung des
4045 Automorphismus)? Dabei werden die zwischenzeitlich erreichten Ecken
4046 in den Arrays f1[n][...] und f2[n][...] zwischengespeichert. Also:
4047 f1[n][0] = f[e1], f1[n][1] = f[f[e1]], f1[n][2] = f[f[f[e1]]], ... ,
4048 f1[n][x] = f[...[f[e1]]...] = e1 (mit x = Ordnung des Automorphismus = Endwert von ord) */
4049 ord = 0; /* Ordnung des Automorphismus */
4050 e1 = k1->ursprung;
4051 e2 = k1->name;
4052 do {
4053 f1[n][ord] = e1 = f[e1];
4054 f2[n][ord] = e2 = f[e2];
4055 ord++;
4056 if (ord>12) {fprintf(stderr,"Ordnung eines Automorphismus groesser als 12!\n"); exit(38);}
4057 } while ((e1!=k1->ursprung) || (e2!=k1->name)); /* bis Identitaet erreicht */
4058 ordnung[n] = ord;
4059
4060 /* Nun ist die Ordnung des Automorphismus bekannt (=ordnung[n]) und es muessen noch
4061 die zugehoerigen Pfade in der miniliste gefunden und geloescht werden */
4062 miniliste[0] = miniliste[m_laenge-1]; m_laenge--; /* erster Pfad wird geloescht */
4063 i = 1; /* Anzahl der geloeschten Pfade */
4064 j = 0; /* laufende Nummer des Pfades, ueber den entschieden wird, ob er geloescht wird */
4065 while (j<m_laenge) {
4066 ii=0; geloescht=0;
4067 while (ii<ord-1 && !geloescht) {
4068 if (miniliste[j]->ursprung==f1[n][ii] && miniliste[j]->name==f2[n][ii])
4069 {miniliste[j]=miniliste[m_laenge-1]; m_laenge--; geloescht=1; i++;}
4070 /* Der Pfad wird geloescht, weil sein Anfang durch den aktuellen Automorphismus erreicht wird */
4071 ii++;
4072 }
4073 if (!geloescht) {j++;} /*falls geloescht, so ist in Position j neuer Pfad => nicht ueberspringen*/
4074 } /* while */
4075
4076 if (i+1>ord) {fprintf(stderr,"Zu viele Pfade geloescht!\n"); exit(39);}
4077
4078 /* Nun wird folgender Fall behandelt:
4079 Bei einem Automorphismus der Ordnung ord muessen ord-1 Pfade geloescht
4080 werden (alle bis auf den Originalpfad, der nicht in der Liste enthalten
4081 ist). Wenn weniger Pfade geloescht wurden, so sind zuvor schon einige
4082 Pfade des Automorphismus geloescht worden. Es gibt folgende Moeglichkeiten:
4083 - es wurde schon frueher eine Zweierdrehung entdeckt, die Bestandteil einer Sechserdrehung ist
4084 - es wurde schon frueher eine Dreierdrehung entdeckt, die Bestandteil einer Sechserdrehung ist
4085 - es wurden schon frueher eine Zweier- und eine Dreierdrehung entdeckt, die beide Bestandteil
4086 einer Sechserdrehung sind.
4087 In diesen Faellen muessen die zuerst gefundenen Zweier- bzw. Dreierdrehungen geloescht werden
4088 und in Sechserdrehungen umgewandelt werden.
4089 Falls einer der drei Faelle vorliegt, so ist der erste Eintrag f1[j][0] und f2[j][0]
4090 des zuerst gefundenen Automorphismus j auch im zweiten Automorphismus n enthalten. Also:
4091 f1[j][0] = f1[n][ii] und f2[j][0] = f2[n][ii] fuer ein ii */
4092
4093 if (i+1<ord) { /* zuwenig Pfade geloescht */
4094 j=0; /* laufende Nummer des Automorphismus, mit dem verglichen wird */
4095 while (j<n && i+1<ord) { /* es sind noch Automorphismen zu untersuchen */
4096 ii=0; geloescht=0;
4097 while (ii<ord-1 && !geloescht) {
4098 if (f1[j][0]==f1[n][ii] && f2[j][0]==f2[n][ii]) {
4099 i += ordnung[j]-1; /* die Anzahl der zuvor geloeschten Pfade */
4100 /* nun wird der zuvor gefundene Automorphismus geloescht (ueberschrieben) */
4101 ordnung[j] = ordnung[n-1];
4102 for (jj=0; jj<ordnung[n-1]; jj++) {f1[j][jj]=f1[n-1][jj]; f2[j][jj]=f2[n-1][jj];}
4103 ordnung[n-1] = ordnung[n];
4104 for (jj=0; jj<ordnung[n]; jj++) {f1[n-1][jj]=f1[n][jj]; f2[n-1][jj]=f2[n][jj];}
4105 n--;
4106 geloescht=1;
4107 } /* if */
4108 ii++;
4109 } /* while */
4110 if (!geloescht) {j++;}
4111 } /* while */
4112 if (i+1!=ord) {fprintf(stderr,"Falsche Ordnung des Automorphismus.\n"); exit(40);}
4113 } /* if i+1<ord */
4114
4115 n++; /* nun wird der naechste Automorphismus behandelt */
4116 } /* while m_laenge>0 */
4117
4118 /* Jetzt sind die Anzahl der Drehungen (n) und zu jeder Drehung j die Art der Drehung
4119 (ordnung[j]) bekannt.
4120
4121 Es folgt dieselbe Vorgehensweise fuer Spiegelungen. Es wird die Liste minispiegel
4122 aufgeloest. Es werden n2 Spiegelungen festgestellt. Da die Ordnung einer Ebenen-
4123 spiegelung immer 2 betraegt, ist eine Speicherung der Automorphismen in Arrays
4124 wie f1, f2 und ordnung nicht notwendig.
4125 In der Liste minispiegel befinden sich auch Drehspiegelungen (und Punktspiegelungen,
4126 die nichts anderes sind als 2er-Drehspiegelungen). Diese verursachen
4127 Probleme. Deshalb werden Drehspiegelungen, die gefunden werden, vernachlaessigt.
4128 Das ist moeglich, denn sobald die Ordnung einer Symmetriegruppe hoeher als 6 ist, ist
4129 jede Drehspiegelung schon in Form einer Drehung und einer Ebenenspiegelung berueck-
4130 sichtigt (das Fulleren enthaelt auch die einzelnen Symmetrien der zusammengesetzten
4131 Drehspiegelung). Es faellt also nichts unter den Tisch.
4132 Falls die Symmetriegruppe des Fullerens die Ordnung 4 oder 6 besitzt,
4133 ist es moeglich, anhand der gespeicherten Zahlen n und n2 auf die Existenz einer
4134 Drehspiegelung zu schliessen (deren einzelne Bestandteile nicht als Symmetrien in dem
4135 Fulleren vorhanden sind).
4136 Eine Drehspiegelung erkennt man daran, dass der Automorphismus im Gegensatz zur
4137 Ebenenspiegelung keine Ecken auf sich selbst oder benachbarte Ecken abbildet (letzteres
4138 ist durch die Mindestgroesse eines Fullerens gewaehrleistet).
4139 Falls der Automorphismus eine Ordnung besitzt, die groesser als 2 ist, so erkennt
4140 man die Drehspiegelung unmittelbar, denn Ebenenspiegelungen haben immer die Ordnung 2.
4141
4142 Ein Beispiel fuer ein Problem mit Drehspiegelungen:
4143 Die Symmetriegruppe C3h besteht aus einer Dreierdrehung und einer Ebenenspiegelung senk-
4144 recht zur Dreierdrehung. Das Programm koennte einen Automorphismus bilden, der einer
4145 6er-Drehspiegelung gleichkommt. Dabei wuerde dann sogar die Ebenenspiegelung uebersehen. */
4146
4147 /* Teil 2: Nun werden alle Spiegelungen untersucht und die Zahl und die Art der
4148 Spiegelungen ermittelt */
4149
4150 n2 = 0; /* n2: laufende Nummer des aktuellen Automorphismus */
4151 while (ms_laenge>0) { /* Liste mit Spiegelungen durchforsten und dabei aufloesen */
4152 k1 = map[1][0].invers;
4153 k2 = mini_spiegel[ms_laenge-1]; /* es wird immer der letzte Pfad in der Liste betrachtet */
4154 bilde_f_sp(&f[0],k1,k2,map[0][0].name);
4155 // Fehler bei Detektierung von Cs mit Fixkanten -- Aenderung: GB 13.2.2016
4156 if (symm_ord==2) ord=2; // GB
4157 else// GB
4158 {//GB
4159
4160 /* Automorphismus, bei dem k1 auf k2 abgebildet wird, wird gebildet */
4161 ord = 0; /* Ordnung des Automorphismus */
4162 /* es reicht, den Funktionswert der Kante k1={e1,e2} zu verfolgen, da k1!=k2,
4163 also k1 keine Fixkante unter f, also f[e1]!=e1 oder f[e2]!=e2 */
4164 e1 = k1->ursprung;
4165 e2 = k1->name;
4166 do {
4167 e1 = f[e1];
4168 e2 = f[e2];
4169 ord++;
4170 // commented out by GB: if (ord>12) {fprintf(stderr,"Ordnung eines Automorphismus groesser als 12!\n"); exit(41);}
4171 } while (((e1!=k1->ursprung) || (e2!=k1->name)) && ord<=2); /* bis Identitaet erreicht oder
4172 bis klar ist, dass es sich um Drehspiegelung handelt (wegen ord>2) */
4173 /* Nun wird ueberprueft, ob es sich bei der Spiegelung um eine reine Ebenenspiegelung oder um eine
4174 Drehspiegelung handelt. Bei einer Spiegelung mit der Ordnung >2 handelt es sich eindeutig um
4175 eine Drehspiegelung. Bei einer Spiegelung mit der Ordnung 2 ist zu pruefen, ob der Automorphismus
4176 Punkte auf sich selbst oder auf benachbarte Punkte abbildet (dann reine Ebenenspiegelung).
4177 Der aktuelle Automorphismus ist noch im Array f vorhanden. */
4178 } //GB
4179 if (ord==1) ord=2; /* GB: wenn eine gerichtete Kante fix ist unter einem orientierungsumkehrenden Automorphismus
4180 ist die Ordnung 2 */
4181 dreh = 1; /* falls keine andere Entdeckung: Drehspiegelung */
4182 if (ord==2) { /* Ebenenspiegelung oder Punktspiegelung ? */
4183 i=1;
4184 while (dreh && i<=map[0][0].name) {
4185 if (f[i]==map[i][0].name || f[i]==map[i][1].name || f[i]==map[i][2].name || f[i]==i) {dreh=0;}
4186 i++;
4187 }
4188 }
4189 if (!dreh) {n2++;}
4190 ms_laenge--; /* letzter Pfad wird geloescht */
4191 } /* while ms_laenge>0 */
4192 /* Jetzt ist die Anzahl der Ebenenspiegelungen (n2) bekannt */
4193
4194 /* Es folgt die Bestimmung der Symmetriegruppe. */
4195 switch(symm_ord) {
4196 case 1: return(C1__);
4197 case 2: if (n) {return(C2__);}
4198 else {
4199 if (n2) {return(Cs__);}
4200 else {return(Ci__);}
4201 }
4202 case 3: return(C3__);
4203 case 4: if (!n2) {
4204 if (n==3) {return(D2__);}
4205 else {return(S4__);}
4206 }
4207 else {
4208 if (n2==2) {return(C2v__);}
4209 else {return(C2h__);}
4210 }
4211 case 6: if (!n2) {
4212 if (n==4) {return(D3__);}
4213 else {return(S6__);}
4214 }
4215 else {
4216 if (n2==3) {return(C3v__);}
4217 else {return(C3h__);}
4218 }
4219 case 8: if (n2==3) {return(D2h__);}
4220 else {return(D2d__);}
4221 case 10: return(D5__);
4222 case 12: if (!n2) {
4223 BOOL d6=0;
4224 for (i=0; i<n; i++) {if (ordnung[i]==6) {d6=1;} }
4225 if (d6) {return(D6__);}
4226 else {return(T__);}
4227 }
4228 else {
4229 if (n2==4) {return(D3h__);}
4230 else {return(D3d__);}
4231 }
4232 case 20: if (n2==6) {return(D5h__);}
4233 else {return(D5d__);}
4234 case 24: { if (n2==7) {return(D6h__);}
4235 if (n2==6) {
4236 BOOL d6=0;
4237 for (i=0; i<n; i++) {if (ordnung[i]==6) {d6=1;} }
4238 if (d6) {return(D6d__);}
4239 else {return(Td__);}
4240 }
4241 else {return(Th__);}
4242 }
4243 case 60: return(I__);
4244 case 120: return(Ih__);
4245 default: {fprintf(stderr,"Unbekannte Ordnung %d! %d\n",symm_ord,code[1]); exit(42);}
4246 } /* switch symm_ord */
4247
4248 } /* if code[1]!=1 */
4249
4250
4251 /* Es folgt dasselbe fuer Bauchbinden */
4252
4253 if (code[1]==1) { /* Bauchbinde (redundante if-Abfrage) */
4254 /* Bei der Bauchbinde befindet sich der Originalpfad in der miniliste. Also wird einfach
4255 der erste Pfad in der Liste als Originalpfad genommen. */
4256 /* Bei der Bauchbinde sind verschiedene Symmetrien zu untersuchen, bei denen die
4257 Bauchbinde auf sich selbst abgebildet wird (so dass diese Symmetrien nicht
4258 direkt aus der miniliste abzulesen sind). Dies sind Drehungen um die Achse
4259 senkrecht zur Bauchbinde und Spiegelungen an Ebenen senkrecht zur Bauchbinde.
4260 Falls die Bauchbinde das Fulleren in zwei gleiche Teile zerteilt (lowercode==uppercode),
4261 so kommen noch Drehspiegelungen um die Achse senkrecht zur Bauchbinde und
4262 Zweierdrehungen um die Achse, die durch die Mittelpunkte zweier gegenueberliegender Kanten der
4263 Bauchbinde verlaeuft, hinzu. Falls die Bauchbinde das Fulleren in zwei ungleiche Teile zerteilt,
4264 so werden diese Symmetrien in der miniliste festgehalten und muessen erst spaeter
4265 betrachtet werden. */
4266
4267 KNOTENTYP f1[24][2]; /* speichert bei gefundenen SPIEGELEBENEN eine Beispielkante */
4268 /* 15 als Maximalzahl wuerde ausreichen (bei Ih__) */
4269 KNOTENTYP f2[32][2]; /* speichert bei gefundenen DREHUNGEN eine Beispielkante */
4270 /* 31 als Maximalzahl wuerde ausreichen (bei I__ und Ih__) */
4271 KNOTENTYP g[N+1];
4272 char ordnung2; /* Ordnung bei Spiegelungen */
4273 char drehung; /* Art der Drehung um Achse senkrecht zur Bauchbinde */
4274 char sp_ebene; /* Spiegelebene(n) senkrecht zur Bauchbinde */
4275 char drehsp; /* Drehspiegelung um Achse senkrecht zur Bauchbinde */
4276 char zdrehung; /* Zweierdrehung(en) wie oben beschrieben. */
4277
4278 n = 0; /* Anzahl der gefundenen Drehungen */
4279 i = (code[0]/2)/code[3]; /* Drehung im oberen Teil des Fullerens */
4280 j = (code[0]/2)/code[11]; /* Drehung im unteren Teil des Fullerens */
4281 drehung = i<j ? i : j; /* groesser auf keinen Fall */
4282 if (i%drehung || j%drehung) {drehung = 1;} /* Drehung um die Achse senkrecht zur Bauchbinde */
4283 if (drehung>1) { /* Drehung in die Liste eintragen */
4284 k2 = miniliste[0];
4285 for (j=1; j<=knoten_auf_pfad/drehung; j++) {
4286 if (j%2) {k2 = k2->invers->prev;} else {k2 = k2->invers->next;}
4287 }
4288 f2[n][0] = k2->ursprung; /* Beispielkante */
4289 f2[n][1] = k2->name;
4290 ordnung[n] = drehung;
4291 n++;
4292 }
4293
4294 /* Nun wird versucht, Spiegelebenen zu ermitteln, die senkrecht auf der Bauchbinde
4295 stehen. Wenn es eine solche Spiegelebene gibt, dann schneidet sie die Bauchbinde
4296 in zwei Ecken. Es ist nicht moeglich, dass die Spiegelebene die Bauchbinde in
4297 einer Ecke und einer Kante oder in zwei Kanten schneidet.
4298 Also werden im folgenden je zwei gegenueberliegende Ecken betrachtet. Ausgehend
4299 von den Winkeln, die diese Ecken einschliessen, wird eine nicht ordnungserhaltene
4300 Abbildung gebildet und es wird untersucht, ob es sich dabei um einen Automorphismus
4301 der Ordnung 2 handelt.
4302 Damit nicht jede Spiegelebene doppelt betrachtet wird, reicht es aus bzw. ist es
4303 sogar erforderlich, nur die Ecken auf einer Haelfte des Pfades zu betrachten.
4304 Die gegenueberliegenden Ecken tauchen im Programmcode nicht auf.
4305 Sobald eine Spiegelebene gefunden wurde, wird die Suche nach weiteren Spiegelebenen
4306 vereinfacht, denn die Anzahl der Spiegelebenen senkrecht zur Bauchbinde entspricht
4307 dem Wert von "drehung" und die Spiegelebenen treten in regelmaessigen Abstaenden auf.
4308 Es verdoppelt sich die Symmetrieordnung unabhaengig von der Anzahl der Spiegelebenen. */
4309
4310 n2 = 0; /* Anzahl der gefundenen Spiegelebenen */
4311 sp_ebene = 1; /* noch keine gefundene Spiegelebene */
4312 k1 = miniliste[0]; /* erste Kante */
4313 k2 = k1;
4314 j=1; i=0;
4315 while (j<=knoten_auf_pfad/2) { /* den halben Pfad entlanggehen */
4316 if (j%2) {k2 = k1->invers->prev;} else {k2 = k1->invers->next;}
4317 /* Nun ist k2 im Pfad der Nachfolger von k1 */
4318 /* Wenn durch den Knoten k1->name eine Spiegelebene verlaeuft, so wird k1 auf k2->invers
4319 abgebildet und umgekehrt. Man kann nun eine nicht ordnungserhaltene Funktion f bilden,
4320 die k1 auf k2->invers abbildet, und eine nicht ordnungserhaltene Funktion g, die k2->invers auf
4321 k1 abbildet. Wenn g die Umkehrfunktion zu f ist, so ist f ein nicht ordnungserhaltender
4322 Automorphismus mit ordnung 2, es liegt also eine Spiegelebene vor (denn k1->name = k2->invers->name,
4323 es exisitiert also ein Fixpunkt). */
4324 if (sp_ebene==1 || (sp_ebene==2 && i==knoten_auf_pfad/(2*drehung))) { /* Suche lohnt sich */
4325 if (bilde_f_und_g_sp(&f[0],&g[0],k1,k2->invers,map[0][0].name)) {
4326 sp_ebene=2; /* fuendig */
4327 f1[n2][0] = f[miniliste[0]->ursprung]; f1[n2][1] = f[miniliste[0]->name];
4328 n2++;
4329 i=0; /* Zaehler fuer jetzt beginnende schnelle Suche */
4330 }
4331 }
4332 k1 = k2; /* zur naechsten Kante des Pfades */
4333 j++; i++;
4334 } /* while j */
4335
4336 /* Nun werden die oben beschriebenen Zweierdrehungen und Drehspiegelungen betrachtet, und zwar
4337 die Zweierdrehungen nur dann, wenn lowercode==uppercode.
4338 Zunaechst zu den Zweierdrehungen. Sobald man eine Zweierdrehung gefunden hat, ergeben sich
4339 Anzahl und Lage von (eventuell) weiteren Zweierdrehungen aus dem Wert von "drehung".
4340 Zu der Ordnung der Symmetriegruppe tragen die weiteren Zweierdrehungen nichts bei.
4341 Wie bei den Spiegelebenen werden die Kanten der Bauchbinde betrachtet und es werden ordnungs-
4342 erhaltende Funktionen gebildet, bei denen eine Kante k1 auf k1->invers abgebildet wird und
4343 umgekehrt.
4344 Eine auf diese Weise ermittelte Zweierdrehung kann nicht Bestandteil einer Sechserdrehung sein,
4345 da um den Mittelpunkt einer Kante nur Zweierdrehungen moeglich sind.
4346 Theoretisch kann eine solche Zweierdrehung Bestandteil einer Viererdrehspiegelung sein. Dies
4347 wird in diesem Zusammenhang ebenfalls geprueft. Falls eine Viererdrehspiegelung vorliegt, so
4348 wird die Kante k1 auf die "gegenueberliegende" Kante (bezogen auf die Laenge der Bauchbinde)
4349 abgebildet. Eine Viererdrehspiegelung ist nur dann interessant, wenn es die einzige innerhalb
4350 des Fullerens ist. Insbesondere liegt dann auch nur EINE Zweierdrehung und KEINE Ebenenspiegelung
4351 vor. Es wird also nur bei der ersten gefundenen Zweierdrehung geprueft und auch nur dann, wenn
4352 drehung==1 (keine weitere Drehung) und m_laenge==1 und sp_ebene==1. */
4353
4354 zdrehung = drehsp = 1; /* 1 = noch nichts gefunden, 2 = gefunden */
4355 if (codecmp_kn(code+2,code+10,8)==0) { /* lowercode==uppercode */
4356 k1 = miniliste[0]; /* erste Kante */
4357 j=1; i=0;
4358 while (j<=knoten_auf_pfad/2) { /* den halben Pfad entlanggehen */
4359 if (zdrehung==1 || (zdrehung==2 && i==knoten_auf_pfad/(2*drehung))) { /* Suche lohnt sich */
4360 if (bilde_f_und_g(&f[0],&g[0],k1,k1->invers,map[0][0].name)) {
4361 f2[n][0] = f[miniliste[0]->ursprung]; f2[n][1] = f[miniliste[0]->name];
4362 ordnung[n] = 2;
4363 n++;
4364 if (zdrehung==1 && m_laenge==1 && sp_ebene==1 && drehung==1) { /* Drehspiegelung? */
4365 k2 = k1;
4366 for (ii=0; ii<knoten_auf_pfad/2; ii++) {
4367 if ((j+ii)%2) {k2 = k2->invers->prev;} else {k2 = k2->invers->next;} /* halber Pfad */
4368 }
4369 if (bilde_f_und_g_sp(&f[0],&g[0],k1,k2,map[0][0].name)) {
4370 fprintf(stderr,"Z-Viererdrehspiegelung\n"); /* sollte eine derartige Drehspiegelung
4371 tatsaechlich auftreten, so ist sie eine Zeile wert */
4372 drehsp=4;
4373 }
4374 /* Drehspiegel-Abbildung von k1 nach k2->invers braucht nicht betrachtet zu werden:
4375 dasselbe Ergebnis wegen zdrehung=2 */
4376 }
4377 i=0; /* Zaehler fuer jetzt beginnende schnelle Suche */
4378 zdrehung=2; /* fuendig */
4379 }
4380 }
4381 if (j%2) {k1 = k1->invers->prev;} else {k1 = k1->invers->next;} /* zur naechsten Kante des Pfades */
4382 j++; i++;
4383 } /*while */
4384 } /* if */
4385
4386 /* Nun ist noch zu pruefen, ob eine Drehspiegelung mit einer Drehung um die Bauchbinde vorliegt.
4387 Die einzigen interessanten Faelle sind
4388 Ci, S4 und S6. Liegt einer dieser Faelle vor, so gibt es keine Spiegelebene (also sp_ebene==1 als
4389 Voraussetzung) und nur einen Listeneintrag (also m_laenge==1) und keine weitere Drehung (zdrehung==1).
4390 drehung==1: moeglicherweise Punktspiegelung
4391 drehung==2: moeglicherweise Viererdrehspiegelung
4392 drehung==3: moeglicherweise Sechserdrehspiegelung
4393 => drehung==n/2: moeglicherweise n-Drehspiegelung
4394 Fuer eine n-Drehspiegelung muss die Laenge des Pfades durch n teilbar sein (damit zugehoerige
4395 n/2-Drehung moeglich ist), darf aber nicht durch 2n teilbar sein. */
4396 if (m_laenge==1 && sp_ebene==1 && drehung<=3 && zdrehung==1 && knoten_auf_pfad%(2*drehung)==0 &&
4397 knoten_auf_pfad%(4*drehung)!=0) {
4398 k1 = miniliste[0]; /* erste Kante */
4399 k2 = k1;
4400 for (j=1; j<=knoten_auf_pfad/(2*drehung); j++) { /* einen Teil des Pfades entlanggehen */
4401 if (j%2) {k2 = k2->invers->prev;} else {k2=k2->invers->next;}
4402 }
4403 /* Wenn eine Drehspiegelung der Ordnung 2*drehung vorliegt, so wird durch sie k1 auf k2 abgebildet
4404 und umgekehrt. */
4405 if (bilde_f_und_g_sp(&f[0],&g[0],k1,k2,map[0][0].name)) {drehsp=2*drehung;} /* fuendig */
4406 } /* if */
4407
4408 symm_ord = m_laenge * drehung * sp_ebene * zdrehung; /* Mindestordnung der Symmetriegruppe */
4409 /* Fast immer ist dies auch die tatsaechliche Ordnung der Symmetriegruppe. Falls m_laenge>1,
4410 so kann es jedoch sein, dass zwei Pfade sowohl durch eine Drehung als auch durch eine Spiegelung
4411 aufeinander abgebildet werden (minierg==6). Falls diese Drehungen oder Spiegelungen nicht auch
4412 auf eine andere Weise entdeckt werden koennen, so ist die tatsaechliche Ordnung der Symmetriegruppe
4413 hoeher als symm_ord. Folgende Beobachtung wurde gemacht: Wenn zwischen zwei Bauchbinden eines
4414 Fullerens die Relation minierg==6 auftritt, dann auch zwischen allen anderen Bauchbinden des
4415 Fullerens. */
4416
4417 if (m_laenge==1) { /* schnelle Entscheidung anhand der symm_ord moeglich */
4418 switch (symm_ord) {
4419 case 1: if (drehsp==2) {return(Ci__);} else {return(C1__);}
4420 case 2:{ if (drehsp==4) {return(S4__);}
4421 if (drehung==2 || zdrehung==2 || (m_laenge==2 && minierg[1]==2)) {return(C2__);}
4422 if (sp_ebene==2) {return(Cs__);}
4423 break;}
4424 case 3: if (drehsp==6) {return(S6__);} else {return(C3__);}
4425 case 10: return(D5__);
4426 } /* switch */
4427 } /* if */
4428
4429 /* Nun werden alle Eintraege in der miniliste untersucht. */
4430
4431 /* Es treten folgende Probleme im Vergleich zu Sandwiches und Brillen auf:
4432 1. Ein Eintrag in der miniliste muss nicht aus einer Drehung resultieren, sondern
4433 kann auch von einer Ebenenspiegelung stammen. Deshalb muss zu jedem Eintrag
4434 eine ordnungserhaltende und eine nicht ordnungserhaltende Funktion gebildet
4435 werden. Allerdings kann man sich die Liste minierg[] zunutze machen, die
4436 Auskunft darueber gibt, welche Funktion Aussicht auf Erfolg verspricht.
4437 2. Es steht nicht fest, wohin der Anfang des Originalpfades abgebildet wird, da die
4438 Bauchbinde keinen fest definierten Anfang besitzt. Deshalb muss der "Anfang" der
4439 Originalbauchbinde (mit "Original" ist miniliste[0] gemeint) auf alle Kanten der
4440 in der miniliste (weiter hinten) gespeicherten Bauchbinde
4441 abgebildet werden. Es ergeben sich verschiedene Abbildungen. Teilweise handelt es
4442 sich dabei natuerlich nicht um Automorphismen. Die verbleibenden Spiegelabbildungen, bei
4443 denen es sich wirklich um Automorphismen handelt, koennen sogar unterschiedliche
4444 Ordnungen haben (Beispiel: drehung==5 und in der miniliste steht Ebenenspiegelung
4445 an Ebene parallel zur Bauchbinde. Eine Abbildung spiegelt nur => Ordnung 2. Eine
4446 andere Abbildung spiegelt und macht eine Fuenfteldrehung um die Bauchbinde
4447 => Ordnung 10). Sobald eine Ebenenspiegelung gefunden wurde, eruebrigt sich NICHT die Suche
4448 nach anderen Spiegelabbildungen zwischen den beiden betrachteten Bauchbinden, denn
4449 andere Spiegelebenen koennen gefunden werden: Es ist zwar nicht moeglich, dass zwei verschiedene
4450 Spiegelebenen eine einzelne Kante aufeinander abbilden, aber es ist moeglich, dass zwei verschie-
4451 dene Spiegelebenen zwei verschiedene Bauchbinden als Gesamtes jeweils aufeinander abbilden,
4452 wobei die einzelnen Kanten der Bauchbinden jeweils unterschiedlich aufeinander abgebildet werden
4453 (Beispiel: Fulleren Nummer 145886 bei C100). */
4454
4455 while (m_laenge>1) { /* Liste durchforsten und dabei aufloesen */
4456 /* Zunaechst wird versucht, weitere Spiegelebenen zu ermitteln, die senkrecht auf der Bauchbinde
4457 stehen, die mit k1 beginnt, und die diese Bauchbinde auf sich selbst abbilden.
4458 Das Verfahren ist dasselbe wie oben. Es kann sein, dass eine
4459 gefundene Spiegelebene bereits gespeichert ist, weil sie z.B. gleichzeitig senkrecht auf zwei
4460 Bauchbinden steht. Deshalb muessen neu gefundene Spiegelebenen mit bereits gefundenen
4461 Spiegelebenen verglichen werden. */
4462 if (sp_ebene==2) { /* falls bei Originalpfad Spiegelebene vorhanden <=> so auch hier */
4463 k1 = miniliste[m_laenge-1]; /* erste Kante */
4464 k2 = k1;
4465 gefunden = 0; /* noch keine Spiegelebene gefunden */
4466 j=1; i=0;
4467 while (j<=knoten_auf_pfad/2) { /* den halben Pfad entlanggehen */
4468 if (j%2) {k2 = k1->invers->prev;} else {k2 = k1->invers->next;}
4469 if (gefunden==0 || (gefunden==1 && i==knoten_auf_pfad/(2*drehung))) { /* Suche lohnt sich */
4470 if (bilde_f_und_g_sp(&f[0],&g[0],k1,k2->invers,map[0][0].name)) {
4471 gefunden=1; /* fuendig */
4472 alt = ii = 0;
4473 while (!alt && ii<n2) { /* Spiegelung bereits gespeichert? */
4474 if (f1[ii][0]==f[miniliste[0]->ursprung] && f1[ii][1]==f[miniliste[0]->name]) {alt=1;}
4475 ii++;
4476 }
4477 if (!alt) {f1[n2][0]=f[miniliste[0]->ursprung]; f1[n2][1]=f[miniliste[0]->name]; n2++;}
4478 i=0; /* Zaehler fuer jetzt beginnende schnelle Suche */
4479 }
4480 }
4481 k1 = k2; /* zur naechsten Kante des Pfades */
4482 j++; i++;
4483 } /* while j */
4484 } /* if sp_ebene==2 */
4485
4486 /* Nun wird versucht, weitere Drehungen zu ermitteln, die die Bauchbinde auf sich selbst abbilden.
4487 Auch hier muessen neu gefundene Drehungen mit bereits gefundenen Drehungen verglichen werden. */
4488 /* zunaechst zur inneren Drehung */
4489 if (drehung>1) { /* falls bei Originalpfad innere Drehung <=> so auch hier */
4490 k2 = miniliste[m_laenge-1];
4491 for (j=1; j<=knoten_auf_pfad/drehung; j++) {
4492 if (j%2) {k2 = k2->invers->prev;} else {k2 = k2->invers->next;}
4493 }
4494 if (bilde_f_und_g(&f[0],&g[0],miniliste[m_laenge-1],k2,map[0][0].name)) { /* Abbildung holen */
4495 alt = ii = ord = 0;
4496 while (!alt && ii<n) { /* Drehung bereits gespeichert? */
4497 if (ordnung[ii]==drehung) {
4498 e1 = miniliste[0]->ursprung; e2 = miniliste[0]->name; i = 0;
4499 do {
4500 e1 = f[e1]; e2 = f[e2]; i++;
4501 } while (i<drehung && (e1!=f2[ii][0] || e2!=f2[ii][1]));
4502 if (i<drehung) {alt=1;}
4503 }
4504 ii++;
4505 }
4506 if (!alt) {
4507 f2[n][0] = f[e1]; /* Beispielkante */
4508 f2[n][1] = f[e2];
4509 ordnung[n] = drehung;
4510 n++;
4511 }
4512 } /* if */
4513 } /* if drehung>1 */
4514
4515 /* Nun zu den Zweierdrehungen an den Kantenzentren der Bauchbinde */
4516 if (zdrehung==2) { /* Zweierdrehung(en) beim Originalpfad <=> so auch hier */
4517 k1 = miniliste[m_laenge-1]; /* erste Kante */
4518 j=1; i=0; gefunden=0;
4519 while (j<=knoten_auf_pfad/2) { /* den halben Pfad entlanggehen */
4520 if (gefunden==0 || (gefunden==1 && i==knoten_auf_pfad/(2*drehung))) { /* Suche lohnt sich */
4521 if (bilde_f_und_g(&f[0],&g[0],k1,k1->invers,map[0][0].name)) {
4522 gefunden=1; /* fuendig */
4523 alt = ii = 0;
4524 while (!alt && ii<n) {
4525 if (ordnung[ii]==2) {
4526 if (f2[ii][0]==f[miniliste[0]->ursprung] && f2[ii][1]==f[miniliste[0]->name]) {alt=1;}
4527 }
4528 ii++;
4529 }
4530 if (!alt) {
4531 f2[n][0] = f[miniliste[0]->ursprung]; f2[n][1] = f[miniliste[0]->name];
4532 ordnung[n] = 2; n++;
4533 }
4534 i=0; /* Zaehler fuer jetzt beginnende schnelle Suche */
4535 }
4536 }
4537 if (j%2) {k1 = k1->invers->prev;} else {k1 = k1->invers->next;} /* zur naechsten Kante des Pfades */
4538 j++; i++;
4539 } /* while */
4540 }
4541
4542 /* Nun werden Abbildungen zwischen der Bauchbinde 0 und der letzten Bauchbinde in der Liste
4543 betrachtet, und zwar wie oben beschrieben. */
4544 k1 = miniliste[0];
4545 k2 = miniliste[m_laenge-1]; /* es wird immer der letzte Pfad in der Liste betrachtet */
4546 ordnung2 = 0; /* Ordnung des gefundenen nicht ordnungserhaltenden Automorphismus */
4547 j = 1;
4548 while (j<=knoten_auf_pfad) { /* den Bildpfad entlanggehen */
4549 if (minierg[m_laenge-1]&2) { /* Drehung moeglich */
4550 if (bilde_f_und_g(&f[0],&g[0],k1,k2,map[0][0].name)) {
4551 /* ordnungserhaltenden Automorphismus gefunden */
4552 ord = 0; /* Ordnung des Automorphismus ermitteln */
4553 e1 = k1->ursprung; e2 = k1->name;
4554 do {
4555 e1 = f[e1]; e2 = f[e2];
4556 ord++;
4557 if (ord>12) {fprintf(stderr,"Ordnung eines Automorphismus groesser als 12!\n"); exit(43);}
4558 } while ((e1!=k1->ursprung) || (e2!=k1->name)); /* bis Identitaet erreicht */
4559 alt = ii = 0; /* mit bereits gefundenen Drehungen vergleichen */
4560 while (!alt && ii<n) { /* Drehung bereits gespeichert? */
4561 if (ordnung[ii]==ord) {
4562 e1 = k1->ursprung; e2 = k1->name; i = 0;
4563 do {
4564 e1 = f[e1]; e2 = f[e2]; i++;
4565 } while (i<ord && (e1!=f2[ii][0] || e2!=f2[ii][1]));
4566 if (i<ord) {alt=1;}
4567 }
4568 ii++;
4569 }
4570 if (!alt) {
4571 f2[n][0] = f[e1]; /* Beispielkante */
4572 f2[n][1] = f[e2]; /* e1 und e2 haben wieder die urspruenglichen Werte */
4573 ordnung[n] = ord;
4574 n++;
4575 } /* if */
4576 } /* if */
4577
4578 /* dasselbe mit spiegelverkehrtem Pfad */
4579 if (bilde_f_und_g(&f[0],&g[0],k1,k2->invers,map[0][0].name)) {
4580 /* ordnungserhaltenden Automorphismus gefunden */
4581 ord = 0; /* Ordnung des Automorphismus ermitteln */
4582 e1 = k1->ursprung; e2 = k1->name;
4583 do {
4584 e1 = f[e1]; e2 = f[e2];
4585 ord++;
4586 if (ord>12) {fprintf(stderr,"Ordnung eines Automorphismus groesser als 12!\n"); exit(44);}
4587 } while ((e1!=k1->ursprung) || (e2!=k1->name)); /* bis Identitaet erreicht */
4588 alt = ii = 0; /* mit bereits gefundenen Drehungen vergleichen */
4589 while (!alt && ii<n) { /* Drehung bereits gespeichert? */
4590 if (ordnung[ii]==ord) {
4591 e1 = k1->ursprung; e2 = k1->name; i = 0;
4592 do {
4593 e1 = f[e1]; e2 = f[e2]; i++;
4594 } while (i<ord && (e1!=f2[ii][0] || e2!=f2[ii][1]));
4595 if (i<ord) {alt=1;}
4596 }
4597 ii++;
4598 }
4599 if (!alt) {
4600 f2[n][0] = f[e1]; /* Beispielkante */
4601 f2[n][1] = f[e2];
4602 ordnung[n] = ord;
4603 n++;
4604 } /* if */
4605 } /* if */
4606 } /* if minierg&2 */
4607
4608 if (minierg[m_laenge-1]&4) { /* Ebenenspiegelung moeglich */
4609 if (bilde_f_und_g_sp(&f[0],&g[0],k1,k2->invers->prev,map[0][0].name)) {
4610 /* nicht ordnungserhaltenden Automorphismus gefunden */
4611 ord = 0; /* Ordnung des Automorphismus */
4612 /* da {e1,e2} eventuell Fixkante ist, muss eine weitere Kante {e1,e3} betrachtet werden */
4613 e1 = k1->ursprung; e2 = k1->name; e3 = k1->prev->name;
4614 do {
4615 e1 = f[e1]; e2 = f[e2]; e3 = f[e3];
4616 ord++;
4617 if (ord>12) {fprintf(stderr,"Ordnung eines Automorphismus groesser als 12!\n"); exit(45);}
4618 } while ((e1!=k1->ursprung) || (e2!=k1->name) || (e3!=k1->prev->name)); /* Identitaet erreicht */
4619 if (ordnung2==0 || ordnung2>ord) {ordnung2=ord;}
4620 if (ord>drehsp) {drehsp=ord;} /* groesste gefundene Drehspiegelung speichern */
4621 /* falls in Wirklichkeit Ebenenspiegelung => egal, denn => n2>0 => drehsp wird nicht abgefragt */
4622 if (ord==2) { /* testen: ist gefundene Funktion Ebenenspiegelung? */
4623 i = dreh = 1;
4624 while (dreh && i<=map[0][0].name) { /* Fixpunkte/Beruehrungspunkte suchen */
4625 if (f[i]==map[i][0].name || f[i]==map[i][1].name || f[i]==map[i][2].name || f[i]==i) {dreh=0;}
4626 i++;
4627 }
4628 if (!dreh) { /* Ebenenspiegelung gefunden */
4629 alt = ii = 0;
4630 while (!alt && ii<n2) { /* Spiegelung bereits gespeichert? */
4631 if (f1[ii][0]==f[k1->ursprung] && f1[ii][1]==f[k1->name]) {alt=1;}
4632 ii++;
4633 }
4634 if (!alt) {f1[n2][0]=f[k1->ursprung]; f1[n2][1]=f[k1->name]; n2++;}
4635 } /* if */
4636 } /* if */
4637 } /* if */
4638
4639 /* dasselbe mit spiegelverkehrtem Pfad */
4640 if (bilde_f_und_g_sp(&f[0],&g[0],k1,k2->invers->prev->invers,map[0][0].name)) {
4641 /* nicht ordnungserhaltenden Automorphismus gefunden */
4642 ord = 0; /* Ordnung des Automorphismus */
4643 /* da {e1,e2} eventuell Fixkante ist, muss eine weitere Kante {e1,e3} betrachtet werden */
4644 e1 = k1->ursprung; e2 = k1->name; e3 = k1->prev->name;
4645 do {
4646 e1 = f[e1]; e2 = f[e2]; e3 = f[e3];
4647 ord++;
4648 if (ord>12) {fprintf(stderr,"Ordnung eines Automorphismus groesser als 12!\n"); exit(46);}
4649 } while ((e1!=k1->ursprung) || (e2!=k1->name) || (e3!=k1->prev->name)); /* Identitaet erreicht */
4650 if (ordnung2==0 || ordnung2>ord) {ordnung2=ord;}
4651 if (ord>drehsp) {drehsp=ord;} /* groesste gefundene Drehspiegelung speichern */
4652 if (ord==2) { /* testen: ist gefundene Funktion Ebenenspiegelung? */
4653 i = dreh = 1;
4654 while (dreh && i<=map[0][0].name) {
4655 if (f[i]==map[i][0].name || f[i]==map[i][1].name || f[i]==map[i][2].name || f[i]==i) {dreh=0;}
4656 i++;
4657 }
4658 if (!dreh) { /* Ebenenspiegelung gefunden */
4659 alt = ii = 0;
4660 while (!alt && ii<n2) { /* Spiegelung bereits gespeichert? */
4661 if (f1[ii][0]==f[k1->ursprung] && f1[ii][1]==f[k1->name]) {alt=1;}
4662 ii++;
4663 }
4664 if (!alt) {f1[n2][0]=f[k1->ursprung]; f1[n2][1]=f[k1->name]; n2++;}
4665 } /* if */
4666 } /* if */
4667 } /* if */
4668 } /* if (minierg&4) */
4669
4670 k2 = k2->invers->prev->invers->next; /* zwei Kanten weiter */
4671 j+=2;
4672 } /* while j */
4673
4674 m_laenge--; /* letzter (untersuchter) Pfad wird geloescht */
4675 } /* while m_laenge>1 */
4676
4677 /* Nun werden Drehungen, die doppelt gezaehlt wurden, aus der Liste ordnung[] genommen. Folgender
4678 Fall:
4679 - Sechserdrehung in der Liste: eine Zweierdrehung und eine Dreierdrehung zuviel, aber nur
4680 dann, wenn die Sechserdrehung aus zwei verschiedenen Pfaden rekonstruiert wurde und nicht,
4681 wenn die Sechserdrehung aus dem Wert von "drehung" folgt.
4682 Die Inhalte der Arrays f1 und f2 werden nicht zusammen mit den Inhalten von ordnung verschoben,
4683 da sie nicht mehr gebraucht werden. */
4684 if (drehung!=6) {
4685 j=0;
4686 while (j<n) {
4687 if (ordnung[j]==6) {
4688 ii = 0; i = 0;
4689 while (ii<1 && i<n) {
4690 if (ordnung[i]==3) {
4691 if (i>j) {ordnung[i]=ordnung[n-1]; n--; ii++;}
4692 else {ordnung[i]=ordnung[j-1]; ordnung[j-1]=ordnung[j]; /* i<j */
4693 ordnung[j]=ordnung[n-1]; n--; ii++; j--;}
4694 }
4695 else {i++;}
4696 }
4697 if (ii<1) {fprintf(stderr,"Es fehlt eine Dreierdrehung.\n"); exit(47);}
4698 ii = 0; i = 0;
4699 while (ii<1 && i<n) {
4700 if (ordnung[i]==2) {
4701 if (i>j) {ordnung[i]=ordnung[n-1]; n--; ii++;}
4702 else {ordnung[i]=ordnung[j-1]; ordnung[j-1]=ordnung[j];
4703 ordnung[j]=ordnung[n-1]; n--; ii++; j--;}
4704 }
4705 else {i++;}
4706 }
4707 if (ii<1) {fprintf(stderr,"Es fehlt eine Zweierdrehung.\n"); exit(48);}
4708 j=n; /* Es tritt hoechstens eine Sechserdrehung auf => Abbruch */
4709 } /* if */
4710 j++;
4711 } /* while */
4712 } /* if */
4713
4714 /* Jetzt ist die Anzahl der Ebenenspiegelungen (n2) und die Anzahl (n) und Art (ordnung[]) der
4715 Drehungen bekannt. */
4716 /* Es folgt die Bestimmung der Symmetriegruppe. */
4717
4718 /* Testblock: funktioniert das Programm richtig? */
4719 /* der gesamte Switch-Block kann entfallen, sobald das Vertrauen in die Prozedur gross genug ist */
4720 switch(n2) {
4721 case 0: {switch(n) {
4722 case 0: {if (drehsp!=2) {fprintf(stderr, "%lld: Fehler bei Ci %d\n", graphenzahl[map[0][0].name]+1,
4723 drehsp); exit(49);}
4724 break;}
4725 case 1: {if (drehsp==4) {if (ordnung[0]!=2)
4726 {fprintf(stderr,"%lld: Fehler bei S4\n", graphenzahl[map[0][0].name]+1); exit(50);} }
4727 if (drehsp==6) {if (ordnung[0]!=3)
4728 {fprintf(stderr,"%lld: Fehler bei S6\n", graphenzahl[map[0][0].name]+1); exit(51);} }
4729 if (ordnung[0]!=2 && ordnung[0]!=3)
4730 {fprintf(stderr, "%lld: Fehler bei C%d\n", graphenzahl[map[0][0].name]+1, ordnung[0]);
4731 exit(52);}
4732 break;}
4733 case 3: {if (ordnung[0]!=2 || ordnung[1]!=2 || ordnung[2]!=2)
4734 {fprintf(stderr, "%lld: Fehler bei D2\n", graphenzahl[map[0][0].name]+1); exit(53);}
4735 break;}
4736 case 4: {if (ordnung[0]+ordnung[1]+ordnung[2]+ordnung[3]!=9)
4737 {fprintf(stderr, "%lld: Fehler bei D3\n", graphenzahl[map[0][0].name]+1); exit(54);}
4738 break;}
4739 case 6: {if (ordnung[0]+ordnung[1]+ordnung[2]+ordnung[3]+ordnung[4]+ordnung[5] !=15)
4740 {fprintf(stderr, "%lld: Fehler bei D5\n", graphenzahl[map[0][0].name]+1); exit(55);}
4741 break;}
4742 case 7: {BOOL d6=0; int k=1;
4743 for (i=0; i<7; i++) {k*=(int)(ordnung[i]); if (ordnung[i]==6) {d6=1;} }
4744 if (d6) {if (k!=64*6)
4745 {fprintf(stderr, "%lld: Fehler bei D6\n", graphenzahl[map[0][0].name]+1); exit(56);} }
4746 else {if (k!=81*8)
4747 {fprintf(stderr, "%lld: Fehler bei T\n", graphenzahl[map[0][0].name]+1); exit(57);} }
4748 break;
4749 }
4750 case 31: break;
4751 default: {fprintf(stderr, "%lld: Fehler 0 %d\n", graphenzahl[map[0][0].name]+1, n); exit(58);}
4752 }
4753 break;}
4754 case 1: {switch(n) {
4755 case 0: break;
4756 case 1: {switch(ordnung[0]) {
4757 case 2: break;
4758 case 3: break;
4759 default: {fprintf(stderr, "%lld: Fehler 1 1 %d\n", graphenzahl[map[0][0].name]+1,
4760 ordnung[0]); exit(59);}
4761 } break;}
4762 default: {fprintf(stderr, "%lld: Fehler 1 %d\n", graphenzahl[map[0][0].name]+1, n); exit(60);}
4763 }
4764 break;}
4765 case 2: {switch(n) {
4766 case 1: {if (ordnung[0]!=2)
4767 {fprintf(stderr, "%lld: Fehler bei C2v\n", graphenzahl[map[0][0].name]+1); exit(61);}
4768 break;}
4769 case 3: {if (ordnung[0]!=2 || ordnung[1]!=2 || ordnung[2]!=2)
4770 {fprintf(stderr, "%lld: Fehler bei D2d\n", graphenzahl[map[0][0].name]+1); exit(62);}
4771 break;}
4772 default: {fprintf(stderr, "%lld: Fehler 2 %d\n", graphenzahl[map[0][0].name]+1, n); exit(63);}
4773 }
4774 break;}
4775 case 3: {switch(n) {
4776 case 1: {if (ordnung[0]!=3)
4777 {fprintf(stderr, "%lld: Fehler bei C3v\n", graphenzahl[map[0][0].name]+1); exit(64);}
4778 break;}
4779 case 3: {if (ordnung[0]!=2 || ordnung[1]!=2 || ordnung[2]!=2)
4780 {fprintf(stderr, "%lld: Fehler bei D2h\n", graphenzahl[map[0][0].name]+1); exit(65);}
4781 break;}
4782 case 4: {if (ordnung[0]+ordnung[1]+ordnung[2]+ordnung[3]!=9)
4783 {fprintf(stderr, "%lld: Fehler bei D3d\n", graphenzahl[map[0][0].name]+1); exit(66);}
4784 break;}
4785 case 7: {int k=1;
4786 for (i=0; i<7; i++) {k*=(int)(ordnung[i]);}
4787 if (k!=81*8)
4788 {fprintf(stderr, "%lld: Fehler bei Th\n", graphenzahl[map[0][0].name]+1); exit(67);}
4789 break;}
4790 default: {fprintf(stderr, "%lld: Fehler 3 %d\n", graphenzahl[map[0][0].name]+1, n); exit(68);}
4791 }
4792 break;}
4793 case 4: {if (n!=4 || ordnung[0]+ordnung[1]+ordnung[2]+ordnung[3]!=9)
4794 {fprintf(stderr, "%lld: Fehler bei D3h\n", graphenzahl[map[0][0].name]+1); exit(69);}
4795 break;}
4796 case 5: {if (n!=6 || ordnung[0]*ordnung[1]*ordnung[2]*ordnung[3]*ordnung[4]*ordnung[5]!=32*5)
4797 {fprintf(stderr, "%lld: Fehler bei D5d\n", graphenzahl[map[0][0].name]+1); exit(77);}
4798 break;}
4799 case 6: {switch(n) {
4800 case 6: {if (ordnung[0]*ordnung[1]*ordnung[2]*ordnung[3]*ordnung[4]*ordnung[5]!=32*5)
4801 {fprintf(stderr, "%lld: Fehler bei D5h\n", graphenzahl[map[0][0].name]+1); exit(70);}
4802 break;}
4803 case 7: {BOOL d6=0; int k=1;
4804 for (i=0; i<7; i++) {k*=(int)(ordnung[i]); if (ordnung[i]==6) {d6=1;} }
4805 if (d6) {if (k!=64*6)
4806 {fprintf(stderr, "%lld: Fehler bei D6d\n", graphenzahl[map[0][0].name]+1); exit(71);} }
4807 else {if (k!=81*8)
4808 {fprintf(stderr, "%lld: Fehler bei Td\n", graphenzahl[map[0][0].name]+1); exit(72);} }
4809 break;}
4810 default: {fprintf(stderr, "%lld: Fehler 6 %d\n", graphenzahl[map[0][0].name]+1, n); exit(73);}
4811 }
4812 break;}
4813 case 7: {BOOL d6=0; int k=1;
4814 for (i=0; i<7; i++) {k*=(int)(ordnung[i]); if (ordnung[i]==6) {d6=1;} }
4815 if (d6==0 || n!=7 || k!=64*6)
4816 {fprintf(stderr, "%lld: Fehler bei D6h\n", graphenzahl[map[0][0].name]+1); exit(74);}
4817 break;}
4818 case 15: {if (n!=31) {fprintf(stderr, "%lld: Fehler bei Ih\n", graphenzahl[map[0][0].name]+1); exit(75);}
4819 break;}
4820 default: {fprintf(stderr, "%lld: Fehler %d %d\n", graphenzahl[map[0][0].name]+1, n2, n); exit(76);}
4821 }
4822
4823 /* Nun tatsaechliche Auswertung */
4824 switch(n2) {
4825 case 0: {switch(n) {
4826 case 0: return(Ci__);
4827 case 1: {if (drehsp==4) {return(S4__);}
4828 if (drehsp==6) {return(S6__);}
4829 switch(ordnung[0]) {
4830 case 2: return(C2__);
4831 case 3: return(C3__);
4832 default: exit(78);
4833 }
4834 break;}
4835 case 3: return(D2__);
4836 case 4: return(D3__);
4837 case 6: return(D5__);
4838 case 7: {BOOL d6=0;
4839 for (i=0; i<7; i++) {if (ordnung[i]==6) {d6=1;} }
4840 if (d6) {return(D6__);}
4841 else {return(T__);}
4842 }
4843 case 31: return(I__);
4844 default: exit(79);
4845 }
4846 break;}
4847 case 1: {switch(n) {
4848 case 0: return(Cs__);
4849 case 1: switch(ordnung[0]) {
4850 case 2: return(C2h__);
4851 case 3: return(C3h__);
4852 default: exit(80);
4853 }
4854 default: exit(0);
4855 }
4856 break;}
4857 case 2: {switch(n) {
4858 case 1: return(C2v__);
4859 case 3: return(D2d__);
4860 default: exit(81);
4861 }
4862 break;}
4863 case 3: {switch(n) {
4864 case 1: return(C3v__);
4865 case 3: return(D2h__);
4866 case 4: return(D3d__);
4867 case 7: return(Th__);
4868 default: exit(82);
4869 }
4870 break;}
4871 case 4: return(D3h__);
4872 case 5: return(D5d__);
4873 case 6: {switch(n) {
4874 case 6: return(D5h__);
4875 case 7: {BOOL d6=0;
4876 for (i=0; i<7; i++) {if (ordnung[i]==6) {d6=1;} }
4877 if (d6) {return(D6d__);}
4878 else {return(Td__);}
4879 }
4880 default: exit(83);
4881 }
4882 break;}
4883 case 7: return(D6h__);
4884 case 15: return(Ih__);
4885 default: exit(84);
4886 } /* switch */
4887
4888 } /* if code[1]==1 */
4889
4890 } /* Abgrenzung des Symmetrieteils (neue Variablen) */
4891 return 1; /* wird nie erreicht -- nur um Compilerwarnungen vorzubeugen */
4892 } /* Ende der Prozedur */
4893
4894
4895 /**********************CHECKSIZE_RIGHT_2**************************************/
4896
4897 /* bestimmt die groesse der flaeche rechts von edge -- ist da keine gibt's
4898 hier aber keine Probleme, sondern 6 wird zurueckgegeben -- dient nur
4899 zur Ueberpruefung, ob da ein 5-Eck ist.
4900
4901 Es wird allerdings angenommen, dass edge->name nicht aussen ist
4902 */
4903
4904
checksize_right_2(KANTE * edge)4905 int checksize_right_2( KANTE* edge)
4906 {
4907 KANTE *run;
4908 int zaehler=1;
4909
4910 for (run=edge->invers->prev; run != edge; run=run->invers->prev)
4911 { if (run->name==aussen) return(6); zaehler++; }
4912 return(zaehler);
4913 }
4914
4915
4916
4917
4918 /**********************CHECKSIZE_2**************************************/
4919
4920 /* bestimmt die groesse der flaeche links von edge -- ist da keine gibt's
4921 hier aber keine Probleme, sondern 6 wird zurueckgegeben -- dient nur
4922 zur Ueberpruefung, ob da ein 5-Eck ist.
4923
4924 Es wird allerdings angenommen, dass edge->name nicht aussen ist
4925 */
4926
4927
checksize_2(KANTE * edge)4928 int checksize_2( KANTE* edge)
4929 {
4930 KANTE *run;
4931 int zaehler=1;
4932
4933 for (run=edge->invers->next; run != edge; run=run->invers->next)
4934 { if (run->name==aussen) return(6);
4935 zaehler++; }
4936 return(zaehler);
4937 }
4938
4939
4940
4941
4942 /******************VERGLEICHE_SYMM************TH**************************/
4943 /* Diese Funktion prueft, ob die Nummer "nr" im Array "symm" auftritt,
4944 wobei die ersten "symm_len" Arrayelemente belegt sind. */
4945
vergleiche_symm(char nr)4946 BOOL vergleiche_symm(char nr) {
4947 int i;
4948 for (i=0; i<symm_len; i++) {
4949 if (symm[i]==nr) {return(True);}
4950 }
4951 return(False);
4952 }
4953
4954
4955 /***********************TESTE_UND_SCHREIBE*******TH***********************/
4956
4957 /* ueberprueft ein fertiges Fulleren, testet es auf Kanonizitaet und schreibt
4958 es gegebenenfalls auf */
4959
teste_und_schreibe(PLANMAP map,KNOTENTYP * code)4960 void teste_und_schreibe(PLANMAP map, KNOTENTYP *code)
4961 { int erg;
4962
4963 (non_iso_graphenzahl[map[0][0].name])++;
4964 if ((erg=minitest(map,code))) {
4965 (graphenzahl[map[0][0].name])++;
4966 if (symm_len==0 || vergleiche_symm(erg)) codiereplanar(map);
4967 (symm_anz[erg])++; /* fuer die Symmetriestatistik */
4968 }
4969
4970 }
4971
4972
4973 /***********************SUCHE_ITEM**************************************/
4974
suche_item(KNOTENTYP * adresse)4975 ITEMLISTE *suche_item(KNOTENTYP *adresse)
4976 {
4977 int i, laenge;
4978 SEQUENZLISTE *sq;
4979
4980 laenge=8-adresse[0];
4981
4982 sq=mapliste.sechser[adresse[1]];
4983
4984 for (i=2; i<laenge; i++)
4985 { if (sq->number_next <= adresse[i]) return(nil);
4986 if (sq->next_level[adresse[i]]==nil) return(nil);
4987 sq=sq->next_level[adresse[i]]; }
4988 return(sq->items);
4989 }
4990
4991
4992 /***********************SUCHE_ITEM_BB**************************************/
4993
suche_item_bb(KNOTENTYP * adresse)4994 BBITEMLISTE *suche_item_bb(KNOTENTYP *adresse)
4995 {
4996
4997 BBSEQUENZLISTE *sq;
4998
4999 sq=bbliste.sechser[adresse[1]];
5000
5001 if (sq->number_next <= adresse[2]) return(nil);
5002 return(sq->items[adresse[2]]);
5003 }
5004
5005
5006
5007 /*********************ADD_POLYGON_INVERS***********************************/
5008
add_polygon_invers(int n,PLANMAP map,KANTE * start,KANTE ** lastout)5009 void add_polygon_invers(int n, PLANMAP map, KANTE *start, KANTE **lastout)
5010 /* fuegt ein weiteres polygon einer Reihe an. Dabei ist n die groesse des polygons.
5011 Angefuegt wird immer an start. Ueber lastout wird die letzte Aussenkante des
5012 Polygons zurueckgegeben.
5013 Es arbeitet wie add_polygon nur im anderen Drehsinn. Das wird fuer die REkonstruktion
5014 der Patches gebraucht
5015 Im Falle, dass nur eine Kante eingefuegt werden muss, wird *lastout auf die naechste
5016 zu benutzende Aussenkante gesetzt. Die ist nicht mit dem gebauten Polygon
5017 inzident. Im Falle, dass es sie nicht gibt, wird *lastout auf nil gesetzt.
5018
5019 angefuegt wird in den Winkel in prev-Richtung, d.h. zwischen start und start->prev
5020
5021 */
5022
5023
5024 {
5025 int i, new_tempknz, tempknz;
5026 KANTE *ende, *run;
5027 int common_vertices;
5028
5029
5030 if (start->name != aussen) { fprintf(stderr,"ERROR ADD_P_INV not starting at external edge\n");
5031 exit(86); }
5032
5033 if (IPR && (n==5))
5034 {
5035 if (checksize_2(start->prev)==5) is_ipr=0;
5036 for (ende=start->prev->invers->prev, common_vertices=2; ende->name != aussen;
5037 ende=ende->invers->prev) {if (checksize_2(ende)==5) is_ipr=0;
5038 common_vertices++;
5039 }
5040 }
5041 else for (ende=start->prev->invers->prev, common_vertices=2; ende->name != aussen;
5042 ende=ende->invers->prev) common_vertices++;
5043
5044
5045 if (n<common_vertices)
5046 { fprintf(stderr,"polygon to insert (inv) too small !\n");
5047 exit(87); }
5048
5049 /* es muessen also n-common_vertices knoten hinzugefuegt werden */
5050
5051 tempknz=map[0][0].name;
5052 new_tempknz=tempknz+n-common_vertices;
5053
5054 if (n-common_vertices==0) /* dann kommt kein knoten dazu */
5055 { start->name=ende->ursprung; start->invers=ende;
5056 ende->name=start->ursprung; ende->invers=start;
5057
5058 for (ende=start->next->invers->next, common_vertices=2;
5059 (ende->name != aussen) && (common_vertices<6);
5060 ende=ende->invers->next) common_vertices++;
5061 if (common_vertices<6) *lastout=ende; /* ein common_vertices+1 -- Eck ist noch moeglich */
5062 else { *lastout=nil;
5063 if (ende==start->next) /* dann ist nur noch eine 5-Eck Luecke */
5064 { for (i=anzahl_5ek+5, run=start->invers; anzahl_5ek<i;
5065 anzahl_5ek++, run=run->invers->next) { F_eck_kanten[anzahl_5ek]=run;
5066 if (IPR)
5067 if (checksize_right_2(run)==5) is_ipr=0; }
5068 }
5069 }
5070 }
5071 else
5072 {
5073 if (n-common_vertices==1) /* dann kommt nur ein knoten dazu */
5074 {
5075 tempknz++;
5076 start->name=tempknz; start->invers=map[tempknz];
5077 map[tempknz][0].name=start->ursprung; map[tempknz][0].invers=start;
5078 map[tempknz][1].name=ende->ursprung; map[tempknz][1].invers=ende;
5079 ende->name=tempknz; ende->invers=map[tempknz]+1;
5080 map[tempknz][2].name=aussen; map[tempknz][2].invers=nil;
5081 *lastout=map[tempknz]+2;
5082 map[0][0].name=tempknz;
5083 }
5084 else
5085 {
5086
5087 /* es bleibt: mindestens zwei neue knoten */
5088
5089 tempknz++;
5090 start->name=tempknz; start->invers=map[tempknz];
5091 map[tempknz][0].name=start->ursprung; map[tempknz][0].invers=start;
5092 map[tempknz][1].name=tempknz+1; map[tempknz][1].invers=map[tempknz+1];
5093 map[tempknz][2].name=aussen; map[tempknz][2].invers=nil;
5094
5095 for (tempknz++; tempknz<new_tempknz; tempknz++)
5096 { map[tempknz][0].name=tempknz-1; map[tempknz][0].invers=map[tempknz-1]+1;
5097 map[tempknz][1].name=tempknz+1; map[tempknz][1].invers=map[tempknz+1];
5098 map[tempknz][2].name=aussen; map[tempknz][2].invers=nil; }
5099
5100 /* und nun noch den letzten knoten */
5101 map[tempknz][0].name=tempknz-1; map[tempknz][0].invers=map[tempknz-1]+1;
5102 map[tempknz][1].name=ende->ursprung; map[tempknz][1].invers= ende;
5103 ende->name=tempknz; ende->invers=map[tempknz]+1;
5104 map[tempknz][2].name=aussen; map[tempknz][2].invers=nil;
5105 *lastout=map[tempknz]+2;
5106 map[0][0].name=tempknz;
5107 } /* ende zweites else */
5108 } /* ende erstes else */
5109
5110 if (n==5)
5111 for (i=anzahl_5ek+5, run=start; anzahl_5ek<i;
5112 anzahl_5ek++, run=run->invers->next) F_eck_kanten[anzahl_5ek]=run;
5113
5114 return;
5115 }
5116
5117
5118 /***************************BAUE_KUPPE********************************/
5119
baue_kuppe(PLANMAP map,int bblaenge,FLAECHENTYP code[],KANTE ** anfang,int flaechenzahl)5120 void baue_kuppe(PLANMAP map, int bblaenge, FLAECHENTYP code[], KANTE **anfang, int flaechenzahl)
5121 {
5122 int i, puffer, codestelle, zaehler, flaechenzaehler;
5123 KANTE *run;
5124
5125
5126
5127 puffer=2*bblaenge;
5128
5129 if (*anfang==nil) /* d.h. Bauchbinde und obere Kuppe bauen und Anfang zurueckgeben */
5130 {
5131 map[1][0].name=puffer; map[1][0].invers=map[puffer]+1;
5132 map[1][1].name=aussen; map[1][1].invers=nil;
5133 map[1][2].name=2; map[1][2].invers=map[2];
5134
5135 for (i=2; i<2*bblaenge; i++)
5136 { map[i][0].name=i-1; map[i][0].invers=map[i-1]+2;
5137 map[i][1].name=i+1; map[i][1].invers=map[i+1];
5138 map[i][2].name=aussen; map[i][2].invers=nil;
5139 i++;
5140 map[i][0].name=i-1; map[i][0].invers=map[i-1]+1;
5141 map[i][1].name=aussen; map[i][1].invers=nil;
5142 map[i][2].name=i+1; map[i][2].invers=map[i+1];
5143 }
5144 map[puffer][0].name=puffer-1; map[puffer][0].invers=map[puffer-1]+2;
5145 map[puffer][1].name=1; map[puffer][1].invers=map[1];
5146 map[puffer][2].name=aussen; map[puffer][2].invers=nil;
5147
5148 map[0][0].name= puffer;
5149 *anfang=map[2]+2;
5150
5151 for (run=map[1]+1, zaehler=1; zaehler<= bblaenge*code[0]; zaehler++ )
5152 { add_polygon_invers(6, map, run, &run);
5153 if (run==nil) { fprintf(stderr,"ERROR: nil-edge while building hexagon rings\n");
5154 exit(88); }
5155 }
5156 flaechenzaehler=zaehler;
5157 for (codestelle=2, zaehler=1; run != nil; zaehler++, flaechenzaehler++ )
5158 {
5159 if ((codestelle<8) && (code[codestelle]==zaehler))
5160 { add_polygon_invers(5, map, run, &run); codestelle++; }
5161 else add_polygon_invers(6, map, run, &run);
5162 }
5163 if (flaechenzaehler != flaechenzahl)
5164 { fprintf(stderr,"Baue_Kuppe: Could not insert enough faces: ");
5165 fprintf(stderr,"%d instead of %d\n (upper half)\n",flaechenzaehler,flaechenzahl);
5166 exit(89); }
5167 } /* ende if *anfang==nil) */
5168 else /* d.h. untere Kuppe bauen */
5169 {
5170 for (run= *anfang, zaehler=1; zaehler <= bblaenge*code[0]; zaehler++ )
5171 { add_polygon_invers(6, map, run, &run);
5172 if (run==nil) { fprintf(stderr,"ERROR: nil-edge while building hexagon rings\n");
5173 exit(90); }
5174 }
5175 flaechenzaehler=zaehler;
5176 for (codestelle=2, zaehler=1; run != nil; zaehler++, flaechenzaehler++ )
5177 { if ((codestelle<8) && (code[codestelle]==zaehler))
5178 { add_polygon_invers(5, map, run, &run); codestelle++; }
5179 else add_polygon_invers(6, map, run, &run);
5180 }
5181 if (flaechenzaehler != flaechenzahl)
5182 { fprintf(stderr,"Baue_Kuppe: Could not insert enough faces: ");
5183 fprintf(stderr,"%d instead of %d\n (upper half)\n",flaechenzaehler,flaechenzahl);
5184 exit(91); }
5185 } /* ende else */
5186
5187 }
5188
5189
5190
5191 /*********************BAUCHBINDE****************************************/
5192
5193 /* Der erste Fall der Fullerenkonstruktion: Fullerene mit Bauchbinde */
5194 /* ___________________________
5195 / \
5196 | |
5197 | |
5198 | |
5199 \__________________________/ */
5200
5201
5202 /* konvention: Die obere haelfte is die mit mehr sechsecken. Ist die
5203 Anzahl der sechsecke gleich, so ist es die mit dem groesseren code ohne
5204 Beruecksichtigung der verschiebung. Wenn eine code-kombination betrachtet
5205 wird, wo die haelfte mit weniger sechsecken noch 6-Eck-Ringe hat, ist sie
5206 eh nicht minimal, da der Gesamt-code rekonstruiert von der bauchbinde aus,
5207 die man erhaelt, wenn man die Ringe nach oben verschiebt, kleiner ist. */
5208
5209 /* gesamtcode: (pfadlaenge,1,lowercode[],uppercode[],verschiebung)
5210 dabei wird beim vergleich die stelle, die in den codes die
5211 verschiebungsmoeglichkeiten beschreibt, nicht beruecksichtigt
5212 gesamtcodelaenge: 19 stellen */
5213
5214
bauchbinde(int min_sechsecke,int max_sechsecke)5215 void bauchbinde(int min_sechsecke, int max_sechsecke)
5216 {
5217 int sechsecke, i, j, k, bblaenge, upper6gons, lower6gons;
5218 KNOTENTYP adresse[4];
5219 KANTE *anfang, *merkeanfang; /* eine kante auf dem Rand zum Anfangen */
5220 KANTE *run;
5221 PLANMAP map;
5222 BBITEMLISTE *upitem, *lowitem;
5223 KNOTENTYP code[20];
5224 int modulozaehler;
5225
5226 modulozaehler=rest;
5227
5228 init_map(map);
5229
5230 adresse[0]=6;
5231 code[1]=1; code[19]=leer;
5232
5233 for (bblaenge=minbbl; bblaenge <= maxbbl; bblaenge++)
5234 if (bblmark[bblaenge])
5235 { adresse[2]=bblaenge;
5236 code[0]=2*bblaenge;
5237 for (sechsecke=min_sechsecke; sechsecke <= max_sechsecke; sechsecke++)
5238 for (upper6gons=sechsecke, lower6gons=0; upper6gons >= lower6gons;
5239 upper6gons--, lower6gons++)
5240 { adresse[1]=upper6gons;
5241 for (upitem=suche_item_bb(adresse); upitem != nil;
5242 upitem=upitem->next_item)
5243 { adresse[1]=lower6gons; merkeanfang=nil;
5244 for (k=0; k<8; k++) code[k+10]=upitem->code[k];
5245 for (lowitem=suche_item_bb(adresse); lowitem!=nil; lowitem=lowitem->next_item)
5246 if ((lowitem->code[0]==0) &&
5247 ((upper6gons>lower6gons) || (codecmp(upitem->code+2,lowitem->code+2,6)>=0)))
5248 /* hier geht schon die minimalitaet ein: Wenn es einen 6-Eck-Ring gibt, kann der
5249 nach oben verschoben werden und upper6gons wird noch groesser, lowercode
5250 noch kleiner, der code also besser
5251 Im Fall upper6gons==lower6gons,"(uppercode+2)<(lowercode+2)",aber upper6gons hat
5252 einen 6-eck-ring, kann ein besserer code durch verschieben des ringes und vertauschen
5253 von oben und unten gebaut werden */
5254 { modulozaehler++;
5255 if (modulozaehler==mod) modulozaehler=0;
5256 if (!mod || (modulozaehler==0))
5257 { /* so dass nur gebaut wird, wenn auch ein passendes Unterteil gefunden wird
5258 und auch dann nur einmal: */
5259 if (merkeanfang==nil) { map[0][0].name=0;
5260 anzahl_5ek=0;
5261 baue_kuppe(map,bblaenge,upitem->code,&merkeanfang,upper6gons+6); }
5262 for (k=0; k<8; k++) code[k+2]=lowitem->code[k];
5263 for (i=0, anfang=merkeanfang; (i<lowitem->code[1]) && (i<upitem->code[1]); i++,
5264 anfang=anfang->prev->invers->prev->invers->prev)
5265 { code[18]=i;
5266 anzahl_5ek=30;
5267 baue_kuppe(map,bblaenge,lowitem->code,&anfang,lower6gons+6);
5268 if ( is_ipr ) teste_und_schreibe(map,code); else is_ipr=1;
5269 /* Falls IPR nicht gesetzt ist, ist is_ipr immer 1 */
5270 /* Aufraeumen: */
5271 for (run=anfang, j=0; j<bblaenge;
5272 j++, run=run->next->invers->next->invers->next) run->name = aussen;
5273 map[0][0].name -= (2*lower6gons + 10 -bblaenge);
5274 } /* ende for ueber moegliche Marken bei lowitems */
5275 } /* ende if modulo */
5276 } /* ende for ueber lowitems */
5277 } /* ende for ueber upitems */
5278 } /* ende for ueber 6-Eckverteilung */
5279 } /* ende for ueber bauchbindenlaenge */
5280 } /* ende funktion */
5281
5282
5283
5284 /***********************SUCHESTART********************************/
5285
suchestart(KANTE * start)5286 KANTE *suchestart( KANTE *start)
5287 /* belegt eine sequenz und sucht die kanonische Kante mit dem kleinsten Namen
5288 arbeitet "invers", d.h. es wird als Innenrand gesehen, der gefuellt werden
5289 muss. Wird aufgerufen fuer Brille und Sandwich. Start muss eine Kante sein, die
5290 ins innere zeigt.*/
5291
5292 {
5293 int i, j, k, zaehler, position;
5294 KANTE *run;
5295 int sequenz[7];
5296 KANTE *seqkanten[7];
5297 int puffer[7];
5298 char kan[7];
5299
5300
5301
5302 while (start->next->invers->next->invers->next->name == aussen)
5303 start=start->next->invers->next->invers->next;
5304 /* Sucht 2 Kanten hintereinander nach aussen -- zu unterscheiden vom namen aussen, was
5305 auch nach innen heissen kann. Duerfte nur fuer bauchbinden eine Endlosschleife sein */
5306
5307 for (i=0; i<7; i++) { sequenz[i]=leer; seqkanten[i]=nil; kan[i]=0; }
5308
5309 position=0;
5310 seqkanten[0]=start;
5311
5312
5313 for (zaehler=1, run=start;
5314 run->prev->invers->prev->invers->prev->name == aussen;
5315 run=run->prev->invers->prev->invers->prev) zaehler++;
5316 sequenz[0]=zaehler; position=1; seqkanten[1]=nil;
5317 for (run=run->prev->invers->prev->invers->prev->invers->prev; run->name != aussen;
5318 run=run->invers->prev)
5319 { sequenz[position]=0; position++; seqkanten[position]=nil; }
5320 /* naechste Kante vor nicht-0-sequenz suchen -- entsprechende innenkanten gibt es nicht
5321 und muessen sich dementsprechend auch nicht gemerkt werden */
5322
5323
5324 while (run != start)
5325 {
5326 seqkanten[position]=run;
5327 for (zaehler=1;
5328 run->prev->invers->prev->invers->prev->name == aussen;
5329 run=run->prev->invers->prev->invers->prev) { zaehler++; }
5330 sequenz[position]=zaehler; position++; seqkanten[position]=nil;
5331 for (run=run->prev->invers->prev->invers->prev->invers->prev; run->name != aussen;
5332 run=run->invers->prev)
5333 { sequenz[position]=0; position++; seqkanten[position]=nil; }
5334 }
5335
5336
5337 sequenz[position]=leer; seqkanten[position]=nil;
5338
5339 kan[0]=sequenz_kanonisch(sequenz);
5340
5341
5342 for (i=0; sequenz[i] != leer; i++)
5343 { for (j=i, k=0; sequenz[j]!=leer; j++, k++) puffer[k]=sequenz[j];
5344 for (j=0; j<i; j++, k++) puffer[k]=sequenz[j];
5345 puffer[k]=leer;
5346 kan[i]=sequenz_kanonisch(puffer);
5347 }
5348
5349
5350
5351 for (i=0, run=nil; sequenz[i] != leer; i++)
5352 { if (kan[i])
5353 if ((run==nil) || (seqkanten[i]->ursprung < run->ursprung)) run=seqkanten[i];
5354 }
5355
5356 /* Jetzt die vorige Innenkante suchen, um rechts davon dann einfuegen zu koennen */
5357 for (run=run->next->invers->next->invers->next; run->name != aussen; run=run->invers->next);
5358
5359
5360 return(run);
5361
5362
5363 }
5364
5365 /*******************BERECHNE_BRILLENADRESSEN*************************/
5366
5367 /* berechnet die adressen 2 und 3 im Brillenfall .
5368 uebergeben werden l1 l3 und lgesamt. berechnet werden die
5369 sequenzen */
5370
berechne_brillenadressen(int l1,int lg,int l3,KNOTENTYP * seg,KNOTENTYP * se3)5371 void berechne_brillenadressen( int l1, int lg, int l3, KNOTENTYP *seg,
5372 KNOTENTYP *se3 )
5373 {int l2, zaehler;
5374 int bogen1, bogen3;
5375
5376 l2 = lg - l1 - l3;
5377
5378
5379 if ((l1%2) != 0) lg--;
5380
5381 if ((l3 % 2) ==0) /* l3 gerade */
5382 { se3[0]=4; se3[2]= (l3-2)/2; se3[3]=0; }
5383 else { se3[0]=5; se3[2]= (l3-1)/2; lg--; }
5384
5385 /* Jetzt die grosse Sequenz: */
5386
5387 if ((l2 % 2) == 0) /* "normale" Brille */
5388 {
5389 if (l1%2) /* d.h. ungerade -- bestimmt den Umlaufsinn */
5390 { if ((lg % 2)==0) seg[2]=lg/2; else seg[2]= (lg-1)/2;
5391 zaehler=3;
5392 if (l3 % 2) { seg[zaehler]=0; zaehler++; }
5393 seg[zaehler]= (l2-2)/2; zaehler++;
5394 if (l1 % 2) { seg[zaehler]=0; zaehler++; }
5395 seg[0]=8-zaehler;
5396 }
5397 else /* d.h. l1 gerade -- anderer Umlaufsinn */
5398 { if ((lg % 2)==0) seg[2]=lg/2; else seg[2]= (lg-1)/2;
5399 zaehler=3;
5400 if (l1 % 2) { seg[zaehler]=0; zaehler++; }
5401 seg[zaehler]= (l2-2)/2; zaehler++;
5402 if (l3 % 2) { seg[zaehler]=0; zaehler++; }
5403 seg[0]=8-zaehler;
5404 }
5405 }/* ende "normale" Brille */
5406 else /* d.h. "verbogene" Brille */
5407 {
5408 if (l1%2) bogen1= (l1+l2-2)/2; else bogen1=(l1+l2-1)/2;
5409 if (l3%2) bogen3= (l3+l2-2)/2; else bogen3=(l3+l2-1)/2;
5410 /* um das gleich kanonisch geordnet zu haben, muss da unterschieden werden */
5411 if (l1%2){
5412 /* l1 >= l3 reicht nicht, um die folgende Fallunterscheidung zu vermeiden */
5413 if ((bogen1 > bogen3) || ((bogen1==bogen3) && ((l3 % 2) == 0)))
5414 { seg[2]=bogen1;
5415 zaehler=3;
5416 if (l3 % 2) { seg[zaehler]=0; zaehler++; }
5417 seg[zaehler]=bogen3; zaehler++;
5418 if (l1 % 2) { seg[zaehler]=0; zaehler++; }
5419 seg[0]=8-zaehler;
5420 }
5421 else /* d.h. bogen3 kommt zuerst */
5422 { seg[2]=bogen3;
5423 zaehler=3;
5424 if (l1 % 2) { seg[zaehler]=0; zaehler++; }
5425 seg[zaehler]=bogen1; zaehler++;
5426 if (l3 % 2) { seg[zaehler]=0; zaehler++; }
5427 seg[0]=8-zaehler;
5428 }
5429 }
5430 else /* d.h. l1 gerade */
5431 {
5432 /* keine Fallunterscheidung, da if immer true durch konvention l1>=l3 */
5433 /* if ((bogen1 > bogen3) || ((bogen1==bogen3) && ((l1 % 2) == 0))) */
5434 seg[2]=bogen1;
5435 seg[3]=bogen3;
5436 zaehler=4;
5437 if (l3 % 2) { seg[zaehler]=0; zaehler++; }
5438 seg[0]=8-zaehler;
5439 }
5440 } /* ende verbogene brille */
5441
5442 }
5443
5444 /********************BAUE_BRILLE***********************************/
5445
5446 /* baut eine Brille. Dabei ist die Orientierung von Knoten mit
5447 ungerader Nummer auf dem Pfad immer vorher->aussen->nachher
5448 GEWAEHLT. Da zu jedem Patch frueher oder spaeter
5449 auch das Spiegelbild behandelt wird, ist diese Festlegung moeglich,
5450 aber Achtung -- das ist wichtig fuer die kanonische Darstellung */
5451
baue_brille(int pfadlaenge,int laenge_1,int laenge_3,PLANMAP map,KANTE ** anfang_1,KANTE ** anfang_2,KANTE ** anfang_3)5452 void baue_brille(int pfadlaenge,int laenge_1,int laenge_3,PLANMAP map,
5453 KANTE **anfang_1, KANTE **anfang_2, KANTE **anfang_3)
5454 {
5455 int stelle_2, knotenzahl, i;
5456 KANTE *aussenzeiger, *letzte_Kante, *startkante_1, *startkante_2;
5457
5458 knotenzahl=pfadlaenge-1;
5459
5460 /* zuerst:
5461
5462 knotenzahl-------stelle_2----------stelle1-------
5463 |
5464 1 |
5465 | |
5466 2--3-----
5467 ohne die zykelschliessenden Kanten */
5468
5469
5470
5471 map[1][1].name=2; map[1][1].invers=map[2]+0;
5472 for (i=1; i<=knotenzahl; i++)
5473 { map[i][0].name=i-1; map[i][0].invers=map[i-1]+1;
5474 map[i][1].name=aussen; map[i][1].invers=nil;
5475 map[i][2].name=i+1; map[i][2].invers=map[i+1]+0;
5476 i++;
5477 if (i<=knotenzahl)
5478 { map[i][0].name=i-1; map[i][0].invers=map[i-1]+2;
5479 map[i][2].name=aussen; map[i][2].invers=nil;
5480 map[i][1].name=i+1; map[i][1].invers=map[i+1]+0; }
5481 }
5482
5483 /* Knoten 1 und Knoten knotenzahl haben jetzt falsche vorher bzw nachher
5484 werte, sie muessen jetzt mit der Brille verklebt werden */
5485
5486 if ((laenge_1%2)==0) aussenzeiger=map[laenge_1]+2; else aussenzeiger=map[laenge_1]+1;
5487
5488 aussenzeiger->name=1; aussenzeiger->invers=map[1]+0;
5489 map[1][0].name=laenge_1; map[1][0].invers=aussenzeiger;
5490
5491 stelle_2=pfadlaenge-laenge_3;
5492 if ((stelle_2%2)==0) aussenzeiger=map[stelle_2]+2; else aussenzeiger=map[stelle_2]+1;
5493 if ((knotenzahl%2)==0) letzte_Kante=map[knotenzahl]+1; else letzte_Kante=map[knotenzahl]+2;
5494
5495 letzte_Kante->name=stelle_2; letzte_Kante->invers=aussenzeiger;
5496 aussenzeiger->name=knotenzahl; aussenzeiger->invers=letzte_Kante;
5497
5498 map[0][0].name=knotenzahl;
5499
5500 /* Jetzt die anfangskanten belegen: */
5501
5502 if ((laenge_1 %2)==0) { startkante_1=map[2]+2; startkante_2=map[1]+1; }
5503 /* dann zeigt die Aussenkante von Knoten 2 ins innere von zykel_1 */
5504 else { startkante_2=map[2]+2; startkante_1=map[1]+1; }
5505 *anfang_1=suchestart(startkante_1);
5506 *anfang_2=suchestart(startkante_2);
5507
5508 if ((knotenzahl%2)==0)
5509 { if ((laenge_3 % 2)==0) startkante_1=map[knotenzahl-1]+1;
5510 else startkante_1=map[knotenzahl]+2; }
5511 else /* d.h. knotenzahl ungerade */
5512 { if ((laenge_3 % 2)==0) startkante_1=map[knotenzahl-1]+2;
5513 else startkante_1=map[knotenzahl]+1; }
5514 *anfang_3=suchestart(startkante_1);
5515
5516 } /* ende funktion */
5517
5518
5519
5520 /*********************INSERT_PATCH*********************************/
5521
insert_patch(PLANMAP map,KANTE * anfang,ITEMLISTE * item,int flaechenzahl,int fuenfecke)5522 void insert_patch(PLANMAP map, KANTE *anfang, ITEMLISTE *item, int flaechenzahl, int fuenfecke)
5523 {
5524
5525 FLAECHENTYP *code;
5526 KANTE *run;
5527 int zaehler, codestelle;
5528
5529 code=item->code;
5530 for (codestelle=0, zaehler=1, run=anfang; run != nil; zaehler++ )
5531 {
5532 if ((codestelle<fuenfecke) && (code[codestelle]==zaehler))
5533 { add_polygon_invers(5, map, run, &run); codestelle++; }
5534 else add_polygon_invers(6, map, run, &run);
5535 }
5536 if (zaehler != flaechenzahl)
5537 { fprintf(stderr,"Insert_patch: Could not insert enough faces: ");
5538 fprintf(stderr,"%d instead of %d\n (insert_patch)\n",zaehler,flaechenzahl);
5539 exit(92); }
5540 }
5541
5542
5543 /**********************DELETE_PATCH**************************************/
5544
delete_patch(PLANMAP map,KANTE * anfang,KNOTENTYP * adresse)5545 void delete_patch(PLANMAP map, KANTE *anfang, KNOTENTYP *adresse)
5546 {
5547 int sqlaenge, randlaenge, i, j, knotenverlust;
5548 KANTE *run;
5549
5550 sqlaenge=6-adresse[0];
5551 for (i=2, randlaenge=sqlaenge; i<= 1+sqlaenge; i++) randlaenge+=(2*adresse[i]);
5552
5553 knotenverlust=(3*adresse[0])+randlaenge;
5554 knotenverlust= knotenverlust/2; /* diese konstruktion nur Sicherheitshalber, damit kein
5555 Compiler die Ordnung "erst 3a[0]+r" aufloest */
5556 knotenverlust= knotenverlust+(2*adresse[1])+1-randlaenge;
5557 /*alles nur Euler-Formel*/
5558
5559 map[0][0].name = map[0][0].name - knotenverlust;
5560
5561 for (i=1+sqlaenge; adresse[i]==0; i--);
5562 for ( run=anfang ; i>1 ; i--)
5563 { if (adresse[i])
5564 { for (j=0; j < adresse[i]; j++)
5565 {
5566 run->name=aussen; run->invers=nil; run = run->next->invers->next->invers->next; }
5567 run=run->invers->next;
5568 }
5569 else { run=run->invers->next; }
5570 }
5571 }
5572
5573
5574
5575 /*********************BRILLE****************************************/
5576
5577 /* Der zweite Fall der Fullerenkonstruktion: Fullerene mit Brille */
5578 /*
5579
5580 | l2 |
5581 _________________________
5582 / | | \
5583 | l3 | | l1 |
5584 \______/ \______/
5585
5586
5587 _______ oder
5588 / \
5589 | |
5590 \_________|_____________________
5591 | \
5592 | |
5593 \________/
5594
5595 Der Unterschied ist, ob das Mittelstueck l2 gerade oder ungerade viele
5596 Kanten enthaelt --- kombinatorisch ist es einfach ein Graph mit 2
5597 Knoten, die durch eine Kante verbunden sind und jeder hat eine
5598 Schleife (eine "Hantel").
5599
5600 Die Brille wird als Pfad mit Anfang und Ende interpretiert mit l1 >=
5601 l3, d.h. erste Schleife nicht kleiner als zweite und Orientierung um
5602 ungerade Knoten vorher->aussen->nachher
5603
5604 Die Markierungen sind die nach dieser Ordnung vom kleinsten Knoten
5605 ausgehenden Kanten mit folgender kanonischer Sequenz. Sie sind an der
5606 letzten Innenkante des ersten einzufuegenden Polygons.
5607
5608
5609 Der gesamtcode: (pfadlaenge,2,l1,l3,code1[],code2[],code3[])
5610 gesamtcodelaenge:16
5611
5612 */
5613
5614
5615
brille(int min_sechsecke,int max_sechsecke)5616 void brille(int min_sechsecke, int max_sechsecke)
5617 {
5618 int knotenzahl, pfadlaenge, s1ps2;
5619 int laenge_1, laenge_3;
5620 KNOTENTYP adresse_1[6], adresse_2[6],adresse_3[6];
5621 int sixgons_1, sixgons_2, sixgons_3; /* zur besseren lesbarkeit -- es koennte auch immer adresse_i[1]
5622 benutzt werden */
5623 KANTE *anfang_1, *anfang_2, *anfang_3; /* eine kanonische Kante auf dem Rand zum Anfangen */
5624 ITEMLISTE *item_1, *item_2, *item_3;
5625 BOOL gebaut_1, gebaut_2, ipr_fault_item2;
5626 PLANMAP map;
5627 KNOTENTYP code[20];
5628 int j, czmerke_1, czmerke_2, czmerke_3;
5629 int modulozaehler;
5630
5631 modulozaehler=rest;
5632
5633 knotenzahl= 20 + 2*max_sechsecke;
5634
5635 init_map(map);
5636
5637 code[1]=2;
5638
5639 for (pfadlaenge=2*minbrillenglas+1; pfadlaenge <= knotenzahl+1; pfadlaenge++)
5640 { /* EINZIGE Konvention: laenge_1 >= laenge_3 --- dann darf keine konvention
5641 fuer die 6-Ecke mehr erfolgen ! */
5642 code[0]=pfadlaenge;
5643 for (laenge_1=minbrillenglas; (laenge_1 <= maxbrillenglas) &&
5644 (laenge_1 < pfadlaenge-minbrillenglas); laenge_1++)
5645 if (brillenglasmark[laenge_1])
5646 { if ((laenge_1 % 2)==0)
5647 { adresse_1[0]=4; adresse_1[2]=(laenge_1-2)/2; adresse_1[3]=0; }
5648 else { adresse_1[0]=5; adresse_1[2]=(laenge_1-1)/2; }
5649 code[2]=laenge_1;
5650 for (sixgons_1=0; sixgons_1 <= max_sechsecke; sixgons_1++)
5651 /* auch hier kann man besser abschaetzen */
5652 { adresse_1[1]=sixgons_1;
5653 for (item_1=suche_item(adresse_1); item_1 != nil; item_1=item_1->next_item)
5654 {
5655 czmerke_1=4+adresse_1[0];
5656 for (j=4; j<czmerke_1; j++) code[j]=item_1->code[j-4];
5657 for (laenge_3=minbrillenglas;
5658 (laenge_3 <= laenge_1) && (laenge_1+laenge_3 < pfadlaenge); laenge_3++)
5659 if (brillenglasmark[laenge_3])
5660 {
5661 modulozaehler++;
5662 if (modulozaehler==mod) modulozaehler=0;
5663 if (!mod || (modulozaehler==0))
5664 {
5665 code[3]=laenge_3;
5666 berechne_brillenadressen(laenge_1,pfadlaenge,laenge_3,adresse_2,adresse_3);
5667 gebaut_1=0; /* Man koennte auch patch_1 immer in der aeusseren
5668 Schleife bauen und dann die Brille verschieden fortsetzen, aber erst Brille bauen
5669 und dann die patches einkleben erscheint mir sympathischer und weniger fehleranfaellig --
5670 wenn auch von der Komplexitaet her ein wenig schlechter */
5671 for (sixgons_2=0; sixgons_2 <= max_sechsecke-sixgons_1; sixgons_2++)
5672 { s1ps2=sixgons_1 + sixgons_2;
5673 adresse_2[1]=sixgons_2;
5674 for (sixgons_3=max_sechsecke-s1ps2; (sixgons_3>=min_sechsecke-s1ps2) && (sixgons_3>=0);
5675 sixgons_3--)
5676 {
5677 adresse_3[1]=sixgons_3;
5678 for (item_2=suche_item(adresse_2); item_2 != nil; item_2=item_2->next_item)
5679 { is_ipr=1; ipr_fault_item2=0;
5680 gebaut_2=0;
5681 czmerke_2=czmerke_1+adresse_2[0];
5682 for (j=czmerke_1; j<czmerke_2; j++) code[j]=item_2->code[j-czmerke_1];
5683 for (item_3=suche_item(adresse_3); (item_3 != nil) && (!ipr_fault_item2);
5684 item_3=item_3->next_item)
5685 { czmerke_3=czmerke_2+adresse_3[0];
5686 for (j=czmerke_2; j<czmerke_3; j++) code[j]=item_3->code[j-czmerke_2];
5687 if (gebaut_1==0) {
5688 anzahl_5ek=0;
5689 baue_brille(pfadlaenge,laenge_1,laenge_3,map, &anfang_1, &anfang_2,&anfang_3);
5690 insert_patch(map,anfang_1,item_1,sixgons_1+adresse_1[0],adresse_1[0]);
5691 gebaut_1=1;
5692 }
5693 if (gebaut_2==0)
5694 { anzahl_5ek=5*adresse_1[0];
5695 insert_patch(map,anfang_2,item_2,sixgons_2+adresse_2[0],adresse_2[0]);
5696 gebaut_2=1;
5697 if (is_ipr==0) ipr_fault_item2=1;}
5698 anzahl_5ek=5*(12-adresse_3[0]);
5699 if (is_ipr)
5700 { insert_patch(map,anfang_3,item_3,sixgons_3+adresse_3[0],adresse_3[0]);
5701 if (is_ipr) teste_und_schreibe(map,code); else is_ipr=1;
5702 delete_patch(map,anfang_3,adresse_3); }
5703 } /* ende for ueber item_3 */
5704 if (gebaut_2) delete_patch(map,anfang_2,adresse_2);
5705 } /* ende for ueber item_2 */
5706 } /* ende for ueber sixgons_3 */
5707 } /* ende for ueber sixgons_2 */
5708 map[0][0].name=0; /* entspricht loeschen von map */
5709 }
5710 } /* ende for ueber laenge_3 */
5711 } /* ende for ueber item_1 */
5712 } /* ende for ueber sixgons_1 */
5713 } /* ende for ueber laenge_1 */
5714 } /* ende for ueber pfadlaenge */
5715 } /* ende funktion */
5716
5717
5718 /*********************BERECHNE_ADRESSE3********************************/
5719
berechne_adresse3(int l1,int l3,KNOTENTYP adresse[])5720 void berechne_adresse3(int l1, int l3, KNOTENTYP adresse[])
5721 {
5722 int sl1, sl3;
5723
5724 if (l1%2) { sl1=(l1-1)/2;
5725 if (l3%2) { sl3=(l3-1)/2; adresse[0]=4;
5726 if (sl3>sl1) { adresse[2]=sl3; adresse[3]=sl1; }
5727 else { adresse[2]=sl1; adresse[3]=sl3; }
5728 } else /* d.h. l3 gerade */
5729 { sl3=(l3-2)/2;
5730 adresse[0]=3;
5731 if (sl3>sl1) { adresse[2]=sl3; adresse[3]=0; adresse[4]=sl1; }
5732 else { adresse[2]=sl1;
5733 adresse[3]=sl3; adresse[4]=0; }
5734 }
5735 }
5736
5737 else { sl1=(l1-2)/2;
5738 if (l3%2) { sl3=(l3-1)/2;
5739 adresse[0]=3;
5740 if (sl3>sl1) { adresse[2]=sl3; adresse[3]=0; adresse[4]=sl1; }
5741 else { adresse[2]=sl1; adresse[3]=sl3; adresse[4]=0; }
5742 } else /*d.h. l3 gerade */
5743 { sl3=(l3-2)/2;
5744 adresse[0]=2;
5745 if (sl3>sl1) { adresse[2]=sl3; adresse[3]=0; adresse[4]=sl1; adresse[5]=0; }
5746 else { adresse[2]=sl1; adresse[3]=0; adresse[4]=sl3; adresse[5]=0; }
5747 }
5748 }
5749 }
5750
5751
5752 /*********************BAUE_SANDWICH***********************************/
5753
baue_sandwich(PLANMAP map,int laenge_1,int laenge_2,int laenge_3,KANTE ** anfang_1,KANTE ** anfang_2,KANTE ** anfang_3)5754 void baue_sandwich(PLANMAP map, int laenge_1, int laenge_2, int laenge_3,
5755 KANTE **anfang_1, KANTE **anfang_2, KANTE **anfang_3)
5756
5757 { int stelle_2, knotenzahl, i, stelle, pfadlaenge;
5758 KANTE *aussenzeiger, *letzte_Kante, *startkante_1, *startkante_2,*startkante_3;
5759
5760 pfadlaenge=laenge_1+laenge_2+laenge_3; knotenzahl=pfadlaenge-1;
5761
5762
5763 map[1][1].name=2; map[1][1].invers=map[2]+0;
5764 for (i=1; i<=knotenzahl; i++)
5765 { map[i][0].name=i-1; map[i][0].invers=map[i-1]+1;
5766 map[i][1].name=aussen; map[i][1].invers=nil;
5767 map[i][2].name=i+1; map[i][2].invers=map[i+1]+0;
5768 i++;
5769 if (i<=knotenzahl) {
5770 map[i][0].name=i-1; map[i][0].invers=map[i-1]+2;
5771 map[i][2].name=aussen; map[i][2].invers=nil;
5772 map[i][1].name=i+1; map[i][1].invers=map[i+1]+0;
5773 }
5774 }
5775
5776 /* Knoten 1 und Knoten knotenzahl haben jetzt falsche vorher bzw
5777 nachher werte, sie muessen jetzt mit dem Sandwich verklebt werden */
5778
5779 stelle=laenge_1+laenge_2;
5780 if ((stelle%2)==0) aussenzeiger=map[stelle]+2; else aussenzeiger=map[stelle]+1;
5781
5782 aussenzeiger->name=1; aussenzeiger->invers=map[1]+0;
5783 map[1][0].name=stelle; map[1][0].invers=aussenzeiger;
5784
5785 if ((laenge_1%2)==0) aussenzeiger=map[laenge_1]+2;
5786 else aussenzeiger=map[laenge_1]+1;
5787 if ((knotenzahl%2)==0) letzte_Kante=map[knotenzahl]+1; else letzte_Kante=map[knotenzahl]+2;
5788
5789 letzte_Kante->name=laenge_1; letzte_Kante->invers=aussenzeiger;
5790 aussenzeiger->name=knotenzahl; aussenzeiger->invers=letzte_Kante;
5791
5792 map[0][0].name=knotenzahl;
5793
5794 /* Jetzt die anfangskanten belegen: */
5795
5796 if (laenge_2==1) stelle_2= stelle+1; else stelle_2=stelle-1;
5797 if (stelle %2) { startkante_1=map[1]+1; startkante_2=map[stelle_2]+2; startkante_3=map[2]+2; }
5798 /* dann zeigt die Aussenkante von Knoten 1 ins innere von zykel_1 */
5799 else { startkante_1=map[2]+2; startkante_2=map[stelle_2]+1; startkante_3=map[1]+1; }
5800 *anfang_1=suchestart(startkante_1);
5801 *anfang_2=suchestart(startkante_2);
5802 *anfang_3=suchestart(startkante_3);
5803
5804 } /* ende funktion */
5805
5806
5807
5808
5809
5810
5811
5812 /************************SANDWICH***************************************/
5813
5814 /* Sandwich ist der 3. Fall :
5815
5816 l1
5817 --------------------
5818 / \
5819 / l2 oder l3 \
5820 O--------------------------O
5821 \ /
5822 \ l2 oder l3 /
5823 --------------------
5824
5825 d.h.:
5826
5827 l1
5828 -----------------
5829 / \
5830 O |
5831 ______l2___________/
5832 /
5833 | ^
5834 | |
5835 \______l3_________/
5836
5837 oder das Spiegelbild:
5838
5839 l1
5840 -----------------
5841 / \
5842 O |
5843 ______l3_________> |
5844 / |
5845 | |
5846 | |
5847 \______l2__________/
5848
5849
5850 l2 muss immer ungerade sein !
5851
5852 Konvention: Die Orientierung um Knoten 1 und damit alle ungeraden
5853 Knoten auf dem Pfad ist vorher->aussen->nachher und desweiteren:
5854 l1 >= l3
5855
5856 Der gesamtcode: (pfadlaenge,3,l1,l2,code1[],code2[],code3[])
5857 gesamtcodelaenge:16
5858
5859
5860 */
5861
5862
5863
sandwich(int min_sechsecke,int max_sechsecke)5864 void sandwich (int min_sechsecke, int max_sechsecke)
5865
5866 {
5867 int knotenzahl, maxpfadlaenge, s1ps2;
5868 int laenge_1, laenge_2, laenge_3;
5869 KNOTENTYP adresse_1[6], adresse_2[6], adresse_3[6];
5870 int sixgons_1, sixgons_2, sixgons_3; /* zur besseren lesbarkeit -- es koennte auch
5871 immer adresse_i[1] benutzt werden. s_1 ist
5872 die Anzahl der 6-Ecke zwischen l1 und l2. s_2 zwischen
5873 l2 und l3 und s_3..... analog fuer adresse und item */
5874 KANTE *anfang_1, *anfang_2, *anfang_3; /* eine kanonische Kante auf dem Rand zum Anfangen */
5875 ITEMLISTE *item_1, *item_2, *item_3;
5876 int randl_p1, randl_p2, randl_p3;
5877 BOOL gebaut_1, gebaut_2, ipr_fault_item2;
5878 PLANMAP map;
5879 KNOTENTYP code[20];
5880 int j, czmerke_1, czmerke_2, czmerke_3;
5881 int modulozaehler;
5882
5883 modulozaehler=rest;
5884 /* l1--l2 und l2--l3 bilden je ein brillenglas */
5885
5886
5887 knotenzahl= 20 + 2*max_sechsecke; maxpfadlaenge=knotenzahl+1;
5888 init_map(map);
5889 code[1]=3;
5890
5891 for (laenge_1=(min_2_3_4 /2); laenge_1 <= maxpfadlaenge-minbrillenglas; laenge_1++)
5892 {
5893 code[2]=laenge_1;
5894 for (laenge_2=1; laenge_2 <= maxpfadlaenge-min_2_3_4; laenge_2 += 2) /* muss immer ungerade sein ! */
5895 { randl_p1=laenge_1+laenge_2;
5896 if (brillenglasmark[randl_p1])
5897 { /* l1+l2 umrahmt patch 1 */
5898 code[3]=laenge_2;
5899 if (randl_p1%2) { adresse_1[0]=5; adresse_1[2]=(randl_p1-1)/2; }
5900 else { adresse_1[0]=4; adresse_1[2]=(randl_p1-2)/2; adresse_1[3]=0; }
5901 for (sixgons_1=0; sixgons_1 <= max_sechsecke; sixgons_1++)
5902 {
5903 adresse_1[1]=sixgons_1;
5904 for (item_1=suche_item(adresse_1); item_1 != nil; item_1=item_1->next_item)
5905 {
5906 modulozaehler++;
5907 if (modulozaehler==mod) modulozaehler=0;
5908 if (!mod || (modulozaehler==0))
5909 {
5910 czmerke_1=4+adresse_1[0];
5911 for (j=4; j<czmerke_1; j++) code[j]=item_1->code[j-4];
5912 for (laenge_3=1; ((randl_p1 + laenge_3) <= maxpfadlaenge) && (laenge_1>= laenge_3); laenge_3++)
5913 { randl_p2=laenge_2+laenge_3;
5914 randl_p3=laenge_3+laenge_1;
5915 if (brillenglasmark[randl_p2] && zwei_3_4_mark[randl_p3])
5916 { code[0]=laenge_3 + randl_p1;
5917 gebaut_1=0;
5918 if (randl_p2%2) { adresse_2[0]=5; adresse_2[2]=(randl_p2-1)/2; }
5919 else { adresse_2[0]=4; adresse_2[2]=(randl_p2-2)/2; adresse_2[3]=0; }
5920 /* fuer den patch zwischen l1 und l3 ist die Lage leider komplizierter */
5921 berechne_adresse3(laenge_1,laenge_3,adresse_3);
5922 for (sixgons_2=0; sixgons_2 <= max_sechsecke-sixgons_1; sixgons_2++)
5923 { s1ps2=sixgons_1 + sixgons_2;
5924 adresse_2[1]=sixgons_2;
5925 for (sixgons_3=max_sechsecke-s1ps2; (sixgons_3>=min_sechsecke-s1ps2) && (sixgons_3>=0);
5926 sixgons_3--)
5927 {
5928 adresse_3[1]=sixgons_3;
5929 for (item_2=suche_item(adresse_2); item_2 != nil; item_2=item_2->next_item)
5930 { is_ipr=1; ipr_fault_item2=0;
5931 gebaut_2=0;
5932 czmerke_2=czmerke_1+adresse_2[0];
5933 for (j=czmerke_1; j<czmerke_2; j++) code[j]=item_2->code[j-czmerke_1];
5934 for (item_3=suche_item(adresse_3); (item_3 != nil) && (!ipr_fault_item2);
5935 item_3=item_3->next_item)
5936 {
5937 czmerke_3=czmerke_2+adresse_3[0];
5938 for (j=czmerke_2; j<czmerke_3; j++) code[j]=item_3->code[j-czmerke_2];
5939 /* Der Kern */
5940 if (gebaut_1==0)
5941 { anzahl_5ek=0;
5942 baue_sandwich(map,laenge_1,laenge_2,laenge_3,&anfang_1,&anfang_2,&anfang_3);
5943 gebaut_1=1;
5944 insert_patch(map,anfang_1,item_1,sixgons_1+adresse_1[0],adresse_1[0]); }
5945 if (gebaut_2==0)
5946 { anzahl_5ek= 5*adresse_1[0];
5947 insert_patch(map,anfang_2,item_2,sixgons_2+adresse_2[0],adresse_2[0]);
5948 gebaut_2=1;
5949 if (is_ipr==0) ipr_fault_item2=1; }
5950 anzahl_5ek=5*(12-adresse_3[0]);
5951 if (is_ipr)
5952 { insert_patch(map,anfang_3,item_3,sixgons_3+adresse_3[0],adresse_3[0]);
5953 if (is_ipr) teste_und_schreibe(map,code); else is_ipr=1;
5954 delete_patch(map,anfang_3,adresse_3); }
5955 /* Ende Kern */
5956
5957
5958 } /* ende for ueber item_3 */
5959 if (gebaut_2) delete_patch(map,anfang_2,adresse_2);
5960 } /*ende for ueber item_2 */
5961 } /* ende for ueber sixgons_3 */
5962 } /* ende for ueber sixgons_2 */
5963 map[0][0].name=0; /* entspricht loeschen */
5964 } /* ende if randl_p2 und randl_p3 OK */
5965 } /* ende for ueber laenge_3 */
5966 }
5967 } /* ende for ueber item_1 */
5968 } /* ende for ueber sixgons_1 */
5969 } /* ende if randl_p1 OK */
5970 } /* ende for ueber laenge_2; */
5971 } /* ende for ueber laenge_1 */
5972
5973 } /* ende funktion */
5974
5975
5976 /**************************MAIN*********************************************/
5977
main(argc,argv)5978 int main(argc,argv)
5979
5980 int argc; char *argv[];
5981
5982 { int sechsecke, i, puffer, do_case;
5983 char strpuf[filenamenlaenge], strpuf2[filenamenlaenge], strdummy[filenamenlaenge];
5984 struct stat buf;
5985 char name[4]; /* TH - fuer die Option "symm" */
5986 FLAECHENTYP dummycode[12]={UCHAR_MAX,UCHAR_MAX,UCHAR_MAX,0,0,0,0,0,0,0,0,0};
5987 FLAECHENTYP *dummypointer;
5988
5989 #ifndef NOTIMES
5990 clock_t savetime=0, buffertime;
5991 struct tms TMS;
5992 #endif //NOTIMES
5993
5994 int separate_logfile = 1;
5995
5996 #ifdef __GNUC__
5997 #ifdef __alpha__
5998 fprintf(stderr,"With gcc on alphas some errors might occur if you use -O3 or more.\n");
5999 fprintf(stderr,"This is a bug of the compiler.\n");
6000 fprintf(stderr,"Please use cc on alphas -- the result will be a faster program anyway.\n");
6001 exit(0);
6002 #endif
6003 #endif
6004
6005
6006 for (i=1;i<=N;i++) graphenzahl[i]=non_iso_graphenzahl[i]=0;
6007
6008 do_brille=do_sandwich=do_bauchbinde=1;
6009
6010 do_case=0;
6011
6012
6013 symmstring[0] = 0; /* TH - Filekennung loeschen */
6014
6015 if (argc<2) exit(93);
6016
6017
6018 knotenzahl=atoi(argv[1]);
6019 if ((knotenzahl%2) || (knotenzahl<20)) { fprintf(stderr,"Impossible vertex number. \n"); exit(94); }
6020
6021 min_sechsecke=max_sechsecke=sechsecke=(knotenzahl-20)/2;
6022
6023
6024 if (knotenzahl >= leer) { fprintf(stderr,"Number of vertices too large for the data-types used. \n"); exit(95); }
6025 if (aussen >= leer) { fprintf(stderr,"Definition of \"S\" too large for the data-types used. \n"); exit(96); }
6026 if (S+12 > FL_MAX) { fprintf(stderr,"Definition of \"S\" too large for the data-types used for FLAECHENTYP. \n");
6027 exit(97); }
6028
6029 if (sechsecke > S) { fprintf(stderr,"Fix the constant \"S\" to at least %d\n",sechsecke); exit(98); }
6030
6031 codenumber=listenlaenge=0;
6032
6033 for (i=2; i<argc; i++)
6034 switch (argv[i][0])
6035 {
6036 case 'i': { if (strcmp(argv[i],"ipr")==0) IPR=1;
6037 else { fprintf(stderr,"Nonidentified option: %s \n",argv[i]); exit(99); }
6038 break; }
6039
6040 case 'h': { if (strcmp(argv[i],"hexspi")==0) hexspi=1;
6041 else { fprintf(stderr,"Nonidentified option: %s \n",argv[i]); exit(100); }
6042 break; }
6043
6044 case 's': { if (strcmp(argv[i],"start")==0)
6045 { i++; puffer=atoi(argv[i]);
6046 if ((puffer%2) || (puffer<20))
6047 { fprintf(stderr,"Impossible vertex number to start. \n"); exit(101); }
6048 min_sechsecke=(puffer-20)/2; }
6049 else
6050 if (strcmp(argv[i],"stdout")==0) to_stdout=1;
6051 else
6052 if (strcmp(argv[i],"spistat")==0) spistat=1;
6053 else
6054 if (strcmp(argv[i],"spiralcheck")==0) spiralcheck=1;
6055 else
6056 if (strcmp(argv[i],"symstat")==0) symstat=1; /* TH */
6057 else
6058 if (strcmp(argv[i],"symm")==0) { /* TH */
6059 int j=28, ii;
6060 BOOL gefunden = False;
6061 symstat=1; /* immer -- kostet ja nichts extra */
6062 i++;
6063 if (i<argc) {
6064 while (j>0 && !gefunden) {
6065 for (ii=0; ii<=3; ii++) {
6066 name[ii] = (symm_name[j][ii]==' ') ? '\0' : symm_name[j][ii];
6067 }
6068 if (strcmp(argv[i],name)==0) { /* Symmetrie j gefunden */
6069 gefunden = True;
6070 if (!vergleiche_symm(j)) /* Symmetrie noch nicht in Liste */
6071 {symm[symm_len++] = j;
6072 strcat(symmstring,(char *)"_"); strcat(symmstring,name);}
6073 }
6074 j--;
6075 }
6076 }
6077 if (!gefunden)
6078 {fprintf(stderr,"Unknown symmetry identifier. \n"); exit(102);}
6079 break;
6080 } /* if */
6081 else { fprintf(stderr,"Nonidentified option: %s \n",argv[i]); exit(103); }
6082 break; }
6083 case 'c': { if (strcmp(argv[i],"code")==0)
6084 { i++; codenumber=atoi(argv[i]); }
6085 else
6086 if (strcmp(argv[i],"case")==0)
6087 { i++; do_case=atoi(argv[i]);
6088 switch (do_case)
6089 { case 1: { do_brille=do_sandwich=0; do_bauchbinde=1; break; }
6090 case 2: { do_brille=1; do_sandwich=do_bauchbinde=0; break; }
6091 case 3: { do_brille=do_bauchbinde=0; do_sandwich=1; break; }
6092 default: { fprintf(stderr,"No such case !\n"); exit(104); }
6093 }
6094 }
6095 else { fprintf(stderr,"Nonidentified option: %s \n",argv[i]); exit(105); }
6096 break; }
6097 case 'p': { if (strcmp(argv[i],"pid")==0) {fprintf(stdout,"%d\n",getpid()); fflush(stdout);}
6098 else {fprintf(stderr,"Nonidentified option: %s \n",argv[i]); exit(119);}
6099 break;
6100 }
6101 case 'q': { if (strcmp(argv[i],"quiet")==0) quiet=1;
6102 else {fprintf(stderr,"Nonidentified option: %s \n",argv[i]); exit(120);}
6103 break;
6104 }
6105 case 'l': { if (strcmp(argv[i],"list")==0)
6106 { i++; listenlaenge=atoi(argv[i]); }
6107 else if (strcmp(argv[i],"logerr")==0) {
6108 logfile = stderr;
6109 separate_logfile = 0;
6110 }
6111 else { fprintf(stderr,"Nonidentified option: %s \n",argv[i]); exit(106); }
6112 break; }
6113
6114 case 'm': { if (strcmp(argv[i],"mod")==0)
6115 { i++; rest=atoi(argv[i]); i++; mod=atoi(argv[i]);
6116 if ((mod<=0) || (rest<0) || (rest>=mod))
6117 { fprintf(stderr,"Bad values for option mod \n"); exit(0); }
6118 }
6119 else { fprintf(stderr,"Nonidentified option: %s \n",argv[i]); exit(106); }
6120 break; }
6121
6122
6123
6124 default: { fprintf(stderr,"Nonidentified option: %s \n",argv[i]); exit(107); }
6125 }
6126
6127
6128 switch (codenumber)
6129 {
6130 case 0: break;
6131 case 1:
6132 case 8: { for (i=20+(2*min_sechsecke); i<=knotenzahl; i+=2)
6133 { if (IPR) sprintf(strpuf,"Full_codes_%d_ipr",i);
6134 else sprintf(strpuf,"Full_codes_%d",i);
6135 if (do_case) { sprintf(strpuf2,"_c%d",do_case); strcat(strpuf,strpuf2); }
6136 if (mod) { sprintf(strpuf2,"_m_%d_%d",rest,mod); strcat(strpuf,strpuf2); }
6137 if (symm_len>0) {strcat(strpuf,symmstring);}
6138 if (to_stdout) fil[i]=stdout; else fil[i]=fopen(strpuf,"wb");
6139 if (!to_stdout) write_header_fil[i]=1;
6140 if (fil[i]==nil) { fprintf(stderr,"Can not open file %s. \n",strpuf); exit(109);}
6141 }
6142 break; }
6143 case 2: { for (i=20+(2*min_sechsecke); i<=knotenzahl; i+=2)
6144 { if (IPR) sprintf(strpuf,"Spiral_codes_%d_ipr",i);
6145 else sprintf(strpuf,"Spiral_codes_%d",i);
6146 if (do_case) { sprintf(strpuf2,"_c%d",do_case); strcat(strpuf,strpuf2); }
6147 if (mod) { sprintf(strpuf2,"_m_%d_%d",rest,mod); strcat(strpuf,strpuf2); }
6148 if (symm_len>0) {strcat(strpuf,symmstring);}
6149 if (to_stdout) fil[i]=stdout; else fil[i]=fopen(strpuf,"wb");
6150 if (!to_stdout) write_header_fil[i]=1;
6151 if (fil[i]==nil) { fprintf(stderr,"Can not open file %s. \n",strpuf); exit(110);}
6152 }
6153 spiralcheck=1;
6154 last_code[0]=FL_MAX;
6155 break; }
6156 case 3: { spiralcheck=1;
6157 if (listenlaenge==0) listenlaenge=2000;
6158 for (i=20+(2*min_sechsecke); i<=knotenzahl; i+=2)
6159 { (codeliste[i].code)[0]=0;
6160 if (IPR) sprintf(strpuf,"Spiral_codes_%d_ipr",i);
6161 else sprintf(strpuf,"Spiral_codes_%d",i);
6162 if (do_case) { sprintf(strpuf2,"_c%d",do_case); strcat(strpuf,strpuf2); }
6163 if (mod) { sprintf(strpuf2,"_m_%d_%d",rest,mod); strcat(strpuf,strpuf2); }
6164 if (symm_len>0) {strcat(strpuf,symmstring);}
6165 if (to_stdout) fil[i]=stdout; else fil[i]=fopen(strpuf,"wb");
6166 if (!to_stdout) write_header_fil[i]=1;
6167 if (fil[i]==nil) { fprintf(stderr,"Can not open file %s. \n",strpuf); exit(111);}
6168 lastcode[i]=(FLAECHENTYP **)malloc(sizeof(FLAECHENTYP *));
6169 if (lastcode[i] ==nil) { fprintf(stderr,"Can not get memory for lastcode. \n"); exit(112); }
6170 (*(lastcode[i]))=(FLAECHENTYP *)malloc(sizeof(FLAECHENTYP)*12);
6171 (*(lastcode[i]))[0]=FL_MAX;
6172 }
6173 break; }
6174 case 4: spiralcheck=1; break; /* Nur nicht-spiral-codes schreiben */
6175 case 5: { spiralcheck=1;
6176 for (i=20+(2*min_sechsecke); i<=knotenzahl; i+=2)
6177 { if (IPR) sprintf(strpuf,"Full_codes_%d_ipr",i);
6178 else sprintf(strpuf,"Full_codes_%d",i);
6179 if (do_case) { sprintf(strpuf2,"_c%d",do_case); strcat(strpuf,strpuf2); }
6180 if (mod) { sprintf(strpuf2,"_m_%d_%d",rest,mod); strcat(strpuf,strpuf2); }
6181 if (symm_len>0) {strcat(strpuf,symmstring);}
6182 if (to_stdout) fil[i]=stdout; else fil[i]=fopen(strpuf,"wb");
6183 if (fil[i]==nil) { fprintf(stderr,"Can not open file %s. \n",strpuf); exit(113);}
6184 if (!to_stdout) write_header_fil[i]=1;
6185 }
6186 break; }
6187
6188 case 6: { break; }
6189
6190 case 7: { break; }
6191
6192 default: { fprintf(stderr,"No coding number %d. \n", codenumber); exit(114); }
6193 }
6194
6195 if (hexspi && !spiralcheck)
6196 { fprintf(stderr,"The option \"hexspi\" must be used together with some code involving spiral checking \n");
6197 exit(115); }
6198
6199 if (spistat && (min_sechsecke != max_sechsecke))
6200 { fprintf(stderr,"The option \"spistat\" must be used only for fullerenes of ONE size \n");
6201 exit(116); }
6202
6203 if (spistat) for (i=0; i<=12*max_sechsecke+120; i++) spiralnumbers[i]=0;
6204
6205
6206 if (IPR)
6207 { if (min_sechsecke==max_sechsecke) sprintf(logfilename,"Full_gen_%d_ipr",knotenzahl);
6208 else sprintf(logfilename,"Full_gen_%d_%d_ipr",knotenzahl,(2*min_sechsecke)+20); }
6209 else
6210 { if (min_sechsecke==max_sechsecke) sprintf(logfilename,"Full_gen_%d",knotenzahl);
6211 else sprintf(logfilename,"Full_gen_%d_%d",knotenzahl,(2*min_sechsecke)+20); }
6212
6213 if (do_case) { sprintf(strpuf2,"_c%d",do_case); strcat(logfilename,strpuf2); }
6214 if (mod) { sprintf(strpuf2,"_m_%d_%d",rest,mod); strcat(logfilename,strpuf2); }
6215 if (spiralcheck) { sprintf(no_spiral_filename,"No_spiral_");
6216 strcat(no_spiral_filename,logfilename+9);
6217 sprintf(strdummy,"rm %s",no_spiral_filename);
6218 if (!stat(strdummy,&buf)) {
6219 if(system (strdummy)==-1){
6220 fprintf(stderr,"Could not execute system call.\n");
6221 }
6222 }
6223 sprintf(no_penta_spiral_filename,"No_pentagon_spiral_");
6224 strcat(no_penta_spiral_filename,logfilename+9);
6225 sprintf(strdummy,"rm %s",no_penta_spiral_filename);
6226 if (!stat(strdummy,&buf)) {
6227 if(system (strdummy)==-1){
6228 fprintf(stderr,"Could not execute system call.\n");
6229 }
6230 }
6231 }
6232 if (hexspi) { sprintf(no_hexa_spiral_filename,"No_hexagon_spiral_");
6233 strcat(no_hexa_spiral_filename,logfilename+9);
6234 sprintf(strdummy,"rm %s",no_hexa_spiral_filename);
6235 if (!stat(strdummy,&buf)) {
6236 if(system (strdummy)==-1){
6237 fprintf(stderr,"Could not execute system call.\n");
6238 }
6239 }
6240 }
6241
6242 if (!quiet)
6243 {
6244 strcat(logfilename,".log");
6245 if (separate_logfile) logfile=fopen(logfilename,"w");
6246 if (logfile==nil) { fprintf(stderr,"Can not open file %s. \n",logfilename); exit(118);}
6247 fprintf(logfile,"Minimal vertex number: %d \n",(2*min_sechsecke)+20);
6248 fprintf(logfile,"Maximal vertex number: %d \n",knotenzahl);
6249 fprintf(logfile,"Code_type: %d \n",codenumber);
6250 if (codenumber==3) fprintf(logfile,"List length: %d \n",listenlaenge);
6251 if (separate_logfile) fclose(logfile);
6252 }
6253
6254
6255 initialize_list();
6256
6257 baue_patches(sechsecke);
6258 #ifndef NOTIMES
6259 times(&TMS);
6260 savetime= TMS.tms_utime;
6261 if (!quiet)
6262 { fprintf(stderr,"Time for generating the patches: %.1f seconds \n",(double)savetime/time_factor);
6263 if (separate_logfile) {
6264 logfile=fopen(logfilename,"a");
6265 fprintf(logfile,"Time for generating the patches: %.1f seconds \n",(double)savetime/time_factor);
6266 fclose(logfile);
6267 }
6268 }
6269 #endif //NOTIMES
6270
6271 if (do_bauchbinde)
6272 {
6273 bauchbinde(min_sechsecke,max_sechsecke);
6274 #ifndef NOTIMES
6275 times(&TMS);
6276 buffertime= TMS.tms_utime;
6277 if (!quiet)
6278 { fprintf(stderr,"Time for case 1 (Jordan-Curve Petrie Path): %.1f seconds \n",(double)(buffertime-savetime)/time_factor);
6279 if (separate_logfile) {
6280 logfile=fopen(logfilename,"a");
6281 fprintf(logfile,"Time for case 1 (Jordan-Curve Petrie Path): %.1f seconds \n",(double)(buffertime-savetime)/time_factor);
6282 fclose(logfile);
6283 }
6284 }
6285 savetime=buffertime;
6286 #endif //NOTIMES
6287 }
6288
6289 if (do_brille)
6290 {
6291 brille(min_sechsecke,max_sechsecke);
6292 #ifndef NOTIMES
6293 times(&TMS);
6294 buffertime= TMS.tms_utime;
6295 if (!quiet)
6296 { fprintf(stderr,"Time for case 2 (Dumb-bell): %.1f seconds \n",(double)(buffertime-savetime)/time_factor);
6297 if (separate_logfile) {
6298 logfile=fopen(logfilename,"a");
6299 fprintf(logfile,"Time for case 2 (Dumb-bell): %.1f seconds \n",(double)(buffertime-savetime)/time_factor);
6300 fclose(logfile);
6301 }
6302 savetime=buffertime;
6303 }
6304 #endif //NOTIMES
6305 }
6306
6307 if (do_sandwich)
6308 {
6309 sandwich(min_sechsecke,max_sechsecke);
6310 #ifndef NOTIMES
6311 times(&TMS);
6312 buffertime= TMS.tms_utime;
6313 if (!quiet)
6314 { fprintf(stderr,"Time for case 3 (Sandwich): %.1f seconds \n\n",(double)(buffertime-savetime)/time_factor);
6315 if (separate_logfile) {
6316 logfile=fopen(logfilename,"a");
6317 fprintf(logfile,"Time for case 3 (Sandwich): %.1f seconds \n\n",(double)(buffertime-savetime)/time_factor);
6318 fclose(logfile);
6319 }
6320 }
6321 #endif //NOTIMES
6322 }
6323
6324 if (codenumber==3)
6325 for (i=20+(2*min_sechsecke); i<=knotenzahl; i++) { dummypointer=dummycode; ausgabe(codeliste+i,i,&dummypointer); }
6326
6327
6328 if (!quiet)
6329 {
6330 fprintf(stderr,"MAPLIST: number of patches: %d\n",mapliste.total_maps);
6331 fprintf(stderr,"BBLIST: number of items in list: %d number of patches: %d\n\n",bbliste.total_items,bbliste.total_maps);
6332 for (i=20+(2*min_sechsecke); i<=20+(2*max_sechsecke); i+=2)
6333 fprintf(stderr,"Generated %lld maps on %d vertices -- reduced to %lld non-isomorphic maps. \n",non_iso_graphenzahl[i],i,graphenzahl[i]);
6334 if (spistat) for (i=0; i<=12*max_sechsecke+120; i++)
6335 if (spiralnumbers[i]) fprintf(stderr,"Fullerenes with %d spirals: %d \n",i,spiralnumbers[i]);
6336 if (spiralcheck) fprintf(stderr,"Graphs without a spiral starting at a pentagon: %d \n",no_penta_spiral);
6337 if (hexspi) fprintf(stderr,"Graphs without a spiral starting at a hexagon: %d \n",no_hexa_spiral);
6338 if (symstat) schreibe_symmetriestatistik();
6339 #ifndef NOTIMES
6340 fprintf(stderr,"\nTotal generation time: %.1f seconds \n",(double)buffertime/time_factor);
6341 #endif //NOTIMES
6342 fprintf(stderr,"end of program\n");
6343
6344 if (separate_logfile) {
6345 logfile=fopen(logfilename,"a");
6346 fprintf(logfile,"MAPLIST: number of patches: %d\n",mapliste.total_maps);
6347 fprintf(logfile,"BBLIST: number of items in list: %d number of patches: %d\n\n",bbliste.total_items,bbliste.total_maps);
6348 for (i=20+(2*min_sechsecke); i<=20+(2*max_sechsecke); i+=2)
6349 fprintf(logfile,"Generated %lld maps on %d vertices -- reduced to %lld non-isomorphic maps. \n",non_iso_graphenzahl[i],i,graphenzahl[i]);
6350 if (spistat) for (i=0; i<=12*max_sechsecke+120; i++)
6351 if (spiralnumbers[i]) fprintf(logfile,"Fullerenes with %d spirals: %d \n",i,spiralnumbers[i]);
6352 if (spiralcheck) fprintf(logfile,"Graphs without a spiral starting at a pentagon: %d \n",no_penta_spiral);
6353 if (hexspi) fprintf(logfile,"Graphs without a spiral starting at a hexagon: %d \n",no_hexa_spiral);
6354 if (symstat) { /* schreibe Symmetriestatistik */
6355 int j=0;
6356 fprintf(logfile,"Symmetries:\n");
6357 for (i=1; i<=28; i++) {
6358 if (symm_anz[i]>0) {
6359 fprintf(logfile," %s: %10d ",symm_name[i],symm_anz[i]);
6360 j++;
6361 if (j%4==0) {fprintf(logfile,"\n");}
6362 }
6363 }
6364 if (j%4) {fprintf(logfile,"\n");}
6365 }
6366 #ifndef NOTIMES
6367 fprintf(logfile,"\nTotal generation time: %.1f seconds \n",(double)buffertime/time_factor);
6368 #endif //NOTIMES
6369 fprintf(logfile,"end of program\n");
6370 }
6371 }
6372
6373 return(0);
6374 }
6375
6376