# Random Pixels Image Compression

## Challenge:

Given an integer $$\n\$$, guaranteed to be $$\\geq2\$$ and a power of 2, we are going to draw multiply boards either side-by-side or below one another, where the first has dimensions of $$\n\$$ by $$\n\$$; the second $$\\frac{n}{2}\$$ by $$\\frac{n}{2}\$$; the third $$\\frac{n}{4}\$$ by $$\\frac{n}{4}\$$; etc.; until the final $$\1\$$ by $$\1\$$ pixel.

The first $$\n\$$ by $$\n\$$ board will have its pixels uniformly randomly generated with black (rgb(0,0,0)/#000000) and white (rgb(255,255,255)/#FFFFFF) pixels. The next $$\\frac{n}{2}\$$ by $$\\frac{n}{2}\$$ compressed image will have each 2x2 block of pixels reduced to the color with the most pixels in that block (thus if a 2x2 block has four or three pixels of the same color, it becomes that color; and if both colors have two pixels each, we again choose one uniformly randomly).

It must be clear how the boards of each iteration are separated.

## Challenge rules:

• Output is flexible, but must be a . So it can be drawn and shown in a frame/canvas; output to an image-file on disk; drawn in a graph; generated as black/white Minecraft Wool blocks; generated as colored MS Excel cells; etc.
• As mentioned, it should be clear how the boards of each iteration are separated. This can for example be done by using a non-white and non-black color: setting a background of your canvas with a single pixel delimiter between boards or surrounding each board with a border. Alternatively you can output each board separately, in its own image-file or own canvas tab/window perhaps.
• The iterations can be drawn both horizontally or vertically, and alignment is irrelevant (e.g. vertical output with right aligned blocks is fine).
• The size of the individual blocks doesn't necessarily have to be a single pixel, as long as they are all the same size and squares.

Example:

Input: $$\8\$$
Potential output - horizontal; bottom-aligned; red background as separator: Same example output, but vertical, right-aligned, with a blue border as separator instead: ## General rules:

• This is , so the shortest answer in bytes wins.
Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
• Standard rules apply for your answer with default input rules and graphical output rules.
• Default Loopholes are forbidden.
• Since the boards all have different sizes, can't we just output them all next to each other? May 13, 2022 at 9:34
• @emanresuA I added the rule about the border/background since it's not very clear where a white pixel of the output and white pixel of the default background would differ. E.g. let's say the input is 8, and the four top row pixels of the reduces 4x4 image are all white pixels on a white background, you can't really see it it's a 4x4 or 3x4 'image'. I know what you're trying to say: we know they're squares and powers of 2, but the rule about the separation makes that distinction of where the $n$ by $n$ squares are visually clearer imo. May 13, 2022 at 9:38
• I'll offer a 500 bounty if anyone posts a Minecraft answer with gif and Redstone explanation. ;) May 13, 2022 at 9:49
• @Jonah You're right that the random pixels and compression parts could be replaced by random bits in an ASCII-art challenge, but if I allow ASCII-art, everyone would use it since it's easier and shorter, defeating the whole purpose of the [graphical-output] challenge.. There are a lot of [ascii-art] challenges that can be done with [graphical-output], and vice-versa, but I personally see them as two different things. May 16, 2022 at 6:33
• Fair enough. I suppose my feeling is "if it can be ascii-art, it should," so you'd require graphical output for stuff like "draw the ukrainian flag" or "draw the archimidean spiral", etc. But I admit that's just personal preference. May 16, 2022 at 11:45

## JavaScript (browser), 334 bytes

f=
n=>[...n.toString(2)].map((_,i)=>(c=document.createElementcanvas,c.height=c.width=s=n>>i,c.getContext2d.putImageData(new ImageData(new Uint8ClampedArray(Int32Array.from([].concat(...a=[...Array(s)].map((_,x,t)=>t.map((_,y)=>Math.random()<(i?a[x][y+=y]+a[x+1][y]+a[x][++y]+a[x+1][y]-1.5:.5),x+=x))),b=>-1<<b*24).buffer),s),0,0),c))
;g=n=>{m.value=0;m.max=n;a=f(1<<n);h(0);};h=n=>o.replaceChildren(a[n]);g(8)
canvas{width:256px;height:256px;image-rendering:pixelated;}
log<sub>2</sub>n: <input id=n type=number size=1 min=0 max=8 value=8><input type=button value=Go! onclick=g(+n.value)><input id=m type=number size=1 min=0 max=8 value=0 oninput=h(+this.value)><div id=o>

Viewer takes input of log₂n. To use the viewer, choose n, click Go!, then use the second input to select which of the output canvases to insert into the DOM. Because the CSS is fixed at 256 pixels, this limits the inputs to 8; the browser's actual limit is 15.

# C (GCC), 296 bytes

#define f(I,J,d)for(i=0;i<I;i+=d)for(j=0;j<J;j+=d)
main(N,n,i,j,c){scanf("%d",&N);char m[N][N];f(N,N,1)m[i][j]=rand()&2;printf("P5 %d %d 2 ",N,N*2+(int)log(N));for(n=N;n;n/=2){f(n+1,N,1)putchar(j<n&i<n?m[i][j]:1);f(n,n,2)m[i/2][j/2]=(c=m[i][j]+m[i+1][j]+m[i][j+1]+m[i+1][j+1])-4?c/5*2:rand()&2;}}

Attempt This Online!

Outpus a PGM image.

Since PGM stands for "Portable Gray Map", the output is a grayscale image. The 2 in printf("P5 %d %d 2 " is the maximum gray value, hence there are three possible colors: 0 (black), 1 (50% gray), and 2 (white).

Whit the instruction m[i][j]=rand()&2;, each element of the matrix is assigned a random value (with $$\p(X=0)=0.5\$$ and $$\p(X=2)=0.5\$$), hence the pixels are uniformly randomly generated with black and white pixels.

In the compression phase, the (c=m[i][j]+m[i+1][j]+m[i][j+1]+m[i+1][j+1])-4? expression is false if two of the four pixels have value 2 (that is, they are white, and the other two are black).

The value 1 is used only for the background pixels.

• Is there any way to convert a PGM image to something visual? If yes, could you post a screenshot of an example output? If not, could you at least post an explanation? Without explanation I'm just guessing here, but is the (c=m[i][j]+m[i+1][j]+m[i][j+1]+m[i+1][j+1])-4? correct? Shouldn't the -4 be -2, as in: if there are 0, 1, 3, or 4 black pixels in this 2x2 block, do c/5*2 to convert it to the correct black/white compressed pixel; if there are 2 black pixels instead, pick a random (rand()&2) black or white pixel. May 14, 2022 at 10:13
• You can open a PGM image with many common image viewers. On my system, I can open such images with Eye of Gnome, imagemagick, and GIMP. Regarding how it works, I'll add some details. May 14, 2022 at 21:51
• 290 bytes May 17, 2022 at 15:46

# J, 91 bytes

load'viewmat'
[:viewmat[:,.~/[:>:&>(,:~2 2)0:(?@2)1:@.(1+_2*@++/@,);._3&.:>^:a:[:<,~?@\$2:


Try it online!

Output from the above is show below, since TIO won't produce images.

However, here is a TIO link that outputs the raw matrix data, which is where all the logic is. The image is produced simply by calling viewmat on that.

f 16: # Wolfram Language (Mathematica), 93 bytes

Image/@NestList[BlockMap[Boole[#~Total~2+r[]>2]&,#,{2,2}]&,r=RandomInteger;1~r~{#,#},Log2@#]&


Try it online!

This is a function that takes an input n and returns a list of images. TIO can't display the images, but both the Notebook interface and @wolframtap supports graphical output. # Yabasic, 196 bytes

Program that takes input $$\n\$$ from STDIN and outputs to a 'grafic' window.

Input n
Open Window 5*n,3*n
Color 0,0,99
Fill Circle 0,0,6*n
While n>.5
For x=1To n
For y=1To n
Color 0,0,0
If ran(2)>1Color 255,255,255
Box 2*x+o-1,2*y-1,2*x+o,2*y
Next
Next
o=o+2*n+2
n=n/2
Wend


### Commented

Input n                       rem   take input
Open Window 5*n,3*n           rem   open a graphics window
Color 0,0,99                  rem   set brush color to blue
Fill Circle 0,0,9*n           rem   fill background
While n>.5                    rem   iter across subimages
For x=1To n                   rem   iter across subimage's x
For y=1To n                   rem   iter across subimage's y
Color 0,0,0                   rem   set brush color to black
If ran(2)>1Color 255,255,255  rem   50% to set brush color to white
rem   draw a rectangle for the current cell
rem     of the subimage. Uses the 1px
Box 2*x+o-1,2*y-1,2*x+o,2*y   rem     border to draw each 2px X 2px cell
Next                          rem   loop
Next                          rem   loop
o=o+2*n+2                     rem   update offset for next subimage
n=n/2                         rem   decrement n by base 2 order of magnitude
Wend                          rem   loop


# Example Output ($$\n=256\$$) 