Realizing still life constraints as a planar tiling

For general discussion about Conway's Game of Life.
User avatar
pcallahan
Posts: 845
Joined: April 26th, 2013, 1:04 pm

Re: Realizing still life constraints as a planar tiling

Post by pcallahan » May 19th, 2016, 9:39 pm

That's really cool. Pictures like that at thingiverse might increase the probably of someone trying it out. (As well as removal of the old pictures from previous attempts at the tiles, which will just confuse people.) Can OpenJSCAD confirm that the pieces fit together as placed? (No intersections at least; we can verify visually that space is filled.)

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Realizing still life constraints as a planar tiling

Post by simsim314 » May 19th, 2016, 10:04 pm

pcallahan wrote:Can OpenJSCAD confirm that the pieces fit together as placed?
I highly confident they fit, due to two reasons:

1. I used boolean operations to generate them in the first place. I didn't design the pieces, they came out as a result of negative operation. Everything is defined by basic pieces (the slice, and slice with tooth).

2. I was playing a lot with those pieces, tweaking a bit left and right, found few minor bugs related to some minor details.

So all in all this is working. The only thing missing, is how to scale the pieces a bit to physically fit well together (but for this I will need a 3d printer).

It was also hard task to tweak a bit the pieces so the border of the connections would be visible. It's not working too well yet, but good enough to convey the main idea, and to make sure everything is working well.

EDIT Regarding your question OpenJScad indeed can confirm but it's not that trivial. We can't just unite all intersection pairs or something. I was playing and exploring visually this set for a while already.

EDIT2 I've improved the TileGenerator.jscad to show much better the tiling solution (you can download it from Thingverse)

Here is an example of how the tiling were solved for pretty complex case:
Sample2.png
Sample2.png (151.09 KiB) Viewed 17657 times
Last edited by simsim314 on May 20th, 2016, 4:40 am, edited 1 time in total.

User avatar
calcyman
Moderator
Posts: 2932
Joined: June 1st, 2009, 4:32 pm

Re: Realizing still life constraints as a planar tiling

Post by calcyman » May 20th, 2016, 4:34 am

Just out of interest, is there any reason for switching from 16-gons (truncated octagons) to octagons for the blue tiles?

The 16-gon versions seem less fragile and (paradoxically) result in tiles with fewer edges.
What do you do with ill crystallographers? Take them to the mono-clinic!

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Realizing still life constraints as a planar tiling

Post by simsim314 » May 20th, 2016, 4:47 am

calcyman wrote:Just out of interest, is there any reason for switching from 16-gons (truncated octagons) to octagons for the blue tiles?
It was definitely unfortunate. The reason was that I wanted better interlocking for the empty with >= 4 neighbors case. If you'll look at your tiles, the only thing that holds them are the teeth, the're not interlocking at all. This case also unfortunately needs 8 folded symmetry, and the only existing piece that can provide this symmetry is the piece that you used for the "live" internal connector. But for the live cell case we only need 4 symmetries not 8.

We could use 3d tricks to attach the >=4 empty case, but I'm trying to avoid using this trick as much as possible. The reason for this is that it could not work so well, so I use it only if there is no other choice like in case of square attachments.

Edit Woops just realized that we can use the same 8 folded symmetrical unit in both cases! We just need to use 45 degree rotation like calcyman together with my 0 degrees. Is that what calcyman meant? Anyway will fix this soon.
Last edited by simsim314 on May 20th, 2016, 7:12 am, edited 1 time in total.

mniemiec
Posts: 1590
Joined: June 1st, 2013, 12:00 am

Re: Realizing still life constraints as a planar tiling

Post by mniemiec » May 20th, 2016, 7:04 am

NotLiving wrote:One obvious issue is that your "no-neighbors" corner piece (the diamond) tiles the plane on its own - but that's simple to fix.
pcallahan wrote:Yeah, I overlooked the fact that the square tiles would tile the plane on their own.
pcallahan wrote:calcyman: there is one problem I see with the axis-parallel splits you used. You can get infinite linear boundaries like this and slide entire sections of the tiling.
These are not problems if one considers only the states of the cells, and not the precise boundaries between cells of the same state. Tile boundaries already do not correspond to cell boundaries, and tilings corresponding to specific cell arrangements are already non-unique. If one treats the grey tiles and white tiles as being the same color, the second problem becomes moot, as empty space is still empty space, regardless of whether the tile divisions occur on cell boundaries or not.

The first problem also becomes moot, as an empty field remains unchanged when rotated 45 degrees (and is the only pattern that does so). It's also necessary to treat the empty field as a still life in the limiting case; I suspect that creating a tile set that includes all still-lifes but explicitly things that aren't technically still-lifes (like the empty field, pseudo-still-lifes, and still constellations) would be much more complex, and I strongly suspect that it would not be possible at all.

User avatar
pcallahan
Posts: 845
Joined: April 26th, 2013, 1:04 pm

Re: Realizing still life constraints as a planar tiling

Post by pcallahan » May 20th, 2016, 10:16 am

mniemiec wrote:If one treats the grey tiles and white tiles as being the same color, the second problem becomes moot, as empty space is still empty space, regardless of whether the tile divisions occur on cell boundaries or not.
I never thought the extra tilings were serious problems, but I like this explanation of why they're not.

There are two questions here with different answers. One is how to construct the most appealing set of manipulative pieces, which simsim314 has been working on. The other is to simplify the tile set as much as possible (minimal number of pieces, minimal shape complexity, only 2D constraints). I think there is room for progress on the latter, though I don't really see how to reduce the number below 16. I also really don't like reusing corner tiles to fit together neighborhoods, even if I suggested it. Any other ideas?

EDIT: One minor, minor quibble about simsim314's first tiling (the larger still life). You have the diagonal piece blue inside the 2x2 blocks, but it is yellow inside empty cells. I think keeping it yellow is perfectly fine, though it makes the blocks a little less blocky. They are still connected patterns.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Realizing still life constraints as a planar tiling

Post by simsim314 » May 20th, 2016, 2:29 pm

I've updated the Thingverse with everything new (the tiles and the script and the image captures). We now have calcyman original tiling (pheew it's a relief), together with my grooving on the empty case.

Now the tiles look like this:
tiles.png
tiles.png (127.19 KiB) Viewed 17611 times
@pcalahan Officially speaking the overloaded connecting piece is grey. But It doesn't looks good at all with grey (nor yellow) although it does look valid but ugly.

I was thinking about this a lot. There are three reasons why I don't mind to have one tile with two colors:

1. For the production line the color doesn't matter, because it's just a switch of filament which anyway should be done (unlike for example extra tile, which requires extra preparation, stl file, bom statistics etc.)

2. For the end user the correct color of the tiling is only helping, unlike complexity added by entirely new tile.

3. There is also no theoretical necessity to have a tile with the same color. Theoretically speaking we can have them all grey, and the tiling will still correspond to SLs. The coloring scheme is just aesthetic feature.

It looks like superstition that each tile must have single color. If I'm thinking of it as a puzzle game, the user cares only about the number of pieces, color only helps him.

User avatar
pcallahan
Posts: 845
Joined: April 26th, 2013, 1:04 pm

Re: Realizing still life constraints as a planar tiling

Post by pcallahan » May 21st, 2016, 1:40 pm

Open question: how many new tiles (colored appropriately) would we need to add to represent the non-stable neighborhoods. These would include the dead cells with three live neighbors (birth) and live cells with 0, 1, 4, 5, 6, 7, 8 neighbors. By making the top surfaces interlocking (nub->nub birth, dent-dent death, nub-dent stable dead, dent-nub stable live) you would have a set that could be stacked into changing life patterns (oh darn, but you can't use flip symmetry. need to rethink...)

Maybe that would be of more interest to the maker community since it is the whole CA and not just a subproblem.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Realizing still life constraints as a planar tiling

Post by simsim314 » May 21st, 2016, 3:25 pm

pcallahan wrote:Maybe that would be of more interest to the maker community since it is the whole CA and not just a subproblem.
I think that SLs are also interesting, but we need to show some printed parts and explain how this puzzle is working. I don't think anyone in the makers community understands what those tiles are about (not everyone understood it in the CGOL community).

Some video with this puzzle printed, assembled and explained could promote the topic a lot. 3d printing, game of life and puzzle games have pretty wide audience, you just need to feed with spoon, and maybe make some promotion (post on relevant sites etc.), for now we didn't 3d printed them yet - this will take some time I guess.

BTW I think that dynamic CGOL mechanical computer is more interesting than tiling puzzle, but this will probably be more complex, and can't be branded as game for kids. I'm not sure how much GOL tiling will suit kids, on the other hand it's not much more complex than lego or usual puzzles, and it's not trivial - so I think it can catch.

EDIT I've added many tags, and "re-branded" into category Toys&Games puzzle.

User avatar
pcallahan
Posts: 845
Joined: April 26th, 2013, 1:04 pm

Re: Realizing still life constraints as a planar tiling

Post by pcallahan » May 25th, 2016, 2:45 pm

Here's another way to split up the 2-3 live neighborhoods into 4 tiles, but it does not use an interior tile. (Pardon the freehand drawings; no time to code it up.)
Screen Shot 2016-05-25 at 11.34.02 AM.png
Screen Shot 2016-05-25 at 11.34.02 AM.png (60.75 KiB) Viewed 17543 times
This doesn't change much mathematically. What I think is potentially interesting from a "games and puzzles" perspective is that you could make these into snap-together parts, one for 2-neighborhoods and one for 3-neighborhoods that would not need to be disassembled provided you could flip the tiles around the axis where they are connected. I have no idea how to do this with a 3D printer (or anything else; I'm not a mechanical engineer). If the tiles are thick I do know you need round contours to allow the interior one-tooth segments to rotate freely.

So GOL aside, you would have these little devices for constructing all possible 2-tooth and 3-tooth octagons up to symmetry. (I have been trying to picture how this could work for about a week and it suddenly fit together).

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Realizing still life constraints as a planar tiling

Post by simsim314 » May 25th, 2016, 3:41 pm

This is very nice! This pieces do give additional degree of freedom, and make the parts less breakable.

As for the "rotation" option, I see why it's cool that this option is available, but for more practical and user experience perspective, I think I would stick to puzzling, just add a jigsaw for the internal connection.

The main reason I think rotational axis is not desirable from use experience perspective, is because it makes the puzzle more susceptive to breaking. Adding mechanical parts will give two options:

- or lack of good interlocking. Those pieces will hang in the air all the time, and will be unstable.
- or if interlocking will still be in place, the internal rotational axes will break much more easily, when disassembling.

I also don't like the hanging shape of this "quasi" rotating tiles. But I see why it's kinda cool that this is a valid option.

This do allows to avoid using square as internal connector though, so if the square will be problematic (say the 3d shape will not hold so well, or tend to break), we can still get direct surrounding of the SL with good interlocking.

----

Unrelated - I've edited the tags on the Thingverse for the tiles, and now I get a constant flux of 20-25 views/day.

User avatar
pcallahan
Posts: 845
Joined: April 26th, 2013, 1:04 pm

Re: Realizing still life constraints as a planar tiling

Post by pcallahan » May 25th, 2016, 4:37 pm

simsim314 wrote:This do allows to avoid using square as internal connector though, so if the square will be problematic (say the 3d shape will not hold so well, or tend to break)
I didn't try to work out the details, but if the interior pieces no longer need to fit into live cells, they can be made a little bigger, which should add more flexibility to the tooth sizes.

User avatar
pcallahan
Posts: 845
Joined: April 26th, 2013, 1:04 pm

Re: Realizing still life constraints as a planar tiling

Post by pcallahan » May 27th, 2016, 3:27 pm

One more comment. I have been trying to think of a way to construct a 3-tile solution for empty 0-1-2-neighborhoods that does not use an internal tile and does not result in ambiguity with empty 4+-neighborhoods. I believe there is an alternative 3-tile solution that looks more like the one I posted for live 2-3-neighborhoods (left as an exercise). But I am coming around to the view that symmetry requires the tile to be split on octagon diagonals (you can split at edge midpoints, but you need another tile) and without interior tiles or 3D interlocking, the only possible boundary is a straight line.

User avatar
Scorbie
Posts: 1692
Joined: December 7th, 2013, 1:05 am

Re: Realizing still life constraints as a planar tiling

Post by Scorbie » May 28th, 2016, 1:03 am

There is an option to use magnets to hold the tiles together.Just in case you weren't aware of that...

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Realizing still life constraints as a planar tiling

Post by simsim314 » May 28th, 2016, 7:31 am

Scorbie wrote:There is an option to use magnets
I mentioned this option here.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Realizing still life constraints as a planar tiling

Post by simsim314 » May 28th, 2016, 1:09 pm

Here is my new interpretation of the tiles. It looks somewhat over complex, on the other hand everything is interlocking well (please comment):
tiles_v2.0.png
tiles_v2.0.png (137.44 KiB) Viewed 17447 times
And the code (many parameters added for the live case):

Code: Select all

//!OpenSCAD

//main parameters
emptyToothWidth = 0.4;
emptyToothLength = 0.1;
filledToothWidth = 0.5;

rfilled = 0.55; 
cutFilled = 0.1; 

r1Jig = 0.2; 
r2Jig = 0.14; 
slopeJig = 0.4;

//3d structural teeth 
cubeSizeW = 0.17;
cubeAngle = 30;
toothLocation = 0.07;
//Adding 3d tooths flag
add3dStructure = true; 
addScale= true; 
//Height 
H = 1;
r = 10;
d = r * cos(45 / 2);
side = 2 * r * sin(45 / 2);
eps = 0.001; 

dFactor = 0.1;
scalefactor1 = 0.935;
scalefactor2 = 0.95;
scaleEmpty = 1.03;

module Tooth()
{
    translate([0, 0, -H / 2])rotate([90, 0, 0])linear_extrude(height = cubeSizeW * r) polygon([[-eps,-eps], [-eps ,H / 2],[H / 2 * sin(cubeAngle), -eps]]); 
}

module Slice(use3D = true, r1 = r) 
{
   if(use3D && add3dStructure)
   {
       difference()
       {
           union()
           {
            linear_extrude(height = H) rotate([0,0,-45/2])polygon([[0,0],[r1, 0],[r1 * cos(360/8), r1* sin(360/8)]] );
            translate([d, - side * toothLocation, H / 2]) Tooth();
            translate([d, side * toothLocation, H / 2]) rotate([180, 0, 0]) Tooth();
           }   
           
            translate([d, - side * toothLocation, H / 2]) rotate([0, 180, 0]) Tooth();
            translate([d, side * toothLocation, H / 2]) rotate([180, 180, 0]) Tooth();
       }
   }
   else 
   {
    linear_extrude(height = H) rotate([0,0,-45/2])polygon([[0,0],[r, 0],[r * cos(360/8), r* sin(360/8)]] );
   }
};


module SliceWithTooth() 
{
    
    union()
    {
        Slice(false);
         linear_extrude(height = H) translate([d,  -r * emptyToothWidth / 2]) square([r * emptyToothLength,r * emptyToothWidth]);
    }
};


//Tiles from slices

module SquareTilePiece()
{
     difference()
       {
           union()
           {
             linear_extrude(height = H) polygon([[0,0], [side/2,side/2], [side/2,-side/2]]);
               if(add3dStructure)
               {
                translate([side / 2, - side * toothLocation, H / 2]) Tooth();
                translate([side / 2, side * toothLocation, H / 2]) rotate([180, 0, 0]) Tooth();
               }
           }   
           
           if(add3dStructure)
           {
            translate([side / 2, - side * toothLocation, H / 2]) rotate([0, 180, 0]) Tooth();
            translate([side / 2, side * toothLocation, H / 2]) rotate([180, 180, 0]) Tooth();
           }
       }
    
}
module SquareTile()
{
    rotate([0,0,45/2])union()
    {
        SquareTilePiece();
        rotate([0,0,90]) SquareTilePiece();
        rotate([0,0,180]) SquareTilePiece();
        rotate([0,0,-90]) SquareTilePiece();
    }
};

//Simple Living parts
module LiveSlice()
{
    r1 = (r * cos(45/2) - emptyToothLength * r) / cos(45/2);
    
    color([0, 0.4, 0.9]) linear_extrude(height = H) rotate([0,0,-45/2])polygon([[0,0],[r1, 0],[r1 * cos(360/8), r1 * sin(360/8)]] );
        
    
};

//Simple Living parts
module LiveSlicePartial(dir)
{
    r1 = (r * cos(45/2) - emptyToothLength * r) / cos(45/2);
    r2 = r1 * rfilled;
    r3 = r * cutFilled;
    
    difference()
    {
        color([0, 0.4, 0.9]) linear_extrude(height = H) rotate([0,0,-45/2])polygon([[0,0],[r1, 0],[r1 * cos(360/8), r1 * sin(360/8)]] );
        linear_extrude(height = H) rotate([0,0,-45/2])polygon([[0,0],[r2, 0],[r2 * cos(360/8), r2 * sin(360/8)]]);
        linear_extrude(height = H) polygon([[0,0],[r2 * cos(360 / 16) + r3, 0],[r2 * cos(360 / 16) + r3, r * dir]]);
    
    }
};

module LiveSliceWithTooth() 
{
    size = r/6;
    dtooth = r * filledToothWidth;
    
    color([0, 0.4, 0.9]) union()
    {
        LiveSlice();
        linear_extrude(height = H)translate([r * cos(45/2) - size,  -dtooth /2])square([size,dtooth ]);
    }
};


module LiveSliceWithToothPartial(dir) 
{
    size = r/6;
    dtooth = r * filledToothWidth;
    
    color([0, 0.4, 0.9]) union()
    {
        LiveSlicePartial(dir);
        linear_extrude(height = H)translate([r * cos(45/2) - size,  -dtooth /2])square([size,dtooth ]);
    }
};

module HelperLife_InternalTooth()
{
   rotate([0,0,45])
   union()
    {
        LiveSliceWithTooth();
        rotate([0,0,45]) LiveSliceWithTooth();
        rotate([0,0,-45]) LiveSliceWithTooth();
    }
};


module TileLife_InternalTooth()
{
   rotate([0,0,45/2])
    color([0, 0.4, 0.9]) 
     difference()
    {
        linear_extrude(height = H)polygon([[-d, d], [-d, -d], [d, -d], [d, d]]); 
        translate([-d, -d]) HelperLife_InternalTooth();
        translate([d, -d]) rotate([0,0,90]) HelperLife_InternalTooth();
        translate([-d, d]) rotate([0,0,-90]) HelperLife_InternalTooth();
        translate([d, d]) rotate([0,0,180]) HelperLife_InternalTooth();
        translate([d - filledToothWidth * r / 2, -d/2])cube([side, side, H]);
        translate([-side -d + filledToothWidth * r / 2, -d/2])cube([side, side, H]);
        translate([-d/2, -side -d + filledToothWidth * r / 2 ])cube([side, side, H]);
        translate([-d/2, d - filledToothWidth * r / 2 ])cube([side, side, H]);
    }
};


module TileSpaceFiller_Type4()
{
    rotate([0,0,-45/2])
     color([0, 0.4, 0.9]) 
    difference()
    {
         linear_extrude(height = H) polygon([[-side, side], [-side, -side], [side, -side], [side, side]]); 

    translate([d, -d]) rotate([0,0,45 + 135]) SliceWithTooth()  ;
    translate([d, -d]) rotate([0,0,45 + 90]) Slice()  ;
    translate([d, -d]) rotate([0,0,45 + 45]) SliceWithTooth()  ;
  
        
  translate([d, d]) rotate([0,0,45 + 180])LiveSliceWithTooth() ;
  translate([d, d]) rotate([0,0,45 + 135 ])LiveSlice() ;
  translate([d, d]) rotate([0,0,45 + -135])LiveSlice() ;
  
    translate([-d, d]) rotate([0,0,45 + -45]) SliceWithTooth()  ;
translate([-d, d]) rotate([0,0,45 + -90]) Slice()  ;
  translate([-d, d]) rotate([0,0,45 + -135]) SliceWithTooth();  
    
    translate([-d, -d])rotate([0,0,45]) LiveSliceWithTooth() ;
  translate([-d,-d]) rotate([0,0,45 + 45])LiveSlice() ;
  translate([-d, -d]) rotate([0,0,45 + -45])LiveSlice() ;
    }
  
};

module TileSpaceFiller_Type3()
{

    rotate([0,0,-45/2])
     color([0, 0.4, 0.9]) 
    difference()
    {
         linear_extrude(height = H) polygon([[-side, side], [-side, -side], [side, -side], [side, side]]); 

          translate([d, -d]) rotate([0,0,45 + 135]) LiveSlice()  ;
    scale(1 + eps)translate([d, -d]) rotate([0,0,45 + 90]) LiveSlice()  ;
  translate([d, -d]) rotate([0,0,45 + 45]) LiveSlice()  ;
  
  translate([d, d]) rotate([0,0,90 + 180])SliceWithTooth() ;     
  scale(1 + eps)translate([d, d]) rotate([0,0,45 + 180])Slice() ;
  translate([d, d]) rotate([0,0,45 + 135])Slice() ;
  
    
   translate([-d, d]) rotate([0,0,45 + -45]) Slice()  ;
  scale(1 + eps)translate([-d, d]) rotate([0,0,45 + -90]) SliceWithTooth()  ;
  translate([-d, d]) rotate([0,0,45 + -135]) Slice();  
    
  
  translate([-d,-d]) rotate([0,0,45 + 45])Slice() ;  
  scale(1 + eps)translate([-d, -d])rotate([0,0,45]) Slice() ;
  translate([-d, -d]) rotate([0,0,45 + -45])SliceWithTooth() ;
    
    }
  
};

module TileSpaceFiller_Type2()
{

    rotate([0,0,-45/2])
     color([0, 0.4, 0.9]) 
    difference()
    {
         linear_extrude(height = H) polygon([[-side, side], [-side, -side], [side, -side], [side, side]]); 

          translate([d, -d]) rotate([0,0,45 + 135]) LiveSliceWithTooth()  ;
    scale(1 + eps)translate([d, -d]) rotate([0,0,45 + 90]) LiveSlice()  ;
  translate([d, -d]) rotate([0,0,45 + 45]) LiveSlice()  ;
  
  translate([d, d]) rotate([0,0,90 + 180])SliceWithTooth() ;     
  scale(1 + eps)translate([d, d]) rotate([0,0,45 + 180])SliceWithTooth() ;
  translate([d, d]) rotate([0,0,45 + 135])Slice() ;
  
    
   translate([-d, d]) rotate([0,0,45 + -45]) Slice()  ;
  scale(1 + eps)translate([-d, d]) rotate([0,0,45 + -90]) SliceWithTooth()  ;
  translate([-d, d]) rotate([0,0,45 + -135]) SliceWithTooth();  
    
  
    translate([-d,-d]) rotate([0,0,45 + 45])LiveSlice() ;  
  scale(1 + eps)translate([-d, -d])rotate([0,0,45]) LiveSlice() ;
  translate([-d, -d]) rotate([0,0,45 + -45])LiveSliceWithTooth() ;
    
    }
  
};


module TileSpaceFiller_Type1()
{

    rotate([0,0,-45/2])
     color([0, 0.4, 0.9]) 
    difference()
    {
         linear_extrude(height = H) polygon([[-side, side], [-side, -side], [side, -side], [side, side]]); 

          translate([d, -d]) rotate([0,0,45 + 135]) SliceWithTooth()  ;
    scale(1 + eps)translate([d, -d]) rotate([0,0,45 + 90]) SliceWithTooth()  ;
  translate([d, -d]) rotate([0,0,45 + 45]) SliceWithTooth()  ;
  
  translate([d, d]) rotate([0,0,90 + 180])LiveSlice() ;     
  scale(1 + eps)translate([d, d]) rotate([0,0,45 + 180])LiveSliceWithTooth() ;
  translate([d, d]) rotate([0,0,45 + 135])LiveSliceWithTooth() ;
  
    
   translate([-d, d]) rotate([0,0,45 + -45]) LiveSliceWithTooth()  ;
  scale(1 + eps)translate([-d, d]) rotate([0,0,45 + -90]) LiveSlice()  ;
  translate([-d, d]) rotate([0,0,45 + -135]) LiveSliceWithTooth();  
    
  
    translate([-d,-d]) rotate([0,0,45 + 45])LiveSliceWithTooth() ;  
  scale(1 + eps)translate([-d, -d])rotate([0,0,45]) LiveSliceWithTooth() ;
  translate([-d, -d]) rotate([0,0,45 + -45])LiveSlice() ;
    
    }
  
};

module TileLife_TwoSlicePartial()
{
    color([0, 0.4, 0.9])  union()
    {
        LiveSliceWithToothPartial(1);
        rotate([0, 0, 45])LiveSlicePartial(-1);
    }
}

module TileLife_FourSlicePartial()
{
    r1j = r * r1Jig;
    r2j = r * r2Jig;
    
    color([0, 0.4, 0.9]) rotate([0,0,-45/2])difference()
    {
        rotate([0,0,45/2])difference()
        {
            union()
            {
                LiveSlice();
                rotate([0, 0, 45])LiveSlice();
                rotate([0, 0, 90])LiveSlice();
                rotate([0, 0, 135])LiveSliceWithTooth();
            }
            
             rotate([0, 0, 45])TileLife_TwoSlicePartial();
        }
        
        linear_extrude(height = H) polygon([[-r1j, 0], [r1j, 0], [r1j + slopeJig * r2j, r2j], [-r1j - slopeJig * r2j, r2j]]); 

    }
}


module TileLife_FourSlice()
{
    r1j = r * r1Jig;
    r2j = r * r2Jig;
    
    color([0, 0.4, 0.9]) rotate([0,0,-45/2])difference()
    {
        rotate([0,0,45/2])
        {
            union()
            {
                LiveSlice();
                rotate([0, 0, 45])LiveSlice();
                rotate([0, 0, 90])LiveSlice();
                rotate([0, 0, 135])LiveSliceWithTooth();
            }
        }
        
        linear_extrude(height = H) polygon([[-r1j, 0], [r1j, 0], [r1j + slopeJig * r2j, r2j], [-r1j - slopeJig * r2j, r2j]]); 
    }
}

module TileLife_StaticPart()
{
    color([0, 0.4, 0.9]) difference()
    {
        union()
        {
            for (i = [0 : 7])
               rotate([0,0,45 * i]) LiveSlice();
        }   
    
    
        rotate([0,0,45])TileLife_TwoSlicePartial();
        rotate([0,0,180])TileLife_TwoSlicePartial();
        TileLife_FourSlicePartial();
    }
}


module EmptyTile4_2teeth_90()
{
    difference()
    {
    union()
    {
        SliceWithTooth();
        rotate([0,0,45]) SliceWithTooth();
    }
      TileLife_InternalTooth();
    }  
};

module EmptyTile4_1teeth_90()
{
    difference()
    {
        union()
        {
            Slice();
            rotate([0,0,45]) SliceWithTooth();
        }
         TileLife_InternalTooth();
    }  
};

module EmptyTile4_2teeth_180()
{
    difference()
    {
        union()
        {
            Slice();
            rotate([0,0,45]) Slice();
            rotate([0,0,90]) SliceWithTooth();
            rotate([0,0,135]) SliceWithTooth();
        }
        TileLife_InternalTooth();
    }
};

module PlaceFilled(x, y, type, rot)
{
    dx = dFactor * cos(45/2 - 45 * rot);
    dy = dFactor  * sin(45/2 - 45 * rot);
   
    if(type == 0)
        translate([2 * d * x + dx, 2 * d * y + dy]) scale(scaleEmpty * scalefactor1) rotate([0,0,-45 - 45 * rot])TileLife_EmptyInternalEdgeTooth();
    if(type == 1)
        translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scaleEmpty * scalefactor1) rotate([0,180, -90 - 45 * rot])TileLife_EmptyInternalEdgeTooth();
    if(type == 2)
        translate([2 * d * x + dx, 2 * d * y + dy]) scale(scaleEmpty * scalefactor1) rotate([0,0,-45 - 45 * rot])TileLife_EmptyInternalTooth();
    if(type == 3)
        translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scaleEmpty * scalefactor1) rotate([0,180, -90 - 45 * rot])TileLife_EmptyInternalTooth();
    if(type == 4)
        translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor2) rotate([0,0,-45 - 45 * rot]) TileLife_FilledInternalEdgeTooth();
    if(type == 5)
        translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scalefactor2) rotate([0,180, -90 - 45 * rot])TileLife_FilledInternalEdgeTooth();
    if(type == 6)
        translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor2) rotate([0,0,-45 - 45 * rot]) TileLife_FilledInternalTooth();
      if(type == 7)
        translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scalefactor2) rotate([0,180, -90 - 45 * rot])TileLife_FilledInternalTooth();
};

module PlaceInternalConnector(x, y, type, rot)
{
    dx = 0;
    dy = 0;
   
    if(type == 0)
        translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,- 45 * rot])TileSpaceFiller_Type4();
    if(type == 12)
        color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,45 - 45 * rot])SquareTile();
    if(type == 4)
    {
        if(abs(rot - floor(rot)) < 0.1)
            color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,45 - 45 * rot])TileLife_InternalTooth();
        else
            color([0, 0.4, 0.9]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor1) rotate([0,0, 45 /2 - 45 * rot])TileLife_InternalTooth();
    }
    
}

module PlaceExternalConnector(x, y, type, rot)
{
    dx = 0; 
    dy = 0;
   
    if(type == 0)
        translate([d + 2 * d * x + dx, d + 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,45/2 - 90 * rot])TileSpaceFiller_Type4();
    if(type == 1)
        color([0.8, 0.8, 0.2]) translate([d + 2 * d * x + dx, d + 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,45/2 - 90 - 90 * rot])TileSpaceFiller_Type3();
    if(type == 2)
        color([0.8, 0.8, 0.2]) translate([d + 2 * d * x + dx, d + 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,45/2 - 90 - 90 * rot])TileSpaceFiller_Type1();
    if(type == 3)
        color([0.8, 0.8, 0.2]) translate([d + 2 * d * x + dx, d + 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,45/2 - 90 -  90 * rot])TileSpaceFiller_Type2();
        
    if(type == 12)
        color([0.8, 0.8, 0.2]) translate([d + 2 * d * x + dx, d + 2 * d * y + dy]) scale(scalefactor1) rotate([0,0,45/2 - 45 * rot])SquareTile();
    if(type == 4)
         color([0, 0.4, 0.9])  translate([d +2 * d * x + dx, d +2 * d * y + dy]) scale(scalefactor1) rotate([0,0,-45/2 ])TileLife_InternalTooth();
    
}

module PlaceEmpty0(x, y, type, rot)
{
    dx = dFactor * cos(45/2 - 45 * rot);
    dy = dFactor  * sin(45/2 - 45 * rot);
   
    if(type == 0)
        color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor2) rotate([0,0,-45 - 45 * rot])EmptyTile0_NoTeeth();
    if(type == 1)
        color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor2) rotate([0,0,-45 - 45 * rot])EmptyTile0_InternalTeeth();
    if(type == 2)
        color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scalefactor2) rotate([0,180, -90 - 45 * rot])EmptyTile0_InternalTeeth();        
    if(type == 3)
        color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor2) rotate([0,0,-45 - 45 * rot])EmptyTile0_EdgeTeeth();
    if(type == 4)
        color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scalefactor2) rotate([0,180, -90 - 45 * rot])EmptyTile0_EdgeTeeth();        
    

}

module PlaceEmpty4(x, y, type, rot)
{
    dx = dFactor * cos(45/2 - 45 * rot);
    dy = dFactor  * sin(45/2 - 45 * rot);
   
    if(type == 0)
        color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor2) rotate([0,0,-45 - 45 * rot])EmptyTile4_2teeth_180();
    if(type == 1)
        color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scalefactor2) rotate([0,180, -90 - 45 * rot])EmptyTile4_2teeth_180();
    if(type == 2)
        color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor2) rotate([0,0,45 - 45 * rot])EmptyTile4_1teeth_90();
    if(type == 3)
        color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy, H]) scale(scalefactor2) rotate([0,180, -90 - 45 * rot])EmptyTile4_1teeth_90();
    if(type == 4)
        color([0.8, 0.8, 0.2]) translate([2 * d * x + dx, 2 * d * y + dy]) scale(scalefactor2) rotate([0,0,45 - 45 * rot])EmptyTile4_2teeth_90();
}


module EmptyTile0_NoTeeth()
{
    difference()
    {
        union()
        {
            Slice();
            rotate([0,0,45]) Slice();
            rotate([0,0,90]) Slice();
            rotate([0,0,135]) Slice();
        }
        
       rotate([0,0,45]) TileLife_InternalTooth();
    }
};

module EmptyTile0_EdgeTeeth()
{
    difference()
    {
        union()
        {
            SliceWithTooth();
            rotate([0,0,45]) Slice();
            rotate([0,0,90]) Slice();
            rotate([0,0,135]) Slice();
        }
        
       rotate([0,0,45]) TileLife_InternalTooth();
    }
};


module EmptyTile0_InternalTeeth()
{
    difference()
    {
        union()
        {
            Slice();
            rotate([0,0,45]) SliceWithTooth();
            rotate([0,0,90]) Slice();
            rotate([0,0,135]) Slice();
        }
        
         rotate([0,0,45]) TileLife_InternalTooth();
    }
};


/*
translate([r * 3, 0])TileLife_FourSlicePartial();
translate([r * 6, 0])TileLife_TwoSlicePartial();
TileLife_StaticPart();
translate([r * 9, 0])TileLife_FourSlice();
*/

d1 = 2.4 * d;
translate([-2 * d1, 2 * d1]) TileSpaceFiller_Type4();
translate([- d1, 2 * d1])TileSpaceFiller_Type3();
translate([0, 2 * d1])TileSpaceFiller_Type1();
translate([d1, 2 * d1])TileSpaceFiller_Type2();

color([0.8, 0.8, 0.2])translate([- 2 * d1,  d1])TileLife_InternalTooth();
translate([-  d1,  d1])TileLife_FourSlicePartial();
translate([0,  d1])TileLife_TwoSlicePartial();
translate([d1,  d1])TileLife_StaticPart();

translate([- 2 * d1,  0])TileLife_FourSlice();
color([0.8, 0.8, 0.2])translate([- d1,  0])EmptyTile4_2teeth_180();
color([0.8, 0.8, 0.2])translate([0,  0])EmptyTile4_1teeth_90();
color([0.8, 0.8, 0.2])translate([d1,  0])EmptyTile4_2teeth_90();

color([0.8, 0.8, 0.2])translate([- 2 * d1,  -d1])SquareTile();
color([0.8, 0.8, 0.2])translate([- d1,  -d1])EmptyTile0_NoTeeth();
color([0.8, 0.8, 0.2])translate([0,  -d1])EmptyTile0_InternalTeeth();
color([0.8, 0.8, 0.2])translate([d1,  -d1])EmptyTile0_EdgeTeeth();

User avatar
pcallahan
Posts: 845
Joined: April 26th, 2013, 1:04 pm

Re: Realizing still life constraints as a planar tiling

Post by pcallahan » May 28th, 2016, 1:30 pm

Scorbie wrote:There is an option to use magnets to hold the tiles together.Just in case you weren't aware of that...
There are many options when it comes to a physical realization of the tiles. I'm still curious about the tiling problem in the abstract. I am not super-happy about reusing the diagonal-connecting tiles for interior fitting, but it's sound mathematically. So my question stated more precisely is whether there is a set of 6 or fewer planar tiles that can combine to empty 0-1-2-neighborhoods and empty 4-5-6-neighborhoods but cannot combine to empty 3-neighborhoods. Right now we have just 6 tiles for these neighborhoods, but it requires the (IMO) MacGyver-like use of diagonal-connecting tiles. Since MacGyver-like is not a well-defined mathematical concept, it's probably not that important, but it bothers me nonetheless. It just doesn't seem like an elegant tiling (and magnets and 3D contours don't help with this).

User avatar
Scorbie
Posts: 1692
Joined: December 7th, 2013, 1:05 am

Re: Realizing still life constraints as a planar tiling

Post by Scorbie » May 28th, 2016, 2:29 pm

How about cutting the tiles for 012 neighborhoods in a different axis? You can rotate the line (that cuts the octagon in half) 22.5 degrees and it seems to work. Or did I miss something obvious?
Here are the tiles I am talking about:
https://drive.google.com/file/d/0B057ay ... p=drivesdk
Sorry for the lack of any program...

User avatar
pcallahan
Posts: 845
Joined: April 26th, 2013, 1:04 pm

Re: Realizing still life constraints as a planar tiling

Post by pcallahan » May 28th, 2016, 4:20 pm

I did consider using the other axis of symmetry but I thought it would involve cutting the tooth in half the way calcyman did. The jutting tooth is interesting and never occurred to me. I haven't verified that you can get all four 2-neighborhoods (I have just a couple of minutes to read and post right now).

UPDATE: I don't think you can get a one-space gap between teeth in a 2-neighborhood.

User avatar
Scorbie
Posts: 1692
Joined: December 7th, 2013, 1:05 am

Re: Realizing still life constraints as a planar tiling

Post by Scorbie » May 28th, 2016, 9:51 pm

https://drive.google.com/file/d/0B057ay ... p=drivesdk
Here are all the 2 teeth octagons.

Edit:
(I have just a couple of minutes to read and post right now).
Me too. I totally understand that.

User avatar
pcallahan
Posts: 845
Joined: April 26th, 2013, 1:04 pm

Re: Realizing still life constraints as a planar tiling

Post by pcallahan » May 28th, 2016, 10:52 pm

Scorbie wrote:Here are all the 2 teeth octagons.
Thanks! I realized I was wrong about twenty minutes after I went offline, but this is the first chance I have had to reply. I think this shows there is a 16-tile solution that doesn't require reusing the diagonal-connecting tiles (need a better name) to hook up other tiles. Of course, it doesn't exclude using them to lock the pieces, but this was not my original concern.

Here is a rough rendering of the tile combinations using the same tooth size as calcyman. In practice, the hanging tooth would be fragile, but the teeth could be made wider and a little longer.
Screen Shot 2016-05-28 at 10.09.26 PM.png
Screen Shot 2016-05-28 at 10.09.26 PM.png (46.58 KiB) Viewed 17395 times

--Paul

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Realizing still life constraints as a planar tiling

Post by simsim314 » May 29th, 2016, 1:37 am

Yes scorbie idea was confusing, but I don't see any benefit of this idea. How can we use those tiles for 4-8 case? If we don't, this external tooth is very breakable, and the connection line is straight, this will bring us back to the current tiles more or less.

User avatar
pcallahan
Posts: 845
Joined: April 26th, 2013, 1:04 pm

Re: Realizing still life constraints as a planar tiling

Post by pcallahan » May 29th, 2016, 1:50 am

simsim314 wrote: I don't see any benefit of this idea. How can we use those tiles for 4-8 case?
We don't. We use the existing tiles (quarter and half octagons without interlocking) for the 4-8 case. Because the tile sets split on different axes, they can't be combined. It strikes me as a cleaner solution to finding 16 planar tiles for still life constraints because it doesn't reuse the diagonal connecting tiles. As physical puzzle pieces, they may be less than ideal, but I had been curious if there was a planar solution that did not reuse the diagonal connecting tiles. It is interesting to me to see that it's possible.

User avatar
simsim314
Posts: 1823
Joined: February 10th, 2014, 1:27 pm

Re: Realizing still life constraints as a planar tiling

Post by simsim314 » May 29th, 2016, 2:25 pm

Oh nice idea Scorbie! Once again I missed the point, thanks pcallahan for clarifying!

Now my question: is there something that also "self maintainable" and interlocking, for the empty tiles like for the live tiles?

I will explain the concern - reusing spacefillers is good idea, if they contain the same color, but in our case we have spacefiller which is perfectly "live" (all neighbors are live) and perfectly "empty". This brings the need to create "self maintaining" empty tiles, exactly like like pcallahan managed to solve for the live case.

User avatar
pcallahan
Posts: 845
Joined: April 26th, 2013, 1:04 pm

Re: Realizing still life constraints as a planar tiling

Post by pcallahan » May 29th, 2016, 3:45 pm

simsim314 wrote:I will explain the concern - reusing spacefillers is good idea, if they contain the same color, but in our case we have spacefiller which is perfectly "live" (all neighbors are live) and perfectly "empty".
One alternative is to change the empty tiling to have a more interlocking space filler. I originally liked the idea of the tiling turning into a simple truncated square tiling in empty space, but something like this (many variations are possible) would give you a better internal piece for joining empty neighborhoods.

UPDATE: Fixed symmetry issue. This is hand-traced over octagons in Google drawing but gives the idea.
Screen Shot 2016-05-29 at 6.41.17 PM.png
Screen Shot 2016-05-29 at 6.41.17 PM.png (81.37 KiB) Viewed 17340 times
Last edited by pcallahan on May 29th, 2016, 9:44 pm, edited 1 time in total.

Post Reply