ASCII art square affine fractals

9

Write the smallest program you can to create affine fractals. You may use any method you feel like that generates the same results as the rules below. You don't have to use any ideas from the suggested methods!

Your program will take two inputs, the first to define the pattern in the format 074 made of three digits from 0 to 7. The second input will define the size, 3 will be 8x8, 4 will be 16x16 and so on (2^n). Your program must output the correct result for all sizes from 0 (1x1) to at least 5 (32x32). If it produces any output for higher numbers it must be correct, i.e. it must produce the correct output up to a certain size but produce no output above that size if it would be wrong. You may assume a maximum size of 15 (32768x32768) as that is already an insane size for ASCII art (1GB)!

An 8x8 pattern will look something like below (rule 160). The left-most digit will be for block A, the middle digit (no rude thoughts please!) for block B and the right-most digit for block C. To construct the fractal, shrink it by a half in both dimensions, and apply the rotation/mirroring rule for the block. To shrink the pattern divide it evenly into 2x2 areas. There will either be 3 visible characters or none in each area. If there are visible characters place a character in the appropriate place in the smaller block, otherwise place a space. Rules 0-3 are not mirrored, rules 4-7 are mirrored. Rules 0 and 4 are not rotated, 1 and 5 are rotated 90 degrees clockwise, 2 and 6 are rotated 180 degrees, 3 and 7 are rotated 270 degrees clockwise. Stitch the three blocks together in the order shown, A in the top-left corner, B bottom-left and C bottom-right.

 AAA    
AA A    
AA      
A       
BBB CC  
B BBC   
  BBCCC 
   B CCC

Shrunk, rotated and mirrored by rule number:

 0       1       2       3       4       5       6       7  
----    ----    ----    ----    ----    ----    ----    ----
AA       BAA    CCB        C    C        BCC    AAB       AA
A       BB A     CBB      CC    CC      BBC     A BB       A
BBC     CC         A    A BB    BB A    A         CC     CBB
 BCC    C         AA    AAB      BAA    AA         C    CCB 

Rules:

  1. Not mirrored, Rotated 90 degrees clockwise
  2. Not mirrored, Rotated 180 degrees clockwise
  3. Not mirrored, Rotated 270 degrees clockwise
  4. Mirrored but not rotated
  5. Mirrored then Rotated 90 degrees clockwise
  6. Mirrored then Rotated 180 degrees clockwise
  7. Mirrored then Rotated 270 degrees clockwise
  8. Rule 0: Not mirrored, Not rotated

The mirroring is always done first and is done diagonally through the blank corner e.g. rule 0 vs rule 4:

 0       4  
----    ----
AA /    C  /
A /     CC/ 
BBC     BB A
/BCC    /BAA

Only rules 1, 6 and 0 are used in the above pattern, in that order. After the transformations have been applied and the blocks stitched together it will look like the below except I have spaced each block from each other by one space. Your code will not have this extra space in it. If you compare it to the "parent" image you will see that it has visible characters in the same positions.

 BAA
BB A
CC  
C   

AAB  AA  
A BB A   
  CC BBC 
   C  BCC

Another way to generate the image without shrinking is as follows: Start with one character:

X

Apply the transformations for each of the three blocks (none since it's only one character) and stitch the blocks together:

X
XX

Apply the transformations for each of the three blocks again:

1 
--
XX
X 

6     0 
--    --
XX    X 
 X    XX

Stitch them together:

XX
X 
XXX 
 XXX

Apply the transformations for each of the three blocks again:

 1  
----
 XXX
XX X
XX  
X   

 6       0  
----    ----
XXX     XX  
X XX    X   
  XX    XXX 
   X     XXX

Stitch them together:

 XXX    
XX X    
XX      
X       
XXX XX  
X XXX   
  XXXXX 
   X XXX

You may use any printable character or characters (0x21 - 0x7E) for the visible part of the pattern but only the space character (0x20) for the blanks. Trailing spaces are allowed but there must be no blanks outside the entire square (i.e. for an 8x8 square there can be no characters past column 8).

There are 512 different rules, but some of them produce the same pattern. As a side note, any pattern containing only 0 and 4 will produce the Sierpinski triangle (8 different rules).

You may optionally post your favourite pattern and the rule that generates it. If you do, make sure the size is at least 3 (8x8) to distinguish it from similar rules.

CJ Dennis

Posted 2015-05-17T14:53:28.757

Reputation: 4 104

@trichoplax You can start with a completely filled square or a square with only 1 visible character in it. Either way, repeating the rules n times, where n is the input size, will guarantee the same results. However, you don't have to generate the pattern this way, only generate the same pattern as doing it this way. – CJ Dennis – 2015-05-17T15:15:11.050

@trichoplax I appreciate your input. The way I see things is not necessarily the way other people see things and I don't know I'm making it hard for them! – CJ Dennis – 2015-05-17T15:55:30.607

2

+1 Thank you, you've made the explanation much clearer! In the future, I would recommend you run things through our sandbox so that people can get a clearer picture of what you're asking ahead of time. I will be working on this challenge shortly :)

– BrainSteel – 2015-05-17T16:06:24.797

Yeah everyone sees things differently. Happy to give feedback - a good question is worth clarifying. It reads well now. – trichoplax – 2015-05-17T16:07:04.383

@BrainSteel Thank you, will do! I've been around on SE for many years but I'm still relatively new to PCG! – CJ Dennis – 2015-05-17T16:07:51.220

Answers

1

CJam, 63 57 54 52 bytes

0aarari*{\f{\~7"W%z"a*3"Wf%"t<s~}({__Ser+}%\~.++}/N*

How it works:

The basic idea is that you run a loop, the second input number of times. In each loop, starting from a single array of array containing 0 ([[0]]), we build the fractal for the next step using the three rules, fill the empty quadrant and prepare the quadrants for the next loop.

0aa                           e# Starting condition, equivalent to a single A
   ra                         e# Read the rule string and wrap it in an array
     ri*                      e# Repeat the rule array, second input number of times
        { ...  }/             e# Loop for each rule in the rule array
                              e# In each loop, we will have the current fractal and
                              e# then the rule on stack
\f{\~7"W%z"a*3"Wf%"t<s~}      
\f{                    }      e# Move the rule on top of stack and for each of the rule
                              e# character, run this loop on the current fractal
   \~                         e# Move the rule char on top and convert to int by face value
     7"W%z"a*3"Wf%"t          e# This is the array which has the logic to perform the rules
                              e# ["W%z" "W%z" "W%z" "Wf%" "W%z" "W%z" "W%z"]
                    <s        e# Based on the rule number value, take that many first items
                              e# from the above array and do a toString on the array
                              e# For rule 0 through 7, you will get the following strings:
                              e# 0: "", 1: "W%z", 2: "W%zW%z", 3: "W%zW%zW%z",
                              e# 4: "W%zW%zW%zWf%", 5: "W%zW%zW%zWf%W%z",
                              e# 6: "W%zW%zW%zWf%W%zW%z", 7: "W%zW%zW%zWf%W%zW%zW%z"
                              e# This works because each W%z will rotate the block of
                              e# fractal 90 degrees in clockwise direction.
                              e# For rule 4, where we need to mirror diagonally, we first
                              e# rotate it 279 degrees clock wise and then reverse each row
                              e# of the block. The rest of the rules after 4 take that
                              e# mirroring as base and rotate 90 degrees additionally
                      ~       e# Simply evaluate the string to apply the rule.
\f{ ... }                     e# After this for each loop, we get 3 copies of the fractal
                              e# block before the for loop. Each copy gets each one of the
                              e# three rule gets applied.
         ({      }%           e# We take out the first part corresponding to the 1st
                              e# quadrant and run each row through this loop to fill the
                              e# second quadrant with spaces
           __Ser              e# Take a copy of the row and replace everything in the
                              e# copy with spaces
                +             e# Append it to the original row
                   \~         e# Bring the last two quadrant array on top and unwrap it
                     .+       e# Append corresponding rows from the 4th quadrant to 3rd
                       +      e# Append the rows from lower half to the upper half
                              e# Now we have a full block ready to be run through
                              e# the next iteration which will double its size
                          N*  e# Finally, we join the rows of final fractal block with
                              e# newlines and automatically print the result

Try it online here

Optimizer

Posted 2015-05-17T14:53:28.757

Reputation: 25 836

Very pretty! It produces too few printable characters if the pattern starts with 0 and James Bond has a license to kill. 007: IndexOutOfBoundsException – CJ Dennis – 2015-05-18T07:34:53.200

@CJDennis There are a bug with leading zeros. Fixed now. – Optimizer – 2015-05-18T07:51:32.607

Well done! The output looks perfect now! – CJ Dennis – 2015-05-18T09:40:20.827

0

APL (Dyalog Classic), 47 bytes

⊃(⊂⍪⍕#){,/⍪⌿↑1 ¯2↑¨⊂⍺{⍉∘⊖⍣⍺⌽⍉⍣(⍺>3)⌽⍵}¨⍵}⍣⎕⍨⍎¨⍞

Try it online!

ngn

Posted 2015-05-17T14:53:28.757

Reputation: 11 449