Tile the plane with squashed hexagons

I came across an interesting tiling of the plane using squashed hexagons in a popular math book. All the six edges of the squashed hexagon are the same length. Two opposite corners are right angles and the rest four corners are 135 degrees each. This shape allows four squashed hexagons be arranged so that they meet at a point. Then “concentric rings” of squashed hexagons can outline the resulting cross indefinitely.

Write a full program or a function that accepts an integer 0 < n < 10 and renders n rings of this tessellation. You can rotate the image by 45 dergrees if it's more convenient for your algorithm. You can render directly to the screen, or save the result to a file. In either case, please provide an image demonstrating the the result of your code. You can crop the resulting image so that it contains only the hexagons.

Examples:

n = 1

n = 2

n = 3

n = 4

The shortest code in bytes in each language wins.

• Galen do you happen to know if J’s graphing facilities would be capable of this? – Jonah May 14 at 12:48
• @Jonah I'm not familiar with graphics in J, but the book "Fractals Visualization and J" mentions plotting polygons. It says the following addons are needed: graphics/fvj4 and media/imagekit. (I haven't read it, just opened it to check) – Galen Ivanov May 14 at 12:57
• It's too bad Hexagony doesn't (as far as I know) have the ability to do graphics - that would be worth some bonus points... – Darrel Hoffman May 14 at 15:20
• @DarrelHoffman You can output to an image file too (instead of doing "real" graphics), e.g. write a BMP, but I'm not sure if it's worth the hassle :) – schnaader May 14 at 20:15
• @schnaader Having written a BMP parser in Assembly (as a school assignment years ago), that just gave me chills. Combine that with trying to do anything useful in Hexagony, AND golf it, yeah, definitely not worth it. – Darrel Hoffman May 14 at 20:22

JavaScript (ES6), 319 313 bytes

f=
n=>{s=<svg viewBox=${n*=-12},${n},${n*=-2},${n}><use href=#d transform=rotate(180) /><g id=d><use href=#s transform=rotate(90) /><path id=s fill=none stroke=#000 d=
for(n/=24;n--;)for(j=0;j<=n;j++)s+=M${n*5+j*7},${n*12-j*7}h7l5,5v7h-7l-5,-5z+(j<n?M${n*12},${n*5-j*10}h7l5,-5l-5,-5h-7l-5,5z:)
return s+>}
<input type=number min=1 oninput=o.innerHTML=f(this.value)><div id=o>

Output is an HTML5 SVG, which the snippet inserts into a DOM node so that you can see it. Output is rotated by 45° as allowed by the question. Edit: Saved 3 bytes thanks to @KevinCruijssen.

• ${n*-12},${n*-12},${n*24},${n*24} and i<n can be ${n*=-12},${n},${n*=-2},${n} and i<n/24 for -2. And for(i=0;i<n;i++) can be for(i=n;i-->0;) for an additional -1. – Kevin Cruijssen May 14 at 13:23
• @KevinCruijssen Then again. this isn't Java, so I don't need the >0, and now I can just use n instead of i, saving another byte. – Neil May 14 at 14:06
• The output is rotated 45º counter-clockwise. At least it is on Google Chrome. Would be better to specify this in your answer, so others don't think it is wrong. – Ismael Miguel May 15 at 9:26
• @IsmaelMiguel OK I'll clarify that. – Neil May 15 at 9:40

GFA Basic 3.51 (Atari ST),  187 181 174  171 bytes

A manually edited listing in .LST format. All lines end with CR, including the last one.

PRO f(n)
DR "MA166,94"
t$="FD8LT45PD" h$=t$+"FD8LT90"+t$+t$+"FD8LT90FD8BK8LT90FD8RT45" a$=""
F i=1TO n
DR STRING$(4,a$+h$+"LT45BK8"+a$+t$)+"PUFD8RT45"+t$
a$=a$+h$N i RET  Expanded and commented PROCEDURE f(n) ' move the pen at (166,94) DRAW "MA166,94" ' t$ = move forward by 8, left turn of 45 degrees, pen down
t$="FD8LT45PD" ' h$ holds the directives to draw a single hexagon
' and get ready to draw a contiguous hexagon
h$=t$+"FD8LT90"+t$+t$+"FD8LT90FD8BK8LT90FD8RT45"
' a$is used to store a concatenation of hexagons a$=""
' draw n rings
FOR i=1 TO n
' draw a full ring and move to the next ring
DRAW STRING$(4,a$+h$+"LT45BK8"+a$+t$)+"PUFD8RT45"+t$
' append a new hexagon to a$a$=a$+h$
NEXT i
RETURN

Logo, 276 245 bytes

to i:n
repeat 2[repeat:n[repeat 2[fd 7
rt 45]fd 7
bk 7
lt 90]rt 90
fd 7
rt 90]end
to j:n
make"m:n
repeat:n[i:m
make"m:m-1
rt 90
repeat 2[fd 7
lt 45]]repeat:n[repeat 2[rt 45
bk 7]lt 90]end
to k:n
repeat 4[j:n
rt 90
fd 7
lt 45
j:n-1
rt 45
bk 7]end


Use k <n> to invoke. Output is rotated by 45° as allowed by the question. Example for n=10: Try it online!

Python 3, 361 342 bytes

from turtle import*
def t(a):r(a);fd(9)
u=45;n=int(input());Q=set((1,(0,0),a*90,a>3)for a in range(8));ht()
while Q:
o,p,a,m=Q.pop()
if round(o)>n:continue
r=(rt,lt)[m];g=not o%1;up();goto(*p);seth(a);pd();t(-u)
if g:k(1.1)
t(u)
if g:k(1)
t(u);t(-u);k(2+g/3);undo();undo();t(90);t(u);t(u)
done()

Shadertoy (GLSL), 777 710 679 644 630 609 bytes

#define V vec2
#define F float
#define R return
const int n=10;const F Z=2.2/F(n),W=.01*Z,L=.07*Z,K=L/2.,M=K*1.414;F h(V u,V c){u=abs(u-c);
if(u.x>.0&&u.x<K)R abs(u.y-M)<W/1.4?.0:1.;else if(u.x<K+M+W)R abs(u.y-M+u.x-K)<W?.0:1.;R 1.;}
F m(V u,V c){u=abs(u);R h(u,c)*h(u.yx,c);}void mainImage(out vec4 f,in V c){V S=iResolution.xy;V v=c/S-V(.5);
v.y/=S.x/S.y;F b=-atan(1.);mat2 o=mat2(cos(b),-sin(b),sin(b),cos(b));V w=o*v;F s=1.,a=K+M,k=.0,l;int i,j,J;
for(i=0;i<n;i++,k++){J=i/2+1;l=.0;for(j=0;j<J;j++,l++){F z=l*2.*M;if(i%2==1)z+=M;
s*=m(v,V(a+k*(L+M),z));if(i<n-1)s*=m(w,V(a+k*(L+M)+L,z));}}f.xyz=vec3(s);}


Happy to finally see this working, the tile layout can be a bit puzzling at first. It automatically "zooms in" for lower n values, but can also be manually adjusted by changing the Z variable because it's not optimal. Something is a bit wrong with the line drawing where diagonal and straight lines meet (which gets more apparent for lower n values), perhaps I'll find a way to get that fixed. There also is an ungolfed version with some comments on how it does things.

Output for n = 10:

• I think you can save a bunch of chars by redefining common tokens, e.g #define V vec2 or #define R return. Redundant zeros can be removed from floats, e.g 1. or .1 Also put everything in 1 line to get rid of all new line characters. – Surculose Sputum May 16 at 2:56

JavaScript + HTML + CSS, 82 + 39 + 204 = 325 bytes

JavaScript

Function that takes a number n. An internal function P recursively generates an ASCII pyramid of ⬡ characters, formatted as a CSS string with \a line breaks. On the HTML element with id="X", sets the custom CSS custom properties -- and --- to P(n) and P(n-1), respectively.

n=>X.style=--:"${(P=n=>(n?P(n-1)+\\a:'')+'⬡'.repeat(n))(n-1)}";---:"${P(n)}"


HTML

8 nested HTML elements whose :after pseudo-elements will contain hexagon pyramids; wrapped in a <pre> to show line breaks. <center> ensures pyramids are centered horizontally.

<pre><center id=X><i><b><i><b><i><b><i>


CSS

Applies transform: rotate(45deg) to all elements; the rotation effect compounds for the 8 nested elements. Applies content such that i:after gets the bigger pyramid ---, and center:after and b:after get the smaller pyramid --. Squishes the ASCII hexagon pyramids into a (decently accurate) tile pattern via font-size, line-height, letter-spacing, and transform – results may vary depending on your browser.

*{display:flex;place-content:center;transform:rotate(45deg)}:after{font:150%/.62 auto;letter-spacing:-5px;position:absolute;transform:matrix(.69,0,0,1,-1.75,-5);content:var(--)}i:after{top:-8px;--:var(---


Output for n = 10 (Chromium 81, macOS):

Try it!

f=

n=>X.style=--:"${(P=n=>(n?P(n-1)+\\a:'')+'⬡'.repeat(n))(n-1)}";---:"${P(n)}"

f(+prompt())
head,script{display:none !important}
body{margin:50vmin}

*{display:flex;place-content:center;transform:rotate(45deg)}:after{font:150%/.62 auto;letter-spacing:-.23em;position:absolute;transform:matrix(.71,0,0,1,-1.75,-5);content:var(--)}i:after{top:-.34em;--:var(---
<pre><center id=X><i><b><i><b><i><b><i>

• Can you attach a screenshot? I got the hexagons a bit less squashed in Chrome and that leads to gaps between the "arms". – Galen Ivanov May 28 at 10:20
• @GalenIvanov Done. – darrylyeo May 28 at 17:01
• Thank you! I've already upvoted your solution. – Galen Ivanov May 28 at 18:26