The program below counts polyominoes with fourfold rotational symmetry that have inner rings of length 16 or more with the ring centered on a face. The ring is passed to a subroutine that determines the possible outside and inside additions that can be made to it, and these are conjoined to obtain a full count. Results appear in the rows labeled 16, 24, .... Rings can be classified as chiral and achiral. The achiral results appear in the first 16,24,... and 20,28,... lines below. The chiral results appear farther down. Separate programs are required to obtain results for ring sizes of 4, 8, and 12, none of which can have inside additions. Here are the calculations for n-ominoes with n divisible by four and inner-ring size r. r\n 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 4 1 2 5 15 49 162 551 1930 6875 24807 90556 333774 1239876 4636171 17435443 8 1 3 8 25 83 285 994 3529 12734 46469 171106 635074 2373269 8920590 12 1 4 12 39 133 463 1638 5882 21401 78709 291932 1090347 4096964 16,24,... 2 10 39 146 549 2050 7626 28441 106513 400386 1510159 5715076 20,28,... 2 13 58 234 921 3581 13763 52524 200082 762640 2910211 Total 1 3 9 29 98 336 1173 4170 15013 54630 200630 742626 2767350 10372586 39078284 A142886 1 1 3 5 12 20 45 80 173 310 664 1210 2570 4728 9976 Diff. 2 6 24 86 316 1128 4090 14840 54320 199966 741416 2764780 10367858 39068308 Half 1 3 12 43 158 564 2045 7420 27160 99983 370708 1382390 5183929 19534154 16,24,... 2 15 78 368 1663 7261 30927 129685 538288 2217470 20,28,... 1 5 24 112 495 2113 8867 36830 151645 619994 2522143 A144553 1 3 12 44 165 603 2235 8283 30936 116111 438465 1663720 6342211 24273767 For values of A144553 with n equivalent to one modulus four (which must include the center face), we run a separate program that counts polyominoes that have a child at (0,0) and may not include (1,0), which we call 1* below. The entries for 8(n-1) are the same as for 8 above. The results are r\n 1 5 9 13 17 21 25 29 33 37 41 45 49 53 57 61 1* 1 1 1 3 10 32 108 373 1314 4712 17119 62799 232344 866000 3247962 12246708 8(n-1) 1 3 8 25 83 285 994 3529 12734 46469 171106 635074 2373269 8920590 Sum->1 1 1 2 6 18 57 191 658 2308 8241 29853 109268 403450 1501074 5621231 21167298 A142886 1 1 2 2 4 7 11 20 36 65 117 216 396 736 1369 2558 Diff. 4 14 50 180 638 2272 8176 29736 109052 403054 1500338 5619862 21164740 A144553 2 7 25 90 319 1136 4088 14868 54526 201527 750169 2809931 10582370 There are three separate C++ program files below: main.cpp, Lattice.cpp, and Lattice.hpp. They are separated by a long comment line filled with asterisks. The programs are not finished products. The programs can be run in parallel by using separate values of acol for different runs or breaking down the inner loops used even further. The output provides results for achiral and chiral inner loops separately. In addition, these numbers are broken down by inner-loop size. The number of inner loops used is also shown. Timing is for my 2010 iMac with a 2.93 GHz processor. /****************************************************************************************/ // // main.cpp // ring_4c2_16p // // Created by Robert A Russell on 10/16/21. // Copyright © 2021 Robert A Russell. All rights reserved. // #include "Lattice.hpp" // this program calculates the number of polyominoes with fourfold rotational symmetry and an even // number of cells in a ring quadrant, beginning with four. Each ring is cnetered on the center // of a tile. int main(int argc, const char * argv[]) { for (int acol=MINCOL; acol<NCOLR-1; acol++) { cout << "acol=" << acol << endl; RLattice lattice(acol); lattice.get_rings(); } //cout << endl; print_poly_count(); print_ring_count(); return 0; } /****************************************************************************************/ // // Lattice.cpp // ring_4c2_16p // // Created by Robert A Russell on 10/16/21. // Copyright © 2021 Robert A Russell. All rights reserved. // #include "Lattice.hpp" static Int ring_count[NMAX][2] = {0}; static Int poly_count[NMAX][NMAX][2] = {0}; // [ring size - 4][poly_size - 4][chiral] RLattice::RLattice(int acol_in) { acol = acol_in; for (int i=0; i<NROWR; i++) for (int j=0; j<NCOLR; j++) lattice[i][j] = R_EMPTY; for (int i=0; i<acol; i++) lattice[0][i] = R_FORBIDDEN; count[0] = 0; count[1] = 0; ring[0] = {0,short(acol),0,R_DOWN,{R_UP,R_RIGHT,NONE},0,{NULL,NULL}}; lattice[0][acol] = 1; next_ring = 1; } void RLattice::add_ring() { // we add ring[next_ring] and then increase next_ring until we reach RINGQ // then we determine if ring is achiral or chiral with correct sense // then we repeat delete_ring until we have a new opportunity to do add_ring // determine coordinates of next cell int row=ring[next_ring-1].row, col=ring[next_ring-1].col, quadrant = ring[next_ring-1].quadrant, prev_direction=R_NONE; switch (ring[next_ring-1].next_direction[ring[next_ring-1].next_direction_index]) { case R_LEFT: if (col) { // if column is not zero col--; prev_direction = R_RIGHT; } else { // move to higher quadrant col = ROWM; row = 0; quadrant++; prev_direction = R_DOWN; } break; case R_UP: row++; prev_direction = R_DOWN; break; case R_RIGHT: col++; prev_direction = R_LEFT; break; case R_DOWN: if (ring[next_ring-1].row) { // if row is not zero) row--; prev_direction = R_UP; } else { // move to lower quadrant row = COLP; col = 0; quadrant--; prev_direction = R_LEFT; } break; } // can we use this new ring cell? if (lattice[row][col] // new ring cell is occupied || row >= NROWR || col >= NCOLR // ring cell is too far out || (quadrant && ((!col && (acol==row || acol+2==row)) || (1==col && acol+1==row))) // touch last ) { while (next_ring && (++ring[next_ring-1].next_direction_index > 2 || R_NONE == ring[next_ring-1].next_direction[ring[next_ring-1].next_direction_index])) delete_ring(); return; // we are ready to add_ring() again } // check distance to goal, (acol,0) int distance; switch (quadrant) { case 0: // goal is (acol+1,0) distance = col + abs(LASTROW - row); break; case 1: // left one quadrant (r,c)->(c+1,-1-r) distance = row + 1 + abs(col - acol); break; case -1: // ight one quadrant (r,c)->(-col-1,r-1) distance = abs(ROWM) + LASTROW + col + 1; break; case 2: // left two quadrants case -2: // right two quadrants distance = row + col + LASTROW + 2; break; default: cout << "bad exit -2\n"; exit (-2); } if (1 == distance) { // if we are adjacent to last cell if (NMAX - 2 >= next_ring) { // if we have a complete ring if (col) { // if the cell is (LASTROW,1) ring[next_ring] = {char(LASTROW),1,0,char(prev_direction), {R_LEFT,R_NONE,R_NONE},0,{NULL,NULL}}; ring[next_ring+1] = {char(LASTROW),0,0,R_RIGHT,{R_LEFT,R_NONE,R_NONE},0,{NULL,NULL}}; } else if (LASTROW-1==row) { // if the cell is (acol,0) ring[next_ring] = {char(LASTROW-1),0,0,char(prev_direction), {R_UP,R_NONE,R_NONE},0,{NULL,NULL}}; ring[next_ring+1] = {char(LASTROW),0,0,R_DOWN,{R_LEFT,R_NONE,R_NONE},0,{NULL,NULL}}; } else { // if the cell is (LASTROW+1,0) ring[next_ring] = {char(LASTROW+1),0,0,char(prev_direction), {R_DOWN,R_NONE,R_NONE},0,{NULL,NULL}}; ring[next_ring+1] = {char(LASTROW),0,0,R_UP,{R_LEFT,R_NONE,R_NONE},0,{NULL,NULL}}; } // check for wrong chirality switch (ring_chirality()) { case 1: // chiral right process_ring(true); break; case 0: // achiral process_ring(false); break; case -1: break; // chiral left: wrong chirality } } while (next_ring && (++ring[next_ring-1].next_direction_index > 2 || R_NONE == ring[next_ring-1].next_direction[ring[next_ring-1].next_direction_index])) delete_ring(); return; } // 1 == distance if (distance < NMAX - next_ring) { // add another ring cell // insert border cells for ring[next_ring-1] int bi = 0; // index for border[] switch (ring[next_ring-1].prev_direction) { case R_LEFT: switch (ring[next_ring-1].next_direction[ring[next_ring-1].next_direction_index]) { case R_UP: // two outside if (ring[next_ring-1].col < NCOLR-1) { // if we can go more right RCell *bcell = lattice[ring[next_ring-1].row] + ring[next_ring-1].col + 1; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } if (ring[next_ring-1].row) { // if we can go down RCell *bcell = lattice[ring[next_ring-1].row-1] + ring[next_ring-1].col; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } else { // we can't go down; need a new quadrant RCell *bcell = lattice[ring[next_ring-1].COLP]; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } break; case R_RIGHT: // UP inside, DOWN outside if (ring[next_ring-1].row < NROWR-1) { // if we can go more up RCell *bcell = lattice[ring[next_ring-1].row + 1] + ring[next_ring-1].col; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } if (ring[next_ring-1].row) { // if we can go down RCell *bcell = lattice[ring[next_ring-1].row-1] + ring[next_ring-1].col; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } else { // we can't go down; need a new quadrant RCell *bcell = lattice[ring[next_ring-1].COLP]; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } break; case R_DOWN: // two inside if (ring[next_ring-1].row < NROWR-1) { // if we can go more up RCell *bcell = lattice[ring[next_ring-1].row + 1] + ring[next_ring-1].col; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } if (ring[next_ring-1].col < NCOLR-1) { // if we can go more right RCell *bcell = lattice[ring[next_ring-1].row] + ring[next_ring-1].col + 1; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } break; } break; case R_UP: switch (ring[next_ring-1].next_direction[ring[next_ring-1].next_direction_index]) { case R_RIGHT: // two outside if (ring[next_ring-1].row) { // if we can go down RCell *bcell = lattice[ring[next_ring-1].row-1] + ring[next_ring-1].col; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } else { // we can't go down; need a new quadrant RCell *bcell = lattice[ring[next_ring-1].COLP]; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } if (ring[next_ring-1].col) { // if we can go left RCell *bcell = lattice[ring[next_ring-1].row] + ring[next_ring-1].col - 1; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } else { // we can't go left; need a new quadrant RCell *bcell = lattice[0] + ring[next_ring-1].ROWM; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } break; case R_DOWN: // RIGHT inside, LEFT outside if (ring[next_ring-1].col < NCOLR-1) { // if we can go more right RCell *bcell = lattice[ring[next_ring-1].row] + ring[next_ring-1].col + 1; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } if (ring[next_ring-1].col) { // if we can go left RCell *bcell = lattice[ring[next_ring-1].row] + ring[next_ring-1].col - 1; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } else { // we can't go left; need a new quadrant RCell *bcell = lattice[0] + ring[next_ring-1].ROWM; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } break; case R_LEFT: // two inside if (ring[next_ring-1].col < NCOLR-1) { // if we can go more right RCell *bcell = lattice[ring[next_ring-1].row] + ring[next_ring-1].col + 1; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } if (ring[next_ring-1].row) { // if we can go down RCell *bcell = lattice[ring[next_ring-1].row-1] + ring[next_ring-1].col; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } else { // we can't go down; need a new quadrant RCell *bcell = lattice[ring[next_ring-1].COLP]; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } break; } break; case R_RIGHT: switch (ring[next_ring-1].next_direction[ring[next_ring-1].next_direction_index]) { case R_DOWN: // two outside if (ring[next_ring-1].col) { // if we can go left RCell *bcell = lattice[ring[next_ring-1].row] + ring[next_ring-1].col - 1; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } else { // we can't go left; need a new quadrant RCell *bcell = lattice[0] + ring[next_ring-1].ROWM; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } if (ring[next_ring-1].row < NROWR-1) { // if we can go more up RCell *bcell = lattice[ring[next_ring-1].row + 1] + ring[next_ring-1].col; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } break; case R_LEFT: // DOWN inside, UP outside if (ring[next_ring-1].row) { // if we can go down RCell *bcell = lattice[ring[next_ring-1].row-1] + ring[next_ring-1].col; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } else { // we can't go down; need a new quadrant RCell *bcell = lattice[ring[next_ring-1].COLP]; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } if (ring[next_ring-1].row < NROWR-1) { // if we can go more up RCell *bcell = lattice[ring[next_ring-1].row + 1] + ring[next_ring-1].col; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } break; case R_UP: // two inside if (ring[next_ring-1].row) { // if we can go down RCell *bcell = lattice[ring[next_ring-1].row-1] + ring[next_ring-1].col; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } else { // we can't go down; need a new quadrant RCell *bcell = lattice[ring[next_ring-1].COLP]; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } if (ring[next_ring-1].col) { // if we can go left RCell *bcell = lattice[ring[next_ring-1].row] + ring[next_ring-1].col - 1; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } else { // we can't go left; need a new quadrant RCell *bcell = lattice[0] + ring[next_ring-1].ROWM; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } break; } break; case R_DOWN: switch (ring[next_ring-1].next_direction[ring[next_ring-1].next_direction_index]) { case R_LEFT: // two outside if (ring[next_ring-1].row < NROWR-1) { // if we can go more up RCell *bcell = lattice[ring[next_ring-1].row + 1] + ring[next_ring-1].col; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } if (ring[next_ring-1].col < NCOLR-1) { // if we can go more right RCell *bcell = lattice[ring[next_ring-1].row] + ring[next_ring-1].col + 1; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } break; case R_UP: // LEFT inside, RIGHT outside if (ring[next_ring-1].col) { // if we can go left RCell *bcell = lattice[ring[next_ring-1].row] + ring[next_ring-1].col - 1; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } else { // we can't go left; need a new quadrant RCell *bcell = lattice[0] + ring[next_ring-1].ROWM; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } if (ring[next_ring-1].col < NCOLR-1) { // if we can go more right RCell *bcell = lattice[ring[next_ring-1].row] + ring[next_ring-1].col + 1; if (!*bcell) { *bcell = char(R_OUTSIDE); ring[next_ring-1].border[bi++] = bcell; } } break; case R_RIGHT: // two inside if (ring[next_ring-1].col) { // if we can go left RCell *bcell = lattice[ring[next_ring-1].row] + ring[next_ring-1].col - 1; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } else { // we can't go left; need a new quadrant RCell *bcell = lattice[0] + ring[next_ring-1].ROWM; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } if (ring[next_ring-1].row < NROWR-1) { // if we can go more up RCell *bcell = lattice[ring[next_ring-1].row + 1] + ring[next_ring-1].col; if (!*bcell) { *bcell = char(R_INSIDE); ring[next_ring-1].border[bi++] = bcell; } } break; } break; } for (int i=bi; i<2; i++) ring[next_ring-1].border[i] = NULL; ring[next_ring] = {char(row),char(col),char(quadrant),char(prev_direction), {R_NONE,R_NONE,R_NONE},0,{NULL,NULL}}; // determine possible next cell directions int ndi = 0; // next direction index switch (ring[next_ring].prev_direction) { case R_LEFT: if (row<NROWR-1) ring[next_ring].next_direction[ndi++] = R_UP; if (col<NCOLR-1) ring[next_ring].next_direction[ndi++] = R_RIGHT; if (row || col > acol) ring[next_ring].next_direction[ndi++] = R_DOWN; break; case R_UP: if (col<NCOLR-1) ring[next_ring].next_direction[ndi++] = R_RIGHT; if (row || col > acol) ring[next_ring].next_direction[ndi++] = R_DOWN; if (col || row > LASTROW) ring[next_ring].next_direction[ndi++] = R_LEFT; break; case R_RIGHT: if (row || col > acol) ring[next_ring].next_direction[ndi++] = R_DOWN; if (col || row > LASTROW) ring[next_ring].next_direction[ndi++] = R_LEFT; if (row<NROWR-1) ring[next_ring].next_direction[ndi++] = R_UP; break; case R_DOWN: if (col || row > LASTROW) ring[next_ring].next_direction[ndi++] = R_LEFT; if (row<NROWR-1) ring[next_ring].next_direction[ndi++] = R_UP; if (col<NCOLR-1) ring[next_ring].next_direction[ndi++] = R_RIGHT; break; } for (int i=ndi; i<3; i++) ring[next_ring].next_direction[i] = R_NONE; lattice[ring[next_ring-1].row][ring[next_ring-1].col] = next_ring; next_ring++; return; // add another ring cell } // distance < NMAX - next_ring // we have too far to go; must try a different route while (next_ring && (++ring[next_ring-1].next_direction_index > 2 || R_NONE == ring[next_ring-1].next_direction[ring[next_ring-1].next_direction_index])) delete_ring(); return; } void RLattice::delete_ring() { if (!--next_ring) return; // we are done lattice[ring[next_ring].row][ring[next_ring].col] = R_EMPTY; for (int i=0; i<2; i++) { if (ring[next_ring-1].border[i]) *ring[next_ring-1].border[i] = R_EMPTY; else break; } ++ring[next_ring].next_direction_index; } int RLattice::ring_chirality() { // -1 if left, 0 if achiral, 1 if right if (R_RIGHT == ring[0].next_direction[ring[0].next_direction_index]) return 1; for (int i=1; i<next_ring/2; i++) { int low_turn=0, high_turn=0; switch (ring[i].prev_direction) { case R_LEFT: switch (ring[i].next_direction[ring[i].next_direction_index]) { case R_UP: low_turn = 1; break; case R_RIGHT: low_turn = 2; break; case R_DOWN: low_turn = 3; break; } break; case R_UP: switch (ring[i].next_direction[ring[i].next_direction_index]) { case R_RIGHT: low_turn = 1; break; case R_DOWN: low_turn = 2; break; case R_LEFT: low_turn = 3; break; } break; case R_RIGHT: switch (ring[i].next_direction[ring[i].next_direction_index]) { case R_DOWN: low_turn = 1; break; case R_LEFT: low_turn = 2; break; case R_UP: low_turn = 3; break; } break; case R_DOWN: switch (ring[i].next_direction[ring[i].next_direction_index]) { case R_LEFT: low_turn = 1; break; case R_UP: low_turn = 2; break; case R_RIGHT: low_turn = 3; break; } break; } int ringi = next_ring+2-i; switch (ring[next_ring+2-i].next_direction[ring[next_ring+2-i].next_direction_index]) { case R_LEFT: switch (ring[ringi].prev_direction) { case R_DOWN: high_turn = 1; break; case R_RIGHT: high_turn = 2; break; case R_UP: high_turn = 3; break; } break; case R_UP: switch (ring[ringi].prev_direction) { case R_LEFT: high_turn = 1; break; case R_DOWN: high_turn = 2; break; case R_RIGHT: high_turn = 3; break; } break; case R_RIGHT: switch (ring[ringi].prev_direction) { case R_UP: high_turn = 1; break; case R_LEFT: high_turn = 2; break; case R_DOWN: high_turn = 3; break; } break; case R_DOWN: switch (ring[ringi].prev_direction) { case R_RIGHT: high_turn = 1; break; case R_UP: high_turn = 2; break; case R_LEFT: high_turn = 3; break; } break; } if (low_turn > high_turn) return 1; if (high_turn > low_turn) return -1; } return 0; } void print_ring_count() { cout << "rings of {4,4} n-ominoes with fourfold rotational symmetry\n"; cout << "n chiral achiral\n"; for (int i=0; i<NMAX; i++) { if (ring_count[i][0]) { cout << 4*(i+1) << " " << ring_count[i][1] << " " << ring_count[i][0] << endl; } } clock_t elapsed = clock(); cout << (elapsed / (double)CLOCKS_PER_SEC) << " secs\n"; } void print_poly_count() { for (int i=0; i<NMAX-3; i++) { cout << 4*(i+4) << ": ["; Int total_chiral=0, total_achiral=0; for (int j=0; j<NMAX-3; j++) { total_achiral += poly_count[j][i][0]; total_chiral += poly_count[j][i][1]; } cout << total_achiral << "," << total_chiral << "]"; for (int j=0; j<NMAX-3; j++) { cout << " (" << 4*(j+4) << ")"; cout << "[" << poly_count[j][i][0] << "," << poly_count[j][i][1] << "]"; } cout << endl; } } void RLattice::process_ring(bool chiral) { //if (11!=next_ring) return; // DEBUG - only process rings of 36 ring_count[next_ring+1][chiral]++; Lattice *lattice = new Lattice(*this, chiral); lattice->add_ring_children(); if (lattice->any_child_in()) lattice->redel_in(); lattice->redel_out(); lattice->count_poly(); // how does one delete lattice? delete lattice; //print_ring(true); } void RLattice::print_ring(bool chiral) { if (chiral) cout << "C "; else cout << "A "; cout << "(0," << acol << ")"; for (int i=1; i<next_ring+2; i++) cout << ", (" << ring[i].row << "," << ring[i].col << ")"; cout << endl; } bool Lattice::is_ring_cell( int row, int col ) { #ifdef ERROR_CHECK if (col<0) { cout << "bad column\n"; exit(-12); } #endif unsigned int ring_index = lattice[row][col]; return ring_index>=FIRST_RING && ring_index<FIRST_RING+ring_cell_n; } void Lattice::add_ring_children() { // only children of ring cells for (int i=0; i<ring_cell_n; i++) { // for each ring cell // determine turn at this cell: 1=right, 2=straight, 3=left int turn = (4 + ring_cell[i].prev - ring_cell[i].next) % 4; switch (ring_cell[i].prev) { case UP: // previous ring cell cell above switch (turn) { case 1: // right; two inside add_child_in(ring_cell[i].row, ring_cell[i].col+1, i, ring_cell[i].quad, LEFT); if (ring_cell[i].row) add_child_in(ring_cell[i].row-1, ring_cell[i].col, i, ring_cell[i].quad, UP); else add_child_in(ring_cell[i].COLP, 0, i, ring_cell[i].quad-1, LEFT); break; case 2: // straight; one inside, one outside add_child_in(ring_cell[i].row, ring_cell[i].col+1, i, ring_cell[i].quad, LEFT); if (ring_cell[i].col) add_child_out(ring_cell[i].row, ring_cell[i].col-1); else add_child_out(0, ring_cell[i].ROWM); break; case 3: // left; two outside if (ring_cell[i].row) add_child_out(ring_cell[i].row-1, ring_cell[i].col); else add_child_out(ring_cell[i].COLP, 0); if (ring_cell[i].col) add_child_out(ring_cell[i].row, ring_cell[i].col-1); else add_child_out(0, ring_cell[i].ROWM); break; default: break; } break; case RIGHT: // previous ring cell cell right switch (turn) { case 1: // right; two inside if (ring_cell[i].row) add_child_in(ring_cell[i].row-1, ring_cell[i].col, i, ring_cell[i].quad, UP); else add_child_in(ring_cell[i].COLP, 0, i, ring_cell[i].quad-1, LEFT); if (ring_cell[i].col) add_child_in(ring_cell[i].row, ring_cell[i].col-1, i, ring_cell[i].quad, RIGHT); else add_child_in(0, ring_cell[i].ROWM, i, ring_cell[i].quad+1, DOWN); break; case 2: // straight; one inside, one outside if (ring_cell[i].row) add_child_in(ring_cell[i].row-1, ring_cell[i].col, i, ring_cell[i].quad, UP); else add_child_in(ring_cell[i].COLP, 0, i, ring_cell[i].quad-1, LEFT); add_child_out(ring_cell[i].row+1, ring_cell[i].col); break; case 3: // left; two outside if (ring_cell[i].col) add_child_out(ring_cell[i].row, ring_cell[i].col-1); else add_child_out(0,ring_cell[i].ROWM); add_child_out(ring_cell[i].row+1, ring_cell[i].col); break; default: break; } break; case DOWN: // previous ring cell cell below switch (turn) { case 1: // right; two inside if (ring_cell[i].col) add_child_in(ring_cell[i].row, ring_cell[i].col-1, i, ring_cell[i].quad, RIGHT); else add_child_in(0, ring_cell[i].ROWM, i, ring_cell[i].quad+1, DOWN); add_child_in(ring_cell[i].row+1, ring_cell[i].col, i, ring_cell[i].quad, DOWN); break; case 2: // straight; one inside, one outside if (ring_cell[i].col) add_child_in(ring_cell[i].row, ring_cell[i].col-1, i, ring_cell[i].quad, RIGHT); else add_child_in(0, ring_cell[i].ROWM, i, ring_cell[i].quad+1, DOWN); add_child_out(ring_cell[i].row, ring_cell[i].col+1); break; case 3: // left; two outside add_child_out(ring_cell[i].row+1, ring_cell[i].col); add_child_out(ring_cell[i].row, ring_cell[i].col+1); break; default: break; } break; case LEFT: // previous ring cell cell left switch (turn) { case 1: // right; two inside add_child_in(ring_cell[i].row, ring_cell[i].col+1, i, ring_cell[i].quad, LEFT); add_child_in(ring_cell[i].row+1, ring_cell[i].col, i, ring_cell[i].quad, DOWN); break; case 2: // straight; one inside, one outside add_child_in(ring_cell[i].row+1, ring_cell[i].col, i, ring_cell[i].quad, DOWN); if (ring_cell[i].row) add_child_out(ring_cell[i].row-1, ring_cell[i].col); else add_child_out(ring_cell[i].COLP, 0); break; case 3: // left; two outside if (ring_cell[i].row) add_child_out(ring_cell[i].row-1, ring_cell[i].col); else add_child_out(ring_cell[i].COLP, 0); add_child_out(ring_cell[i].row, ring_cell[i].col+1); break; default: break; } break; default: exit (-3); break; } } } void Lattice::add_child_in( // child must be adjacent to a ring cell RowCol row, RowCol col, unsigned char ring_index, // index of ring cell signed char quad, // quadrant of ring cell unsigned char dir // direction of ring cell ) { if (lattice[row][col]) return; // if already encountered if ((UP!=dir && is_ring_cell(row+1,col)) || (RIGHT!=dir && is_ring_cell(row,col+1)) || (DOWN!=dir && ((row && is_ring_cell(row-1,col)) || (!row && is_ring_cell(COLP,0)))) || (LEFT!=dir && ((col && is_ring_cell(row,col-1)) || (!col && row && is_ring_cell(0,ROWM)))) ) lattice[row][col] = FORBIDDEN; // adjacent to two ring cells else { // we can add a new child cell child_in[child_in_n] = {row, col, char(ring_index - quad * ring_cell_n), char(ring_index - quad * ring_cell_n), dir, 0}; lattice[row][col] = FIRST_RING + ring_cell_n + child_in_n++; } } void Lattice::add_child_out( RowCol row, RowCol col ) { if (lattice[row][col]) return; // if already encountered child_out[child_out_n++] = {row, col}; lattice[row][col] = OUTSIDE; } void Lattice::redel_in() { // requires child_in_count > 0 for (add_parent_in(); ; add_parent_in()) { // also count polyomino if (limit_reached_in()) delete_parent_in(); for (++next_child_in; children_done_in(); next_child_in++) { if (parents_done_in()) return; delete_parent_in(); } } } void Lattice::redel_out() { // requires child_in_count > 0 for (add_parent_out(); ; add_parent_out()) { // also count polyomino if (limit_reached_out()) delete_parent_out(); for (++next_child_out; children_done_out(); next_child_out++) { if (parents_done_out()) return; delete_parent_out(); } } } void Lattice::add_parent_in() { // we either add a new parent based on the current next_child_in along with // its children in any adjacent empty squares or we return. If we add the // parent, we increase next_parent_in and we zero the parent_successor // fields for parent_predecessor, if any; these need not be adjacent cells, but // they must be connected to an adjacent cell. If parent added, count polyomino. parent_in[next_parent_in] = {(unsigned char)next_child_in, (unsigned char)child_in_n, child_in[next_child_in].low_ring, child_in[next_child_in].high_ring}; // temporary (assume zeros at end!) int row = child_in[next_child_in].row; // coordinates of new parent cell int col = child_in[next_child_in].col; // check for conflict in ring attachments int cell_num = lattice[row+1][col]; // cell above if (bad_connection(cell_num, 0)) return; cell_num = lattice[row][col+1]; // cell at right if (bad_connection(cell_num, 0)) return; int quad_adjust; // expect new cell to have this added to ring contact if (row) { cell_num = lattice[row-1][col]; // cell below quad_adjust = 0; } else { cell_num = lattice[COLP][0]; quad_adjust = ring_cell_n; } if (bad_connection(cell_num, quad_adjust)) return; if (row || col) { // unused center cell left of lattice[0][0] for even rings if (col) { cell_num = lattice[row][col-1]; // cell at left quad_adjust = 0; } else { cell_num = lattice[0][ROWM]; quad_adjust = -ring_cell_n; } if (bad_connection(cell_num, quad_adjust)) return; } // we have a new parent, as we did not return because of a conflict for (int i=0; parent_in[next_parent_in].parent_predecessor[i]; i++) { // for each adjacent parent cell parent_in[parent_in[next_parent_in].parent_predecessor[i]-1].parent_successor = next_parent_in; // link } child_in[parent_in[next_parent_in].child_index].parent_index = next_parent_in+1; // link from child to parent // add neighbors as children if empty if (EMPTY == lattice[row+1][col]) { lattice[row+1][col] = child_in_n + ring_cell_n + FIRST_RING; child_in[child_in_n++] = {(RowCol)(row+1), (RowCol)col, parent_in[next_parent_in].low_ring, parent_in[next_parent_in].high_ring, DOWN}; } if (EMPTY == lattice[row][col+1]) { lattice[row][col+1] = child_in_n + ring_cell_n + FIRST_RING; child_in[child_in_n++] = {(RowCol)row, (RowCol)(col+1), parent_in[next_parent_in].low_ring, parent_in[next_parent_in].high_ring, LEFT}; } if (row) { if (EMPTY == lattice[row-1][col]) { lattice[row-1][col] = child_in_n + ring_cell_n + FIRST_RING; child_in[child_in_n++] = {(RowCol)(row-1), (RowCol)col, parent_in[next_parent_in].low_ring, parent_in[next_parent_in].high_ring, UP}; } } else { if (EMPTY == lattice[COLP][0]) { lattice[COLP][0] = child_in_n + ring_cell_n + FIRST_RING; child_in[child_in_n++] = {RowCol(COLP), 0, char(parent_in[next_parent_in].low_ring + ring_cell_n), char(parent_in[next_parent_in].high_ring + ring_cell_n), LEFT}; } } if (col) { if (EMPTY == lattice[row][col-1]) { lattice[row][col-1] = child_in_n + ring_cell_n + FIRST_RING; child_in[child_in_n++] = {(RowCol)row, (RowCol)(col-1), parent_in[next_parent_in].low_ring, parent_in[next_parent_in].high_ring, RIGHT}; } } else if (row) { // unused center cell left of lattice[0][0] for even rings if (EMPTY == lattice[0][ROWM]) { lattice[0][ROWM] = child_in_n + ring_cell_n + FIRST_RING; child_in[child_in_n++] = {0, RowCol(ROWM), char(parent_in[next_parent_in].low_ring - ring_cell_n), char(parent_in[next_parent_in].high_ring - ring_cell_n), DOWN}; } } child_in[next_child_in].parent_index = ++next_parent_in; // actual+1 pcount[0][next_parent_in]++; } void Lattice::add_parent_out() { parent_out[next_parent_out] = {(char)next_child_out, (char)child_out_n}; int row = child_out[next_child_out].row; // coordinates of new parent cell int col = child_out[next_child_out].col; //child_out[next_child_out].parent_index = next_parent_out; // link from child to parent // add neighbors as children if empty if (EMPTY == lattice[row+1][col]) { // ABOVE lattice[row+1][col] = OUTSIDE; child_out[child_out_n++] = {(RowCol)(row+1), (RowCol)col}; } if (EMPTY == lattice[row][col+1]) { // RIGHT lattice[row][col+1] = OUTSIDE; child_out[child_out_n++] = {(RowCol)row, (RowCol)(col+1)}; } if (row) { if (EMPTY == lattice[row-1][col]) { // BELOW lattice[row-1][col] = OUTSIDE; child_out[child_out_n++] = {(RowCol)(row-1), (RowCol)col}; } } else { if (EMPTY == lattice[COLP][0]) { // BELOW lattice[COLP][0] = OUTSIDE; child_out[child_out_n++] = {RowCol(COLP), 0}; } } if (col) { if (EMPTY == lattice[row][col-1]) { // LEFT lattice[row][col-1] = OUTSIDE; child_out[child_out_n++] = {(RowCol)row, (RowCol)(col-1)}; } } else { if (EMPTY == lattice[0][ROWM]) { // LEFT lattice[0][ROWM] = OUTSIDE; child_out[child_out_n++] = {0, RowCol(ROWM)}; } } next_parent_out++; pcount[1][next_parent_out]++; } void Lattice::delete_parent_in() { next_child_in = parent_in[--next_parent_in].child_index; while (child_in_n != parent_in[next_parent_in].child_begin) { // eliminate neighbors child_in_n--; lattice[child_in[child_in_n].row][child_in[child_in_n].col] = EMPTY; } for (int i=0; parent_in[next_parent_in].parent_predecessor[i]; i++) { // for each adjacent parent cell parent_in[parent_in[next_parent_in].parent_predecessor[i]-1].parent_successor = 0; // delete link } child_in[parent_in[next_parent_in].child_index].parent_index = 0; // eliminate child link } void Lattice::delete_parent_out() { next_child_out = parent_out[--next_parent_out].child_index; while (child_out_n != parent_out[next_parent_out].child_begin) { // eliminate neighbors child_out_n--; lattice[child_out[child_out_n].row][child_out[child_out_n].col] = EMPTY; } } bool Lattice::bad_connection( // return true if this is a bad connection int cell_num, // content of adjacent lattice cell int quad_adjust // expect adjacent cell to have this added to ring contact // generally add quad_adjust to parent_in[next_parent_in].---ring ) { if (cell_num < ring_cell_n+FIRST_RING) return false; // neighbor is not inside child if (!child_in[cell_num-ring_cell_n-FIRST_RING].parent_index) return false; // neighbor not a parent cell if (parent_in[next_parent_in].low_ring != parent_in[next_parent_in].high_ring) { // if two ring connections for new parent cell if (child_in[cell_num-ring_cell_n-FIRST_RING].low_ring < parent_in[next_parent_in].low_ring + quad_adjust) return true; if (child_in[cell_num-ring_cell_n-FIRST_RING].high_ring > parent_in[next_parent_in].high_ring + quad_adjust) return true; // determine parent successor int successor = child_in[cell_num-ring_cell_n-FIRST_RING].parent_index-1; while (parent_in[successor].parent_successor) successor = parent_in[successor].parent_successor; if (parent_in[successor].low_ring == parent_in[successor].high_ring) { for (int i=0; i<4; i++) if (!parent_in[next_parent_in].parent_predecessor[i]) { parent_in[next_parent_in].parent_predecessor[i] = successor+1; return false; } } else { // successor has two ring connections // determine quadrant adjustment for successor if (parent_in[successor].low_ring < parent_in[next_parent_in].low_ring) { int successor_adjust = ring_cell_n; while (parent_in[successor].low_ring + successor_adjust < parent_in[next_parent_in].low_ring) successor_adjust += ring_cell_n; if (parent_in[successor].low_ring + successor_adjust != parent_in[next_parent_in].low_ring) return true; if (parent_in[successor].high_ring + successor_adjust != parent_in[next_parent_in].high_ring) return true; } else if (parent_in[successor].low_ring > parent_in[next_parent_in].low_ring) { int successor_adjust = ring_cell_n; while (parent_in[successor].low_ring - successor_adjust > parent_in[next_parent_in].low_ring) successor_adjust += ring_cell_n; if (parent_in[successor].low_ring - successor_adjust != parent_in[next_parent_in].low_ring) return true; if (parent_in[successor].high_ring - successor_adjust != parent_in[next_parent_in].high_ring) return true; } else { // no adjustment required if (parent_in[successor].high_ring != parent_in[next_parent_in].high_ring) return true; } } } else { // only one ring connection for trial parent // first check if adjacent cell has one or two attachments int successor = child_in[cell_num-ring_cell_n-FIRST_RING].parent_index-1; int adj_parent = successor; // index of adjacent parent, which may have successors while (parent_in[successor].parent_successor) successor = parent_in[successor].parent_successor; int succ_quad_adjust; // adjustment for change in quad from adj_parent to successor if (adj_parent == successor) succ_quad_adjust = 0; else { // ***** change on 5/22 ***** succ_quad_adjust = ring_cell_n * ((2+abs(parent_in[successor].low_ring - parent_in[adj_parent].low_ring))/ring_cell_n); // could be zero if (parent_in[successor].high_ring < parent_in[adj_parent].low_ring) succ_quad_adjust = -succ_quad_adjust; } // return true if proposed parent would add new connection if (parent_in[successor].low_ring != parent_in[successor].high_ring) { if (parent_in[successor].low_ring - quad_adjust - succ_quad_adjust > parent_in[next_parent_in].low_ring) return true; if (parent_in[successor].high_ring - quad_adjust - succ_quad_adjust < parent_in[next_parent_in].high_ring) return true; // expand connections of trial parent if (parent_in[successor].low_ring - quad_adjust - succ_quad_adjust == parent_in[next_parent_in].low_ring) { parent_in[next_parent_in].high_ring = parent_in[next_parent_in].low_ring + 1; } else parent_in[next_parent_in].low_ring = parent_in[next_parent_in].high_ring - 1; } else { // check if possible connection where adjacent has one attachment if (abs(parent_in[successor].low_ring - quad_adjust - succ_quad_adjust - parent_in[next_parent_in].low_ring) > 1) return true; // find double connection if any //int adjacent_parent = successor; //while (parent_in[successor].parent_successor) //successor = parent_in[successor].parent_successor; if (parent_in[successor].low_ring != parent_in[successor].high_ring) { if (!((parent_in[successor].low_ring-parent_in[next_parent_in].low_ring) % ring_cell_n)) parent_in[next_parent_in].high_ring++; else if (!((parent_in[successor].high_ring-parent_in[next_parent_in].high_ring) % ring_cell_n)) parent_in[next_parent_in].low_ring--; else return true; // adjacent parent would extend to three } else { // only one connection for adjacent cell if (parent_in[successor].low_ring - quad_adjust - succ_quad_adjust > parent_in[next_parent_in].low_ring) { parent_in[next_parent_in].high_ring = parent_in[successor].low_ring - quad_adjust - succ_quad_adjust; } else if (parent_in[successor].low_ring - quad_adjust - succ_quad_adjust < parent_in[next_parent_in].low_ring) { parent_in[next_parent_in].low_ring = parent_in[successor].low_ring - quad_adjust - succ_quad_adjust; } for (int i=0; i<4; i++) { // trial parent is potential successor if (!parent_in[next_parent_in].parent_predecessor[i]) { parent_in[next_parent_in].parent_predecessor[i] = successor + 1; break; } } } } } return false; } void Lattice::count_poly() { Int total[NMAX] = {0}; for (int i=0; i<=NMAX-ring_cell_n; i++) { for (int j=0; j<=NMAX-ring_cell_n-i; j++) { total[ring_cell_n+i+j-4] += pcount[0][i] * pcount[1][j]; } } for (int i=0; i<NMAX; i++) { poly_count[ring_cell_n - 4][i][ring_is_chiral] += total[i]; } } const void Lattice::dump_ring() { for (int i=0; i<next_parent_out; i++) { lattice[child_out[parent_out[i].child_index].row][child_out[parent_out[i].child_index].col] = PARENT; } for (int ri=NROW-1; ri>=0; ri-=1) { // for each row for (int ci=0; ci<NCOL; ci++) { // for each column int index = lattice[ri][ci]; if (index>=FIRST_RING+ring_cell_n) { int successor = child_in[index-FIRST_RING-ring_cell_n].parent_index; if (successor--) { while (parent_in[successor].parent_successor) successor = parent_in[successor].parent_successor; if (parent_in[successor].low_ring == parent_in[successor].high_ring) cout << 'X'; else cout << 'Z'; } else cout << 'i'; // child (i) } else if (index>=FIRST_RING) cout << char('A'-FIRST_RING+index); else switch (index) { case EMPTY: cout << ' '; break; case FORBIDDEN: cout << '-'; break; case OUTSIDE: // outside child cout << 'o'; break; case PARENT: // outside child cout << 'Y'; break; default: cout << "error in case\n"; exit (-2); // error } } cout << endl; } cout << "in=" << child_in_n << " out=" << child_out_n << endl; for (int i=0; i<next_parent_out; i++) { lattice[child_out[parent_out[i].child_index].row][child_out[parent_out[i].child_index].col] = OUTSIDE; } } /****************************************************************************************/ // // Lattice.hpp // ring_4c2_16p // // Created by Robert A Russell on 10/16/21. // Copyright © 2021 Robert A Russell. All rights reserved. // #ifndef Lattice_hpp #define Lattice_hpp #include <iostream> using std::cout; using std::endl; #include <set> using std::set; using std::pair; #define NMAX 18 // maximum number of cells in quarter of polyomino; must be even // 18 takes 33.1 secs; 20 takes 467.4 secs; 22 takes 6815.8 secs; 24 takes 29 hrs. #define NROWR NMAX/2 + 2 #define NCOLR NMAX/2 + 1 #define MINCOL 1 #define LASTROW acol+1 #define ROWM row-1 #define COLP col+1 #define NROW NMAX #define NCOL NMAX-1 typedef unsigned long long int Int; typedef short LongChar; // used to make chars numeric typedef unsigned short UnLongChar; // used to make chars numeric enum {R_EMPTY=0, R_INSIDE=-1, R_OUTSIDE=-2, R_FORBIDDEN=-3}; // values for RCell typedef char RCell; // nonzero if in use; ring cell is positive integer enum {R_NONE, R_LEFT, R_UP, R_RIGHT, R_DOWN}; // directions typedef struct { LongChar row; LongChar col; LongChar quadrant; // 0 for first, 1 for second, -1 for fourth LongChar prev_direction; // see directions above LongChar next_direction[3]; // possible directions of next ring cell LongChar next_direction_index; // index to actual direction above RCell *border[2]; // border cells of this ring cell, possibly null } RingCellR; class RLattice { // used to construct all of the possible rings, >=4 and <= NMAX RCell lattice[NROWR][NCOLR]; // {4,4} Int count[2]; // first is achiral, second chiral RingCellR ring[NMAX]; int acol; // lowest column for first cell of ring int next_ring; // ring[next_ring] is next ring cell to be added void add_ring(); void delete_ring(); int ring_chirality(); void process_ring(bool chiral); void print_ring(bool chiral); friend class Lattice; public: RLattice(int acol_in); void get_rings() { while (next_ring) add_ring(); }; // count rings }; // typedef unsigned char Cell; // values below typedef unsigned short Cell; // values below enum {EMPTY, FORBIDDEN, OUTSIDE, PARENT, FIRST_RING}; // FIRST_RING..FIRST_RING+ring_cell_n-1 are ring cells, higher numbers are inside children typedef UnLongChar RowCol; // change back to char later typedef pair<RowCol,RowCol> CPair; typedef set<CPair> CPairSet; typedef set<CPairSet> CPairSet2; enum {NONE, UP, RIGHT, DOWN, LEFT}; // clockwise typedef struct { RowCol row; RowCol col; unsigned char prev:4; // direction of previous cell unsigned char next:4; // direction of next cell LongChar quad; // quadrant of rotation (0 for quadrant shown) } RingCell; // used in list of ring cells typedef struct { RowCol row; RowCol col; LongChar low_ring; // index of associated ring cell, adjusted for rotation LongChar high_ring; // index of associated ring cell, adjusted for rotation UnLongChar dir; // direction of cell for which this is a child UnLongChar parent_index; // 1 + index of parent this child becomes, else zero } ChildIn; typedef struct { UnLongChar child_index; // index of child_in[] UnLongChar child_begin; // where new children of this parent begin in child_in LongChar low_ring; // index of associated ring cell, adjusted for rotation LongChar high_ring; // index of associated ring cell (could be zero!) UnLongChar parent_predecessor[4]; // 1+index of predecessor in parent_in[] UnLongChar parent_successor; // index origin 0 (parent_in[0] cannot be successor) } ParentIn; typedef struct { RowCol row; RowCol col; } ChildOut; typedef struct { char child_index; // offset to child that has become this parent char child_begin; // offset of first child of this parent } ParentOut; class Lattice { // used to enumerate inside and outside ring Cell lattice[NROW][NCOL]; // {4,4} RingCell ring_cell[NMAX]; // only fourth of ring here bool ring_is_chiral; // true if ring is chiral, false if achiral int ring_cell_n; // number of ring cells in ring_cell[] ChildIn child_in[3*NMAX]; int child_in_n; // number of cells in child_in ParentIn parent_in[NMAX]; ParentOut parent_out[NMAX]; ChildOut child_out[3*NMAX]; int child_out_n; // number of cells in child_out int next_child_in; int next_child_out; int next_parent_in; int next_parent_out; Int pcount[2][NMAX]; // child_in, child_out void add_child_in(RowCol, RowCol, unsigned char, signed char, unsigned char); void add_child_out(RowCol, RowCol); bool is_ring_cell(int row, int col); void add_parent_in(); void add_parent_out(); void delete_parent_in(); void delete_parent_out(); bool children_done_in() { return next_child_in == child_in_n; } bool children_done_out() { return next_child_out == child_out_n; } bool parents_done_in() { return next_parent_in == 0; } bool parents_done_out() { return next_parent_out == 0; } bool limit_reached_in() { return ring_cell_n + next_parent_in >= NMAX; } bool limit_reached_out() { return ring_cell_n + next_parent_out >= NMAX; } bool bad_connection(int cell_num, int quad); public: Lattice(class RLattice &rlat, bool chiral) : child_in_n(0), child_out_n(0), next_child_in(0), next_child_out(0), next_parent_in(0), next_parent_out(0) { memset(lattice, 0, sizeof lattice); ring_is_chiral = chiral; memset(pcount, 0, sizeof pcount); pcount[0][0] = pcount[1][0] = 1; // no child_in, no child_out ring_cell_n = rlat.next_ring+2; for (int i=0; i<ring_cell_n; i++) { // fill in ring_cell[] unsigned char prev_dir=LEFT, next_dir=LEFT; switch (rlat.ring[i].prev_direction) { case R_UP: prev_dir = UP; break; case R_RIGHT: prev_dir = RIGHT; break; case R_DOWN: prev_dir = DOWN; break; default: break; // must be R_LEFT } switch (rlat.ring[i].next_direction[rlat.ring[i].next_direction_index]) { case R_UP: next_dir = UP; break; case R_RIGHT: next_dir = RIGHT; break; case R_DOWN: next_dir = DOWN; break; default: break; // must be R_LEFT } ring_cell[i] = {(RowCol)rlat.ring[i].row, (RowCol)rlat.ring[i].col, prev_dir, next_dir, (char)rlat.ring[i].quadrant}; lattice[ring_cell[i].row][ring_cell[i].col] = FIRST_RING + i; } // check ring is okay?? } void add_ring_children(); // create inside and outside children void redel_in(); void redel_out(); void count_poly(); const bool any_child_in() {return child_in_n>0;} const void dump_ring(); }; void print_ring_count(); void print_poly_count(); #endif /* Lattice_hpp */ /****************************************************************************************/