Challenge: Maximum Pixel-art, Minimum Code

Ah, those abominations.

Got to be honest, I forgot those digraphs existed. Fair enough.
(Not the trigraphs though, I remembered those being deprecated.)

Though surely now you’re just trying to obfuscate things?
The alternative operators use more characters than the ‘proper’ ones.

1 Like

Yeah, there wasn’t much point in trying to codegolf that one so I figured I’d throw in the <::> as a little prank.

1 Like

Then consider me pranked.


No time to make an animation, but here’s a really simple single-pixel chequerboard:

for(size_t index = 0; index < 1024; ++index)
	arduboy.sBuffer[index] = ((index % 2) == 0) ? 0xAA : 0x55;

(Full code in this gist.)

Hideous, badly-written golfed form for character-counting loons:

for(int i=0;i<1024;++i)b[i]=i&1?0x55:0xAA;
1 Like

You can further golf the expression into: 170>>(i&1)

and one more with


Oh even better:


That actually produces the opposite sequence.
My original sequence was 0xAA, 0x55, 0xAA, 0x55, ...,
this produces 0x55, 0xFFAA, 0x55, 0xFFAA, ....

To produce the right sequence you’d need to use either -i%2^170 or ~i%2^85.

~i%2 produces the opposite of -i%2 because -x == (~x + 1).

1 Like

@sparr - I struggled to get the code to run for some reason- but glad I persisted! This is wonderful stuff! I like watching it slowly develop with a.setFrameRate = 1;. It’s great you provided such readable code- really helped. I golfed your code a little, to get it down to 361(!) characters. Perhaps a collaboration with @Mr.Blinky and @FManga could get that lower?..


Thanks again for sharing this!

PS - Welcome to the forum ~ what a great first post! :partying_face:

I think we’ve reached peak ‘Checkers’! :checkered_flag:

It’s interesting that while @Mr.Blinky’s 7 characters (-i%2^85) is 3 characters smaller than @Pharap’s original (i&1?85:170), the compiled code is 102 bytes more! (14 → 116 bytes). I presume this is the use of modulus function?..

Of course, it highlights the issue of golfing a compiled languages, rather than interpreted languages :slight_smile:

Further inspiration:

  • Hitomezashi Stitch Patterns.
  • Images ‘hidden’ in the digits of pi.
  • Drawing larger images- rather than repeating patterns. E.g. a screen-filling shape like a star or circle would be fun.
  • Pokemon-style screen wipes could be useful.

Thank you everyone for such great entries.

A classic woven pattern- ‘Houndstooth’.


I’m collating nice 8x8px fill patterns at :slight_smile:

1 Like

Weekend Golf anyone ?

I’ve realised I can compact this diagonal, 2px line pattern from:


to a more mathematical:


Is it possible to shave off a couple more characters? :thinking:
(Must produce bit identical pattern).

I can’t beat it offhand, but I can match it:

1 Like

Nice stuff! :star_struck:
I’ve not considered using | in these statements… also I don’t think I ever explored multiple expressions (perhaps it feels like cheating!?.. :sweat_smile: ). I’m also waiting to find a good use for the ‘space-ship’ operator <=>

1 Like

I’m using that because after inspecting the binary encoding of 129 I noticed that you’re basically attempting to left-rotate 3 and offset the pattern.

x << n | x >> (c - n) is the idiom for a left-rotate, where:

  • x is the value to be rotated
  • n is the number of bits to rotate by
  • c is the target bit width

Effectively it shifts the bits left by n and right by the ‘inverse’ of n and combines the result, thus mimmicking a rotate once the outlier bits are discarded. Normally you’d need an & to mask off the excess, but in this case the implicit cast to uin8_t has the same effect.

The comma operator is 100% legal C++, even if it’s pretty much only ever useful for operator overloading and nasty tricks like this.

The += and %= trick would work without the comma operator, but you need at least one comma to ensure that the modification is sequenced before the rotate, otherwise you’ll fall foul of the fact the evaluation order of binary operator operands is unsequenced. (I.e. the compiler is allowed to evaluate them in whichever order it wants.)

Unfortunately that won’t work on Arduboy because it’s a C++20 feature.

1 Like

Ah! So it allows shifting with wrapping around those ‘lost bits’ ? i.e. it can be used for thicker line patterns.

No!!! I thought that was gonna be neat! :scream:

Update: @Pharap your code doesn’t seem to work for me…? Just a blank screen…

Full code ~
#include <Arduboy2.h>
Arduboy2  a;
uint8_t  *b = a.sBuffer;
uint16_t &c = a.frameCount;

void setup() {

void loop() {
  if (!a.nextFrame())

  for (int16_t i = 0; i < 1024; i++) {
    a.sBuffer[i] = i+=3,i%=8,3<<i|3>>8-i;

Building off of @Pharap’s answer… bake the +3 shift into the shifted constant 3:


Wow! Down to 17 characters! That’s amazing! :exploding_head:
– I will need to try with other patterns now…

Update: Yes! It’s simple to change the constant 2428 to change the line width. (A nice feature of macOS’s calculator in ‘Programmer’ view, is being able to click on binary digits and quickly get a value). Thanks so much @Pharap & @brow1067 !

Needless to say, I always test my noodling in Ardens (the coloured pixel grid is vital!).
… But I do miss the old emulator with built in compiler, to quickly iterate on these little challenges…


It’s not a perfect solution, but the desktop builds of Ardens watch the hex file and automatically reload and restart the sim when the file is modified. So you can iterate and build while watching Ardens in the background.


I’m not sure what you mean by ‘lost bits’.


  • 0b0000_0011 rol 70b1000_0001
  • 0b0000_0011 << 70b1000_0000
  • 0b0000_0011 >> (8 - 7)0b0000_0001
  • 0b0000_0011 << 7 | 0b0000_0011 >> (8 - 7)0b1000_0001

So you’re using the left shift to move the bits leftwards, discarding what would have been wrapped around, and then the right shift generates the part of the pattern that would have resulted from the wraparound.

Do it manually a few times and you’ll see what’s happening.

Ah, sorry, I forgot you were doing it inline rather than implementing the expression as a function.

I was depending on the assumption that i would be a fresh variable each time as if by:

uint8_t f(uint16_t i)
	return i+=3,i%=8,3<<i|3>>8-i;

I had been testing with:

std::uint8_t get_a(std::uint16_t i)
	return 72 ^ "Px(\210\311KND"[i % 8];

std::uint8_t get_b(std::uint16_t i)
	return i += 3, i %= 8, 3 << i | 3 >> 8 - i;

bool test()
	for(std::uint16_t index = 0; index < 1024; ++index)
		if(get_a(index) != get_b(index))
			return false;

	return true;

When i is persistant as it is in a for loop, that means you can’t just modify it as I did there because it’ll break the loop condition early and skip steps.

It’s times like this I wish C++ had an equivalent of let x = y in e, like most functional/lambda-calculus-derived languages do, then I could have just declared a variable for the duration of the expression.

let j=(i+3)%8in3<<j|3>>8-j

Though to be fair, that would have ended up being longer anyway.

Here’s what I do in Microsoft land:


1 Like

Fair comment :laughing: … of course I should have said the bits that overflow on shifting. Your example demonstrates nicely this function; thanks!

This shows my complete, blind faith in you!.. Happily copy&pasting anything you post :crazy_face: … which also answers the question, “If @Pharap jumped off to an undefined address… would you ?!” …

Nice! I assumed this was a standard… I just never tried clicking those binary digits until last year. Also loving your ‘Vapourwave’ magenta theme! :wink:

1 Like