r/codegolf • • Apr 17 '23

Explanation of "Black Box of Primes"

98 Upvotes

Explanation

So, the task is to find all the prime numbers up to N.

There are multiple approaches. One of the simplest approach is using recursion: to find all prime numbers up to N, first find all prime numbers up to N-1, and if N is prime, add it to the list.

function findPrimesUpTo(n) {
    const primes = findPrimesUpTo(n-1);
    if (isPrime(n)) {
        primes.push(n);
    }
    return primes;
}

Simple, but doesn't work for 2 reasons:

  1. infinite recursion

  2. isPrime function is not defined

Let's first fix the first issue. We know, that the smallest prime number is 2, so the list of prime numbers prior to 2 is empty.

    if (n<2) {
        return [];
    }

Now let's defined isPrime. There are a lot of different approaches. The easiest one (but definitely not the optimal) is to check divisibility by every number up to N-1. I know, it's super bad idea. So we can improve it a bit: divide not by every number, but by prime numbers only. We have a list, remember?

function isPrime(n, primes) {
    return primes.all((prime) => n % prime !== 0);
}

Just don't forget to pass this extra argument.

Can we do that without fancy fashioned functional methods? Sure, we can rewrite it with old-school loop:

function isPrime(n, primes) {
    let i = 0;
    while (i < primes.length) {
        if (n % primes[i] === 0) {
            return false;
        }
        i++;
    }
    return true;
}

That looks much longer, less fancy and absolutely out-fashioned. Another cool way to do that is with recursion again. We just take this loop and convert it to recursion:

function isPrime(n, prime, i = 0) {
    if (i < primes.length) {
        if (n % primes[i] === 0) {
            return false;
        } 
        return isPrime(n, primes, i+1);
    }
    return true;
}

Now let's start a dark codegolf magic.

Trick one: we can replace if with &&.

function isPrime(n, primes, i = 0) {
    if (i < primes.length) {
        return n % primes[i] && isPrime(n, primes, i+1);
    } 
    return true;
}

Trick two: JS doesn't complain when you get out of array bounds. It just returns undefined, and as we know that all items in array are non-zero, we can replace proper condition i < primes.length with a hacky primes[i].

function isPrime(n, primes, i = 0) { 
    if (primes[i]) {
        return n % primes[i] && isPrime(n, primes, i+1);
    } 
    return true;
}

Finally, let's turn it into arrow function to get rid of all that return's. Also replace if with ternary operator.

const isPrime = (n, primes, i = 0) => 
    primes[i] ? (n % primes[i] && isPrime(n, primes, i+1)) : true;

Good old one-liner. Like the one we started with (the fancy functional, remember?), but much more cryptic and jedi-ish.

Let's put it into our initial function:

function findPrimesUpTo(n) {
    if (n<2) {
        return [];
    }
    const primes = findPrimesUpTo(n-1);

    const isPrime = (n, primes, i) => 
        primes[i] ? (n % primes[i] && isPrime(n, primes, i+1)) : true;
    
    if (isPrime(n, primes, 0)) {
        primes.push(n);
    }
    return primes;
}

As it's nested function now, we can get rid of extra arguments, it can just access it from the context.

function findPrimesUpTo(n) {
    if (n<2) {
        return [];
    }
    const primes = findPrimesUpTo(n-1);

    const isPrime = (i) => 
        primes[i] ? (n%primes[i] && isPrime(i+1)) : true;
    
    if (isPrime(0)) {
        primes.push(n);
    }
    return primes;
}

console.log(findPrimesUpTo(1000));

It works!

Now let's apply some forbidden practices, to make it shorter. Warning! Never do this in production code!

First thing to change: basically, we do primes.push only when isPrime returns true. So let's just put it there. That's absolutely not what you gonna do in production code.

function findPrimesUpTo(n) {
    if (n<2) {
        return [];
    }
    const primes = findPrimesUpTo(n-1);

    const isPrime = (i) => 
        primes[i] ? (n % primes[i] && isPrime(i+1)) : primes.push(n);
    
    isPrime(0);

    return primes;
}

Now we can get rid of push at all: if i reached the end of list, we can just save n there:

 const isPrime = (i) => 
    primes[i] ? (n % primes[i] && isPrime(i+1)) : primes[i] = n;

There are too many primes[i] here. Let's join them all together:

 const isPrime = (i) => 
    n % (primes[i] ??= n) ? isPrime(i+1) : true;

What's going on here??? ??= operator assigns new value only if previous value was undefined. So if we reached the end of array, the new value is added to the end, if not, nothing happens.

Now, if we didn't reach the end of list, we calculate n % primes[i] as usual, but if we reached, then it becomes n % n, which is always zero, and we skip recursion and return true.

Beautiful? Yeah!

Whole picture now:

function findPrimesUpTo(n) {
    if (n<2) {
        return [];
    }
    const primes = findPrimesUpTo(n-1);

    const isPrime = (i) => 
        n % (primes[i] ??= n) ? isPrime(i+1) : true;
    
    isPrime(0);

    return primes;
}

console.log(findPrimesUpTo(1000));

It still works!

Next stupid jedi thing we do, is to join last two lines: isPrime(0); and return primes;. Now isPrime function returns array instead of boolean, but who cares?

function findPrimesUpTo(n) {
    if (n<2) {
        return [];
    }
    const primes = findPrimesUpTo(n-1);

    const isPrime = (i) => 
        n % (primes[i] ??= n) ? isPrime(i+1) : primes;
    
    return isPrime(0);
}

console.log(findPrimesUpTo(1000));

Now let's make primes a global variable. Just because that's what you must never do in real life.

const primes = [];

function findPrimesUpTo(n) {
    if (n>2) {
        findPrimesUpTo(n-1);
    }

    const isPrime = (i) => 
        n % (primes[i] ??= n) ? isPrime(i+1) : primes;
    
    return isPrime(0);
}

console.log(findPrimesUpTo(1000));

Now we do 3 tricks:

  1. replace if with && again.

  2. call isPrime function right after declaration.

  3. turn findPrimesUpTo into arrow function.

const primes = [];

const findPrimesUpTo = (n) => (
    n>2 && findPrimesUpTo(n-1),

    (isPrime = (i) => 
        n % (primes[i] ??= n) ? isPrime(i+1) : primes)(0)
)

console.log(findPrimesUpTo(1000));

Now, let's get rid of numbers. Why? Because why not. n-1 can be replaced with ~-n i+1 can be replaced with -~i

n>2 is trickier, but basically it's like n-2>0, which is almost the same as n-2, and that can be replaced with ~-~-n.

const primes = [];

const findPrimesUpTo = (n) => (
    ~-~-n && findPrimesUpTo(~-n),

    (isPrime = (i) => 
        n % (primes[i] ??= n) ? isPrime(-~i) : primes)(0)
)

console.log(findPrimesUpTo(1000));

How to hide 1000?

Thanks to JavaScript advanced math '' + 1 + 0 + 0 + 0 == "1000"

And did you know that -[] in JS equals to zero?

And -~[] equals to 1.

And if we add [] to a number, it will be converted to empty line ''.

So, to get it together: 1000 can be replaced with [] + -~[] + -[] + -[] + -[].

Actually, it will be a string "1000", not a number, but thanks to our bitwise operations, it will be automatically converted to a number during computations.

console.log(...findPrimesUpTo([]+-~[]+-[]+-[]+-[]));

There's still a zero left when we call isPrime.

You know what? Instead of disguising it, let's just remove it! undefined is almost the same stuff as zero. Though, not exactly the same, so we need to add some bitwise converter: ~~.

const primes = [];

const findPrimesUpTo = (n) => (
    ~-~-n && findPrimesUpTo(~-n),

    (isPrime = (i) => 
        n % (primes[~~i] ??= n) ? isPrime(-~i) : primes)()
)

console.log(...findPrimesUpTo([]+-~[]+-[]+-[]+-[]));

No more silly numbers. Now let's get of letters.

Rename n to $.

Rename primes to _.

Rename findPrimesUpTo to $$.

Rname isPrime to _$.

Rname i to $_.

And const - let's just get rid of them.

_ = [];

$$ = ($) => (
    ~-~-$ && $$(~-$),

    (_$ = ($_) => 
        $ % (_[~~$_] ??= $) ? _$(-~$_) : _)()
)

console.log(...$$([]+-~[]+-[]+-[]+-[]));

This pretty obfuscated code still works nice.

Now some optimization: you see, that we use a lot of []'s?

And totally accidentally our _ variable is initialized to []. So...

$$ = ($) => (
    ~-~-$ && $$(~-$),

    (_$ = ($_) => 
        $ % (_[~~$_] ??= $) ? _$(-~$_) : _)()
)

console.log(...$$((_ = [])+-~_+-_+-_+-_));

Now let's call $$ right after initialization:

console.log(...($$ = ($) => (
    ~-~-$ && $$(~-$),
    (_$ = ($_) => $ % (_[~~$_] ??= $) ? _$(-~$_) : _)()
))((_ = [])+-~_+-_+-_+-_));

And get rid of all that spaces and some brackets:

console.log(...($$=$=>(~-~-$&&$$(~-$),(_$=$_=>$%(_[~~$_]??=$)?_$(-~$_):_)()))((_=[])+-~_+-_+-_+-_))

Here we go!

Wait, what about console.log,

In interactive environment (like browser console), you can just run the code without console.log and still get output.

For non-interactive environment... Well... Actually, it is possible to get rid of it, but it will make code way bigger and require a lot of effort, so let's just keep it.


r/codegolf • • Dec 10 '21

brainfuck to c in python

52 Upvotes

b,a=lambda t:'main(){char m[30000]={0},*p=m;%s}'%''.join([a[x]for x in t if x in a]),{'+':'++*p;','-':'--*p;','>':'++p;','<':'--p;','[':'while(*p){',']':'}',',':'*p=getchar();','.':'putchar(*p);'}

a one line function that converts brainfuck code to c


r/codegolf • • Dec 31 '25

Tic-Tac-Toe in Python using only 161 bytes of code

46 Upvotes

So as the title says, I implemented Tic-Tac-Toe or Noughts and Crosses in Python as short as I could make it over the span of a few days. I'm at a point where I can't find any further improvements but I'd be happy to hear if anyone else can find something I was unable to!

Python Code (161 bytes):

b=p='_|_|_\n'*3
while'_'in b*all(3*p!=b[v>>4::v&15][:3]for v in[2,6,8,38,68,70,98,194]):
 i=2*int(input(b))
 if b[i]>'X':p='XO'[p>'O'];b=b[:i]+p+b[i+1:]
print(b)

Edit: Improvements made with feedback (151 bytes)

b=p='_|_|_\n'*3
while'_'in b*all(3*p!=b[v&15::v>>4][:3]for v in b' `\x80bDd&,'):
 if b[i:=2*int(input(b))]>'X':p='XO'[p>'O'];b=b[:i]+p+b[i+1:]
print(b)

I flipped the upper and lower bits of each value in [2,6,8,38,68,70,98,194] and converted into the b-string: b' \\x80bDd&,'` , as well as utilizing the walrus operator (:=) to save a line break and a space (thanks to u/3RR0R400 for the ideas)

Example run:

_|_|_
_|_|_
_|_|_
4
_|_|_
_|O|_
_|_|_
5
_|_|_
_|O|X
_|_|_
2
_|_|O
_|O|X
_|_|_
6
_|_|O
_|O|X
X|_|_
0
O|_|O
_|O|X
X|_|_
1
O|X|O
_|O|X
X|_|_
8
O|X|O
_|O|X
X|_|O

Below is a simple explanation of what it does for anyone interested:

b: Board
p: Current Player Marker

b=p='_|_|_\n'*3 Initialize the board such that printing results in a 3x3 grid, as well as having each "cell" at an even index pattern (2* Cell index). Furthermore, I save bytes by chained assignment of p, since p is updated before it's used.

while'_'in b*all(3*p!=b[v>>4::v&15][:3]for v in[2,6,8,38,68,70,98,194]): This line has had the most effort put into it. It consists of two parts, draw detection ('_'in b), and a general win detection, combined in a way to make use of string repetition to avoid an and.

all(3*p!=b[v>>4::v&15][:3]for v in[2,6,8,38,68,70,98,194]) After each move the only winning pattern has to include the last players marker (except for the first iteration where 3*p=3*b can never equal a slice of b, thus entering the loop). Then test the string 'XXX' or 'OOO' against a slice of three characters from the board where each win pattern is stored in a single number, each having a starting position and a stride length stored in the upper and lower 4 bits of v respectively. (I did find this that reduces the codes character length, but increased the number of bytes: b[ord(v)&15::ord(v)>>7][:3]for v in'Ā̀Ѐ̂Ȅ̄ĆČ' due to the use of 'Ā̀Ѐ̂Ȅ̄ĆČ' where each character is more than one byte)

i=2*int(input(b)) I make use of the fact that input(prompt) prints the prompt (in this case b) to display the board before a move, then read an input and store in i, ready for indexing.

if b[i]>'X':p='XO'[p>'O'];b=b[:i]+p+b[i+1:] Here I update player and board if the input is valid, making use of b[i]>'X' being the same as b[i]=='_' for all valid b[i] in this context, to save one byte. Player switching uses a similar fact as well as indexing into 'XO' using a bool (This also sets the first player to O when p=b*3*)*. And finally updating the board is a simple slicing of b and adding of p since p is a string.

print(b) This line just prints the board a last time after a win or a draw (Here I did find using exit(b) or quit(b) to save one byte, but I didn't feel like it counted).

Since I know what constitutes "Tic-Tac-Toe" is a little arbitrary, I tried to define and follow a few self-imposed rules:

  • Display the board before each move in a 3x3 grid

  • Only allow placement of marker on empty cell, otherwise don't switch player

  • End the game and display the final board on a win or draw

Other rules that some might consider, which I didn't for this project

  • Also display the current player before each move

    • Pretty intuitive that the player switches after each turn (only caveat is when someone makes an invalid move)

  • Print out the result on a win or draw (Like "X won" or "Draw")

    • I didn't like the trade-off between an informative result representation and number of bytes (for example "X" vs "Player X won"), and I'd say it's pretty intuitive to figure out who won when the game ends.


r/codegolf • • Jun 25 '18

[Python 3][ALL][meme] This subreddit is pretty inactive, what a LOSS.

46 Upvotes
for y in range(7):print(*(' #'[0**(x%8*(x-y//4*3)%11*(y^6+(x<11)))]for x in range(14*(y!=3))))

94 characters (88 without whitespace)

for r in[261]*3+[0,324,324,1303]:print(*(' #'[c=='1']for c in bin(r)))

70 characters (65 without whitespace)


r/codegolf • • Feb 17 '20

Mandelbrot renderer (C, 354 characters, including image output)

Post image
30 Upvotes

r/codegolf • • Mar 06 '21

The Kilobyte’s Gambit ♟️💾 1k chess game

Thumbnail
vole.wtf
28 Upvotes

r/codegolf • • Aug 30 '26

minimal size .png file

25 Upvotes

Hey everyone!

For the past few days, I’ve been obsessed with a single question: How small can a valid PNG file possibly get while still being natively readable by a PC (specifically, opening properly in the standard Windows photo viewer/gallery)?

I started by trying to make a lightweight 512x512 file, eventually managing to shrink it down to 111 bytes. After that, I started playing around with compression levels and various patterns, even managing to generate some basic procedural textures in PNG format that weighed roughly the same.

Then I decided to go deeper and chase the absolute minimum file size. At first, I hit a wall at 67 bytes—an article I read online claimed that was the lowest possible size for a functional PNG. But I kept experimenting and eventually pushed past it down to 55 bytes, and finally all the way to 42 bytes.

My current record is a fully working 42-byte PNG. It opens without issues on Windows and can be sent across messaging apps where it renders properly as an image.

However, I've hit a hard brick wall here. Every single attempt to strip away even one more byte results in an invalid file or completely breaks the structure.

My question is: Does anyone have any radical ideas, unconventional compression tricks, or deep spec-hacking methods to squeeze it down even further? I'm open to any crazy suggestions!


r/codegolf • • Jan 18 '23

Let’s do this guys!

Post image
23 Upvotes

r/codegolf • • Dec 10 '20

Code.golf - ranked ever running contest with 27 langs, 50 holes and growing!

Thumbnail
code.golf
20 Upvotes

r/codegolf • • Oct 15 '20

Fibonacci numbers in 44 bytes of Ruby.

20 Upvotes

a=b=1;ARGV[0].to_i.times{p a;c=a+b;a=b;b=c}

EDIT: saved a byte with negative indexing

ARGV[-a=b=1].to_i.times{p a;c=a+b;a=b;b=c}

EDIT 2: saved 2 more by abusing assignment chaining more

ARGV[-a=b=1].to_i.times{p a;c=a+a=b;b=c}

EDIT 3: down to 39! ARGV[-a=b=1].to_i.times{p a;b=c=a+a=b}


r/codegolf • • Aug 14 '20

Mandelbrot set in 170 bytes of Python, my first major attempt at codegolfing

20 Upvotes

I haven't been in the coding space for as long as some others have, and I'm only really familiar and comfortable with python. As such I don't know too much about functions or operators that are especially useful in code golfing, and did the best I can with what I already know :

c,d,h=0,0,''
while d!=51:
	l=0;c+=1
	for b in range(9):
		l=l*l-3+.04*c-2j+.08j*d
		if abs(l)>2:h+=' ';break
		if b==8:h+='*'
	if len(h)==99:d+=1;print(h);h,c='',0

Let me know if this is a good first attempt and if there's anything that I might be able to do to reduce the size even further.

Edit : I forgot to mention that this is Python 3


r/codegolf • • Nov 30 '20

Flappy Bird in 228 bytes

Thumbnail
gist.github.com
19 Upvotes

r/codegolf • • Jun 09 '20

150+ mobile-friendly "coding challenges" (algos, data struct, etc.) in a game-like app, with user rankings/leaderboard. Let's improve, compete, and have fun?

19 Upvotes

Hello fellow golfers,

My friend Ed and I figured something. There's currently no way to practice coding challenges when we're away from our computers. Also, some exercises take 30 minutes, and we don't always have that much time available. So he and I have been building this app on our spare time. We call it SolveFaction.

We've put together a "beta" version. And we wanted to share it with you. All exercise questions are original. We've built them ourselves. And there's enough of them for you to play for a couple of weeks.

Sign up for the waitlist: https://solvefaction.com
Go straight to playing: https://play.solvefaction.com/signup

Cheers,
Gunar

---


r/codegolf • • Nov 07 '21

Imagine the following - a spoken language golf!

18 Upvotes

You would be given a prompt of a chunk of text and your goal would be to come up with as short a grammatically correct chunk of text you can think of, sharing the meaning of the original one. Staying within the prompt's original language is not required. Differential writing systems (alphabetical vs. scriptial, for example) would be scored differently and independently, such that there's still a point in participating if you're not fluent in a script based language).

Your first task? This very ruleset here. good luck!


r/codegolf • • Apr 30 '20

"Game of Life" in 32 bytes of assembler (source included)

Thumbnail
pouet.net
18 Upvotes

r/codegolf • • Oct 05 '18

13 games in ≤ 13kB of JavaScript · js13kGames 2018 highlights

Thumbnail
blog.github.com
17 Upvotes

r/codegolf • • Dec 31 '23

Happy New Year! Quine edition. HTML page: 227 bytes. Code in comment.

16 Upvotes

r/codegolf • • Oct 06 '21

Code Golf for LC Hard - Word Break II

Post image
16 Upvotes

r/codegolf • • Oct 16 '20

BrainF*** interpreter in 248 bytes of Ruby

16 Upvotes

t={};s=ARGV[t.default=p=w=0];m={"+"=>"z+=1","-"=>"z-=1","."=>"puts z.chr",","=>"z=STDIN.getc.ord","<"=>"p-=1",">"=>"p+=1","]"=>"z==0||w-=Z'['","["=>"z==0&&w+=Z']'"};until w==s.length;eval m[s[w]].gsub(/Z/,"1until s[w]==").gsub(/z/,"t[p]");w+=1;end

Unfortunatly dosn't do nested brackets (I have enough trouble doing that normally).


r/codegolf • • Oct 03 '18

I made a 34-byte implementation of Conway's Game of Life in the J programming language

Thumbnail self.cellular_automata
16 Upvotes

r/codegolf • • Aug 20 '22

[Python] Worley Noise generator in 236 bytes

15 Upvotes
import random as R,PIL.Image as I
a=R.randrange
r=range
s=250
p=tuple((a(0,s),a(0,s))for _ in r(25))
i=I.new('L',(s,s))
i.putdata([255-min((d:=x-t[0],e:=y-t[1],d*d+e*e)[-1]for t in p)//28 for y in r(s)for x in r(s)])
i.save('w.png')

Edit: now it's 232 bytes


r/codegolf • • Jan 15 '20

Fortified C[a]stle in 140 Characters of JavaScript

15 Upvotes

r/codegolf • • Jun 27 '18

D&D Attribute + Modifier Generator

15 Upvotes

So I was talking with my friend, and she mentioned how she wrote a basic python script to roll her D&D character attributes for her. Upon looking at it, I said the words "It could be shorter" and so this began.

What started as a well spaced 40ish line Python 3 script designed to simulate the dice rolls of creating a D&D character (4d6 rolls, minus smallest, 6 times) became what I have pasted right here. We based our little competition on number of lines (instead of bytes) and banned 'exec()' calls (bc that's no fun). We ended with what we have here.

If anyone can shorten it to one line I encourage you to do so. Also, anyone who can figure out how to close the file without adding a line will definitely help ease my pain of leaving "/dev/urandom" open.

abl_scores = [sum(sorted([(int.from_bytes(open("/dev/urandom", 'rb').read(10), 'big') >> 70) % 5 + 1 for j in range(4)])[1:]) for i in range(6)] if input("Choose standard scores? (y/n): ") != 'y' else [15,14,13,12,10,8]
print("Attribute: " + str(abl_scores).strip("[").strip("]") + "\n Modifier: " + str([{3:-4, 4:-3, 5:-3, 6:-2, 7:-2, 8:-1, 9:-1, 10:0, 11:0, 12:1, 13:1, 14:2, 15:2, 16:3, 17:3, 18:4}[score] for score in abl_scores]).strip("[").strip("]"))

r/codegolf • • Sep 17 '21

Code Golf For The Notorious DP Problem “Coin Change”.

Thumbnail
gallery
14 Upvotes