A demake of one of my favorite solitaire variants: Free Cell

Made in just 1022 characters of code, with no pre-drawn sprites!


  • click and drag cards around
    • you cannot move stacks of cards; one at a time only!
  • stack descending cards of alternating colors in the main play area
    • any card may be placed in an empty column of the main area
  • store any card in the four "free cells" at the top left
  • make a stack of each suit A->K in the top right to win
  • cmd-r to start a new game

The web version drops your cards if you accidentally move your mouse outside the game window; this behavior is less annoying in the downloaded versions.


You can only move one card at a time; if you want to move a stack of cards you have to take it apart and put it back together manually. This is different from "standard" solitaire, and it makes Free Cell particularly interesting! It also makes the implementation a bit easier to fit into the tiny code-size constraint ;)

> I WON!

Congrats! Enjoy the win animation here: https://pancelor.itch.io/solitaire-win-animation (I wanted to add a "you win" animation to this game, but I didn't have the room to fit it in... so I made it as a separate cartridge)


Some of the more bizarre tricks I used to squeeze every bit of functionality out of my 1024-character budget:

  • set the palette with poke2(-15-šŸ˜,264,2043,4,3843)!
  • update card positions with for _ENV in all(S)do x=u+3*x+.5>>2y=v+3*y+.5>>2end!
  • dynamically cast shadows with a very particular palette and poke2(63-šŸ˜,244)rectfill(x-1,y-1,x+W,y+Z,4)poke2(61-šŸ˜,-1,-1)!
  • draw the 4 suit icons with split("ā™„,ā—†,ā—†āµ8f..Ā³aį¶œ3.,ā—†āµ8f惋")[suit_id]!
  • check if you can drop your held card with i\12+G+#S<1or 16-i\8|k+G==16|1+H.k^^32or H.k==i\12+k|G!
  • wait until the next frame and clear the screen with ?"ā¶1ā¶c6"! (thanks to zep for pointing this out)
  • auto-move cards to the top right by tracking the minimum stack height with bitshifting! (search for M (and m) to see the relevant code)
  • check whether the game is won by taking advantage of the fact that 2^12<ā§— and ā§—<2^13!

> I'M SORRY, "poke2(63-šŸ˜,244)"???

Yeah! 63-šŸ˜ is 24414.5, which is the address I need to poke to get those slick shadows! Check out this post for more info.


Here's the full code; remember to enable puny text mode (cmd-p) before pasting this into your local PICO-8 console!

function F(i)S=s[i]J=i\W I=i\8O=1-I U=I*(i-8+J)*14+O*i*Z+2V=O*max(#S*6+22,28)+5end
for i=0,51do s[i]={m=i\W}A(B,{x=i,y=400,k=i+i\w*3},rnd(i+1)+1)end
q(-15-šŸ˜,264,2043,4,3843)D=rectfill::_::L=T%8T+=1K=B[T]N=not btn(5)X=stat(32)-6Y=stat(33)-8C=fillp
for i=15,0,-1do
C(ā–’)a=5+O*28D(U,a,U+W,a+Z,2)C()for _ENV in all(S)do x=u+3*x+.5>>2y=v+3*y+.5>>2end
if(H and N and(J+G+#S<1or Z-I|k+G==Z|1+H.k^^32or H.k==J+k|G))K=H L=i
for r in all(B)do
q(63-šŸ˜,244)D(x-1,y-1,x+W,y+Z,4)q(61-šŸ˜,-1,-1)D(x,y,x+W,y+Z,3)a=r.k%Z+1?(a==10and"Ā³f|Ā³f0 Ā³b"or sub("a23456789|jqk",a,a).." Ā³d")..split("ā™„,ā—†,ā—†āµ8f..Ā³aį¶œ3.,ā—†āµ8f惋")[r.k\Z+1],x+1,y+1,r.k\32
for i=0,77do
goto _

An earlier, more readable, and much longer version of this code can be found here

PlatformsWindows, macOS, Linux, HTML5
Rated 4.4 out of 5 stars
(5 total ratings)
GenreCard Game
Made withPICO-8, Aseprite, Sublime Text
Tags2D, Demake, PICO-8, Pixel Art, Retro, Short, Singleplayer, sourcecode
Average sessionA few minutes
InputsMouse, Touchscreen, Smartphone
AccessibilityColor-blind friendly, High-contrast, Textless


free-cell-1k-windows.zip 972 kB
Version 7 Sep 26, 2021
free-cell-1k-linux.zip 721 kB
Version 7 Sep 26, 2021
free-cell-1k-osx.zip 3 MB
Version 7 Sep 26, 2021
free-cell-1k-raspi.zip 1 MB
Version 9 Sep 26, 2021
freecell.p8.png 6 kB
Version 9 Sep 26, 2021


Log in with itch.io to leave a comment.


Beat it, and enjoyed it. Your code is a work of art :)


obsessed. i have this bookmarked on my phone. 10/10


I just had an instance where the game stopped auto filling the lowest cards to the top. At one point I had a stack where the 2 descended below the bounds of the screen. I was still able to grab it when I needed it later, but I don't know if that would be what did it?

Not a major issue at all, just thought you may be interested to know!

attached a screenshot of having all my ordered stacks not filling in:

(3 edits) (+3)

yep, thatā€™s a known bug! itā€™s kinda interesting how it happens: if you play the game for longer than 18 minutes, T overflows and becomes negative, so if(T>52)q(14-šŸ˜,3)M=T%3 doesnā€™t run every frame anymore (because T is no longer larger than 52) so M never gets reset to 0, which is necessary to make the cards auto-move.

(why 18 minutes? T+=1 executes once per frame and pico-8 numbers overflow at 2^15, and (2^15 frames)*(1 second/30 frames)*(1 minute/60 seconds) is roughly 18.2 minutes)

If you wait for another 18 minutes, you might think that T would become positive and the cards would start auto-moving again, but before that happens the deck re-deals itself (starting when T reaches 0) and all sorts of weirdness happens.

Anyway, thanks for the bug report! That screenshot is really satisfying to look at :)




Absolutely mindblowing, really fun to dig through the early version.

But i should point out that it's missing the rectfillwh function šŸ˜‰

thank you :D

oh, ha, good point! fixed


Wow... this is amazing. šŸ˜®
This looks and plays SO well, considering the limitations.
Nice & clean itch page too - glad the instructions were given.
(Also - bravo for sharing some awesome char-saving tips for others! šŸ˜‰)
Superb entry šŸ‘


thank you!! and thank you for running this jam; I had a lot of fun making this and golfing it down. (and if I find the time, Iā€™d like to write up an in-depth devlog dissecting the code!)

Nice work!

thank you!