Take a unit circle centered on the origin. In any two neighboring quadrants, mirror the curve of the circle across the lines connecting the circle's x and y intercepts.
With the resulting shape, you can tile the plane:
I made this image with the awesome 2D physics sandbox Algodoo!
Write a program that outputs an image similar to this one in some common lossless image file format. You may save the image as a file with the name of your choice or you may simply display it. No input should be taken.
Rules:
The entire image must be tessellated with the modified-circle tiles using any two visually distinct RGB colors: one for the vertically pointing tiles, one for the horizontally pointing tiles.
The radius of the circle tiles should be at least 32 pixels. (The radius in the image above is about 110 pixels.)
The image should be at least 4 tiles wide and 4 tiles tall. This, combined with the rule above, means that images can have a minimum size of 256×256 pixels. (The image above is 4 tiles by 4 tiles.)
The tessellation may be translated by any amount. For example, the top left corner of the image does not need to be the vertex where tiles meet. (The tessellation should not be rotated, however.)
You may use external graphics libraries that have commands for drawing circles and outputting images and the like.
The curves really should approximate circles, as can done with the midpoint circle algorithm, which most graphics libraries will do for you.
Anti-aliasing around the edges of the tiles is allowed but not required.
The shortest submission in bytes wins.
10 Answers 10
POV-Ray, (削除) 199 (削除ここまで) 163
Old version
camera{location -9*z}light_source{-9*z}#declare L=union{#for(X,-9,9,2)#for(Y,-9,9,2)cylinder{X*x+x+Y*y,<.001*pow(-1,(X+Y)/2),0,.1>+X*x+x+Y*y,1}#end#end}object{L pigment{color x}}object{L rotate z*90}
Same output, but golfed down further by using default light/camera, so I dont even need to specify them
#declare L=union{#for(X,-9,9,2)#for(Y,-9,9,2)cylinder{<X+1,Y,9>,<.001*pow(-1,(X+Y)/2),0,.1>+<X+1,Y,9>,1}#end#end}object{L pigment{color rgb x}rotate z*90}object{L}
enter image description here
I am using as many default parameters for camera and lightsource as possible, thats why it is a little dark. Lets ungolf it first
camera{location 9*z look_at 0}
light_source{9*z color 1}
#declare L=union{
#for(X,-9,9,2)
#for(Y,-9,9,2)
cylinder{<1+X,Y,0>, //central axis, start
<1+X,Y,0> + <.001*pow(-1,(X+Y)/2), 0, .1>, //central axis, end
1} //radius
#end
#end
}
object{L pigment{color x}} // x is the <1,0,0> vector, here interpreted as RGB
object{L rotate<0,0,90>}
It is obvious what is happening once we increase the offset of the cylinder axis and change the perspective
enter image description here
-
1\$\begingroup\$ Won't the edges be slightly distorted thanks to 3d perspective? \$\endgroup\$orlp– orlp2015年05月09日 04:04:47 +00:00Commented May 9, 2015 at 4:04
-
6\$\begingroup\$ With a height of
0.1and an offset of0.001the disk is tilted by $\phi=\arctan(0.01) = 0.57°,ドル looking from the top the disks appear squeezed by a factor of $\cos(\phi) = 0.99995,ドル thats far less than a pixel. \$\endgroup\$DenDenDo– DenDenDo2015年05月09日 07:20:43 +00:00Commented May 9, 2015 at 7:20 -
\$\begingroup\$ @DenDenDo is pov-ray not able to put a camera at infinity? \$\endgroup\$Random832– Random8322015年05月10日 04:03:16 +00:00Commented May 10, 2015 at 4:03
-
\$\begingroup\$ @Random832 it can, with
camera{orthographic location -9z}. But since the scene is basically 2D it makes no difference, you can even render it with a viewingangle 170without any fisheye distortion in the result. \$\endgroup\$DenDenDo– DenDenDo2015年05月10日 09:21:44 +00:00Commented May 10, 2015 at 9:21
Gnuplot, 182
I noticed that the boundaries between the cells look very sinusoidal, so i went for an analytical solution with a very simple core equation
enter image description here
set view map
set isosamples 900
f(x,y)=.3*sin(x*3.14)+y
splot(ceil(f(x,y))+ceil(f(y,x)))%2?1:NaN #can only modulo integers
enter image description here
While it looks similar, the circles are way too square. With the same idea, I replace sin by a curve made from concatenated quartercircle-arcs and rotate it 45° by replacing x and y with x+y and x-y
set view map
set samples 800
set isosamples 800
d=.5**.5
c(x,k)=(-1)**k*sqrt(1-(x-d*(1+2*k))**2)-(-1)**k*d # k-th circle arc
# s(x)=c(x,floor(x/d/2)) # circlified sinus
# f(x,y)=d*s(x/d)+y
f(x,y)=d*c(x/d,floor(x))+y # combined commented functions
splot(ceil(f(x+y,x-y))+ceil(f(x-y,x+y)))%2?1:NaN
enter image description here
Context Free, 99 bytes
startshape d CF::Tile=[s 4]CF::Symmetry=CF::pmg,0,1,0path d{ARCTO(-1,1,1)ARCTO(1,1,-1)ARCTO(0,0,1)}
You can see the result at the Context Free Gallery.
-
\$\begingroup\$ Nice one, that's an amazing use of Context Free. :) \$\endgroup\$Martin Ender– Martin Ender2015年05月09日 23:45:53 +00:00Commented May 9, 2015 at 23:45
HTML+JavaScript, 277
<canvas id=C></canvas><script>r=50,C.width=C.height=9*r,T=C.getContext('2d');
for(f=1,P=Math.PI,i=0;i<45;f=-f,i+=i&7?1:2)x=2*r*(i%8-2),y=2*r*(i>>3),T.moveTo(x,y+f*r),
T.arc(x+r,y+f*r,r,P,-f*P/2,f<0),T.arc(x,y,r,0,P,f>0),T.arc(x-r,y+f*r,r,-f*P/2,0,f<0);
T.fill()</script>
To test, save as html file and open with a browser. Or else, run the snippet
r=50,C.width=C.height=9*r,T=C.getContext('2d')
for(f=1,P=Math.PI,i=0;i<45;f=-f,i+=i&7?1:2)
x=2*r*(i%8-2),y=2*r*(i>>3),
T.moveTo(x,y+f*r),
T.arc(x+r,y+f*r,r,P,-f*P/2,f<0),
T.arc(x,y,r,0,P,f>0),
T.arc(x-r,y+f*r,r,-f*P/2,0,f<0)
T.fill()
<canvas id=C></canvas>
Due to popular demand, here is the output image. Not so exciting after all...
Tiles
-
1\$\begingroup\$ You may want to post an image so the code doesn't have to be run each time someone wants to see the output. \$\endgroup\$Calvin's Hobbies– Calvin's Hobbies2015年05月09日 19:27:43 +00:00Commented May 9, 2015 at 19:27
-
\$\begingroup\$ @Calvin'sHobbies oh well it's fast enough and run in every modern browser. I'll make the image bigger instead \$\endgroup\$edc65– edc652015年05月09日 19:34:25 +00:00Commented May 9, 2015 at 19:34
-
\$\begingroup\$ That's true. I thought it used
=>like a lot of your posts and would only work in Firefox. But no worries. \$\endgroup\$Calvin's Hobbies– Calvin's Hobbies2015年05月09日 19:39:13 +00:00Commented May 9, 2015 at 19:39 -
1\$\begingroup\$ Better reason for posting an image: These snippets don't work very well on mobile :( \$\endgroup\$Sp3000– Sp30002015年05月09日 20:05:32 +00:00Commented May 9, 2015 at 20:05
IDL 8.3, (削除) 201 (削除ここまで) (削除) 193 (削除ここまで) 183 bytes
The image is output into an IDL graphics window; I took a screenshot, below.
EDIT: thanks to @AlexA. and @Sp3000 for helping me shave some bytes
p=!pi/99*[0:99]
q=p[49:0:-1]
o=p[99:50:-1]
window,xs=(ys=400)
for i=0,24 do cgpolygon,i mod 5*100+50*[cos(p),cos(q)-1,cos(o)+1],i/5*100+(-1)^i*50*[sin(p),sin(q)-1,sin(o)-1],/d,/fi
end
enter image description here
Mathematica: 86 bytes (or 82 bytes)
Thanks to the infinite @alephalpha for a clever array-based method:
Image@ArrayFlatten@Array[DiskMatrix@32~RotateLeft~32/.a_/;OddQ@+##:>1-Thread@a&,{5,5}]
Inside the array is an anonymous function, which uses a clever trick to add its arguments (+##) and determine whether the sum is odd. That boolean is used as the conditional to a pattern that replaces the whole 'white' tile with the transformed, 'black' tile. From there, ArrayFlatten joins together the tiles and Image displays them.
Note the use of the shorter Thread to replace Transpose. We can still save 4 bytes by using the transpose symbol instead.
Previous: 97 bytes (or 90 bytes)
Image@ArrayFlatten@Partition[
Join@@Table[{#,1-Transpose@#}&@RotateLeft[DiskMatrix@32,32],{13}],5]
You can reduce the number of bytes by replacing Transpose@# with the superscript-t symbol (codepoint U+F3C7, shortcut ESCtrESC). In UTF-8 that brings the total to 90 bytes in 88 characters.
enter image description here
We start with DiskMatrix, which generates a binary matrix:
DiskMatrix@32 // Image
enter image description here
We then circular-shift the rows of the matrix to produce the unit cell for the tiling:
RotateLeft[DiskMatrix@32, 32] // Image
enter image description here
If the plane is a chessboard, these are the 'white' squares. For the 'black' squares, we need to invert the colors and rotate by 90 degrees. We can invert by subtracting from 1 (1 - 1 -> 0 and 1 - 0 -> 1), and rotate by taking the transpose:
Image /@ {#, 1 - Transpose@#} &@RotateLeft[DiskMatrix@32, 32]
enter image description here
If the dimensions of the image are even (like the minimum size, 4), then a tile on the right edge will be the same as the next one on the left edge. However, adding one tile to get an odd size (5) then concatenating the rows produces a regular alternating pattern.
This suggests that we can get the full image by wrapping a single row of alternating tiles with Partition. We use Table to make a list of 13 black/white tile pairs, and Join to flatten the list of pairs to a list of 26 tiles. Then we Partition the list into a 5 by 5 matrix of tiles (Partition discards the trailing 26th tile):
Map[Image] /@
Partition[
Join @@ Table[{#, 1 - #\[Transpose]} &@
RotateLeft[DiskMatrix@32, 32], {13}], 5] // MatrixForm
enter image description here
Finally ArrayFlatten turns the matrix of tile matrices into a flat matrix, and Image displays the result.
Previous: 111 bytes
Image[ArrayFlatten[{{#, #}, {#, #}}] &[
Join[#, Reverse@#, 2] &[
Join[1 - Transpose@#, #] &@RotateLeft[DiskMatrix[32], 32]]]]
enter image description here
-
\$\begingroup\$
Image@ArrayFlatten@Array[RotateLeft[DiskMatrix@32,32]/.a_/;OddQ[+##]:>1-Thread@a&,{5,5}]\$\endgroup\$alephalpha– alephalpha2015年05月12日 05:37:13 +00:00Commented May 12, 2015 at 5:37
Mathematica (削除) 299 (削除ここまで) 256
Wordy but it was nice to figure out.
The basic tile is r (shown below),which is a region displayed by RegionPlot. A left-right reflection of the tile is made and joined with r. The two tile assembled figure is then repeated to tile the space.
r
a_~f~b_ := (x + a)^2 + (y + b)^2 <= 1;
a = ImageAssemble;
r = RegionPlot[(0~f~0 && y <= 0 && ! f[-1, 1]) \[Or] (0~f~2 &&
y >= -2 && ! f[1, 1]), {x, -1, 1}, {y, -2, 0}, Frame -> False,
BoundaryStyle -> None];
s = ImageCrop@Rasterize@r;
t = s~ImageReflect~Right;
i = a@{s, t};
j = a@{t, s};
a@{k = {i, i, i, i}, m = {j, j, j, j}, k, m, k, m}
tile
gs2, 49 bytes
50 31 05 0d 1f 2a 48 0a 1e 2e 40 83 2c e8 64 2d
1e 73 ed 1e 33 40 20 30 9a a2 22 e8 e9 40 20 30
9a 30 40 20 30 ee 40 20 30 12 32 e9 12 32 55 e8
2b
Generates a PBM image:
output
Mnemonics:
# Print header
"P1" space 256 double
2dup new-line
# Make 1/4 circle
64 range dup cartesian-product
square m1 sum sqrt 64 >= m6
64 /
# Make tile
dup reverse + transpose
@2 not m1 m2
dup reverse + transpose
+
# Make quarter of image
dup reverse + z1
dup reverse +
# Loop
2 * m2
2 *
# Format
show-words m1
unlines
Java, (削除) 550 (削除ここまで) (削除) 540 (削除ここまで) (削除) 508 (削除ここまで) 504 bytes
This is a java applet.
import java.awt.*;public class T extends java.applet.Applet{int a=98,b=49,x,y;public void paint(Graphics g){for(x=0;x<5;x++)for(y=0;y<5;y++)a(g.create(x*a,y*a,a,a),x%2^y%2);}void a(Graphics g,int c){if(c>0){g.translate(a,0);((Graphics2D)g).scale(-1,1);}g.setColor(Color.red);g.fillRect(0,0,b,b);g.fillRect(b,b,b,b);g.setColor(Color.blue);g.fillRect(b,0,b,b);g.fillRect(0,b,b,b);g.fillArc(0,-b,a,a,180,90);g.fillArc(0,b,a,a,0,90);g.setColor(Color.red);g.fillArc(-b,0,a,a,0,-90);g.fillArc(b,0,a,a,90,90);}}
Expanded with boilerplate:
import java.awt.*;
public class T extends java.applet.Applet{
int a = 98, b = 49, x, y; //Make these larger for better quality pictures. a = b * 2
public void paint(Graphics g) {
for (x=0; x < 5; x++) //Make these larger for more tiles.
for (y=0; y < 5; y++) //
a(g.create(x * a, y * a, a, a), x % 2 ^ y % 2);
}
void a(Graphics g, int c) {
if (c > 0) {
g.translate(a, 0);
((Graphics2D) g).scale(-1, 1);
}
g.setColor(Color.red); //Change colors for nicer looking colors.
g.fillRect(0, 0, b, b);
g.fillRect(b, b, b, b);
g.setColor(Color.blue);
g.fillRect(b, 0, b, b);
g.fillRect(0, b, b, b);
g.fillArc(0, -b, a, a, 180, 90);
g.fillArc(0, b, a, a, 0, 90);
g.setColor(Color.red);
g.fillArc(-b, 0, a, a, 0, -90);
g.fillArc(b, 0, a, a, 90, 90);
}
}
Applet: A small application program that can be called up for use while working in another application.
Example image:
enter image description here
Explanation:
This works by using a method to print each tile. Before the method is created, it is given a graphics object that uses a coordinate system centered on the upper left corner of each tile:
To create a tile, we use the following method:
void a(Graphics g, int c) {
g.setColor(Color.red);
g.fillRect(0, 0, b, b);
g.fillRect(b, b, b, b);
g.setColor(Color.blue);
g.fillRect(b, 0, b, b);
g.fillRect(0, b, b, b);
g.fillArc(0, -b, a, a, 180, 90);
g.fillArc(0, b, a, a, 0, 90);
g.setColor(Color.red);
g.fillArc(-b, 0, a, a, 270, 90);
g.fillArc(b, 0, a, a, 90, 90);
}
However, every other tile must be reflected horizontally in order to produce the correct image.
To reflect a tile, we simply modify the supplied graphics object with this code:
g.translate(a, 0);
((Graphics2D) g).scale(-1, 1);
Thanks @CoolGuy for 4 bytes.
-
1\$\begingroup\$ You can golf it more by declaring
xandyas fields of the class:int a = 98, b = 49,x,y;\$\endgroup\$Spikatrix– Spikatrix2015年05月10日 13:33:58 +00:00Commented May 10, 2015 at 13:33
C, (削除) 237 (削除ここまで) (削除) 209 (削除ここまで) 180 bytes
180 bytes. This version includes changes suggested by edc65 in a comment. It gives 9 compiler warnings when building on a Mac with clang and default options:
a,b,c,d,x,y;main(){for(puts("P1 256 256");b=a+32&64,a<256;++a){for(c=0;d=c+32&64,x=(a&64)-d?31-a&31:a&31,y=(c&64)-b?c&31:31-c&31,c++<256;)putchar(48+(x*x+y*y<962^b==d));puts("");}}
209 bytes, using some suggestions from comments by Martin. Compiles without warnings with clang:
#include <stdio.h>
int a,b,c,d,x,y;int main(){puts("P1 256 256");for(;b=a+32&64,a<256;++a){for(c=0;d=c+32&64,x=(a&64)-d?31-a&31:a&31,y=(c&64)-b?c&31:31-c&31,c<256;++c)putchar(48+(x*x+y*y<962^b==d));puts("");}}
Original version, 237 bytes:
#include <stdio.h>
int main(){puts("P1 256 256");for(int a=0;a<256;++a){int b=a+32&64;for(int c=0;c<256;++c){int d=c+32&64;int x=(a&64)-d?31-a&31:a&31;int y=(c&64)-b?c&31:31-c&31;putchar(48+(x*x+y*y<962^b==d));}puts("");}}
Result (256x256):
enter image description here
Original code with whitespace for better readability:
#include <stdio.h>
int main()
{
puts("P1 256 256");
for (int a = 0; a < 256; ++a)
{
int b = a + 32 & 64;
for (int c = 0; c < 256; ++c)
{
int d = c + 32 & 64;
int x = (a & 64) - d ? 31 - a & 31 : a & 31;
int y = (c & 64) - b ? c & 31 : 31 - c & 31;
putchar(48 + (x * x + y * y < 962 ^ b == d));
}
puts("");
}
}
This does not use any graphics library, the rendering is completely contained in the code.
The basic idea is to simply loop over all 256x256 pixels, and see if they are inside/outside the circular arc of the 32x32 sub-square they are in. The bottom 5 bits of the overall pixel coordinates define the relative coordinates of the pixel within the sub-square. The inside/outside test of (x, y) being inside the arc with radius r is then the standard:
x * x + y * y < r * r
Most of the logic is for placing the center of the arc in the correct corner of the sub-square, and determining which color is inside/outside.
Some comments on the solution:
- The code generates the image in the PBM ASCII format. I loaded the result into GIMP, and did a copy&paste into Paint to generate the actual file I posted here. So the format was converted, but the content is exactly as the original output.
- If you look closely, you may notice that the quality is not great. This is because the inside/outside calculation is done for the corner of the pixel, instead of the pixel center, causing the whole thing to be 1/2 pixel off. I don't think it would be very difficult to do better, but it would make the code somewhat longer. And since there were not specific quality requirements, I believe this is sufficient.
- Code was compiled using clang on a Mac. Latest version gives warnings, initial version did not.
- This is the first time I ever attempted one of these, so I probably missed a few tricks to save the last byte possible.
-
3\$\begingroup\$ Welcome to PPCG! I'm not a big C golfer, but I think I can see a few improvements: group your declarations like
int a,b,c,d,x,y;... I think you might even be able to just domain(a,b,c,d,x,y)I remember something that the default type is int. Once you're rid of that, you can move the assignments to d, x and y into the innerfor's increment statement liked=c+32&64,...,++c(probably even move the++into some other place where you mentioncanyway), and then you can omit the braces of the innerfor. Nice job, btw! :) \$\endgroup\$Martin Ender– Martin Ender2015年05月09日 23:43:08 +00:00Commented May 9, 2015 at 23:43 -
\$\begingroup\$ Thanks! I saw the trick with declaring arguments without types in a list of tips, but it seemed so dirty that I couldn't get myself to go there. ;) I don't think having non-standard arguments for
main()is standard compliant. I should certainly group the declarations. And moving the increments will save a couple of bytes, too. Theputs()for the newline is in the outer loop, so I'm not sure if I can get rid of the braces. \$\endgroup\$Reto Koradi– Reto Koradi2015年05月09日 23:56:10 +00:00Commented May 9, 2015 at 23:56 -
\$\begingroup\$ We're usually okay with it as long as it compiles in some common compiler (so it doesn't have to be entirely standard C). Also yeah I don't think you can get rid of the outer braces, but you should be able, to remove the inner ones. \$\endgroup\$Martin Ender– Martin Ender2015年05月09日 23:59:42 +00:00Commented May 9, 2015 at 23:59
-
\$\begingroup\$ Got it down to 210 bytes. Thanks for the ideas. \$\endgroup\$Reto Koradi– Reto Koradi2015年05月10日 00:36:01 +00:00Commented May 10, 2015 at 0:36
-
1\$\begingroup\$ Hints:
stdionot needed, use default declaration of function.intis default for globals and can be omitted (variables and main). Firstputscan go inside the for. c var is not used inside the inner loop, so increment in condition. 180:a,b,c,d,x,y;main(){for(puts("P1 256 256");b=a+32&64,a<256;++a){for(c=0;d=c+32&64,x=(a&64)-d?31-a&31:a&31,y=(c&64)-b?c&31:31-c&31,c++<256;)putchar(48+(x*x+y*y<962^b==d));puts("");}}(compiles with many warnings but runs) \$\endgroup\$edc65– edc652015年05月10日 01:01:12 +00:00Commented May 10, 2015 at 1:01
Explore related questions
See similar questions with these tags.