It’s also a good way to spend the time, like when you are commuting. Keep in mind that https://FreeSolitaire.win works offline (after the 1st visit, using a service worker: https://developer.mozilla.org/en-US/docs/Web/API/Service_Wor...) ;-)
1,001 karma · joined February 7, 2008
It’s also a good way to spend the time, like when you are commuting. Keep in mind that https://FreeSolitaire.win works offline (after the 1st visit, using a service worker: https://developer.mozilla.org/en-US/docs/Web/API/Service_Wor...) ;-)
Regarding reverse billing: I don’t know much. I am not myself billed by Moya, although they do bill some of their partners. Please see https://datafree.tech (that’s quite specific to Moya / South Africa carriers, I guess)
It’s even worse with the court cards (aka “picture cards”: jack, queen, king). Out of laziness and for space-saving, they all share the same design: their suit symbol, in big, in the center (and the two corner pips). Not easy to distinguish between them easily/quickly, especially if your sight isn’t good.
I should do something about all that, one of these days. Thank you for your feedback!
Wrt attracting visitors: Word of mouth, mainly. Posted it on Reddit back then, things like that. It grew organically from that. And, although it’s far from being on top results on SERP (search engine result pages), some people do find it that way. But yes, the Moya thing was a big boost!
I started making it in 2016 and I’ve been slowly iterating on it over time. It has stayed minimal & lightweight, on purpose. No framework, no cruft, no obtrusive ads.
Fun fact: because it’s so lightweight, it was included in 2020 in Moya (https://play.google.com/store/apps/details?id=nu.bi.moya), a popular messaging app in South Africa that is “data-free” for users (it does reverse-billing). Now ~40% of players are South Africans!
Discussed on HN from to time, for instance:
— https://news.ycombinator.com/item?id=42026575 (38 days ago, 19 points)
— https://news.ycombinator.com/item?id=41971887 (43 days ago, 25 points) “Quick side-note. Thank you for freesolitaire.win. It's such a beautiful implementation of solitaire. Works so well as a PWA, I can enjoy it even without proper internet connection, it's simple, does the basics, but does it perfectly. There's nothing to add to it, but more importantly... nothing to take out.” (!)
— https://news.ycombinator.com/item?id=34483398 (2023, 4 points)
Feedback always welcome, and happy to answer any question!
I had a vague intuition of doing the same (going backwards) to generate the winnable Solitaire card deals, but I didn’t get far with it… Does anyone have experience/ideas on that? FTR: a similar discussion on X, started recently by Jonathan Blow: https://x.com/Jonathan_Blow/status/1865520149891346634
I ended up generating totally random deals, then filtering-out those unsolvable by an algorithm of mine (described at https://FreeSolitaire.win/strategy#remarks). It’s fast & good enough to run on-the-fly, when a player starts a new game. But this isn’t an intellectually satisfying solution.
Note that “The probability of being able to win a game of Klondike with best-possible play is not known, and the inability of theoreticians to precisely calculate these odds has been referred to by mathematician Persi Diaconis as "one of the embarrassments of applied probability"” dixit https://en.wikipedia.org/wiki/Klondike_(solitaire)#Probabili...
We need another genius like Ken Thompson for Solitaire!
> Apparently, people often have problems finding an appropriate address to contact when they have issues with this app.
> This leads a disproportionate amount of them to send emails to me asking for solutions and fixes to their situations.
— https://daniel.haxx.se/blog/2024/12/03/no-need-to-email-me-a...
Discussed lately on HN: https://news.ycombinator.com/item?id=42010136
For instance, see this recent thread https://news.ycombinator.com/item?id=41967897 about the “418 I’m a teapot” HTTP status code, also linking to MDN. It was nothing new neither.
That you cannot adjust the z-index is disturbing, especially given that you have to style <dialog> yourself if you wanna make it look any good (as others have reported here).
Also, for the record, alert() is still higher than <dialog> on the plane (see https://i.imgur.com/tzKOEF2.png).
Vignettes set their `z-index` CSS property to the max (2147483647), but a <dialog> is still higher on the z-plane (with no way to adjust that).
So if you click a link from a <dialog>, and an interstitial gets displayed, it’s under the <dialog>. It looks like nothing happened, that clicking is broken.
Fix in my case was to close() the <dialog> onclick.
① “Decrease the brightness and contrast of images a bit so that it looks comfortable to the eyes when it’s against a dark background.”
② “If we simply invert a dark shadow using light colors, then we get this funky thing […] Close elements should still be lighter and distant elements should still be darker – even in a dark UI.”
Oh yes, shadows are tricky. I got ① right for the dark theme of https://FreeSolitaire.win, but I never thought of ②. Good to know!
Stale-while-revalidate: see https://web.dev/articles/stale-while-revalidate & https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Ca...
Immutable: https://datatracker.ietf.org/doc/html/rfc8246 & https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Ca...
And if, like in the article, you’re using a CDN, `s-maxage` (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Ca...) is quite useful. Set it to a long time, and purge the CDN cache on deploy.
It shines for large inputs (it’s far up the SMHasher list you linked in this case).
It offers a good compromise; it’s not bad (good, even) for both large and small inputs.
Granted, rapidhash is quite good on both fronts, too.
> It’s the fastest hash function we know of, and we have benchmarked all the ones we could find. On modern Intel x64 CPUs, it hashes 16 bytes per cycle single-threaded. This means in cache it can hash at a rate of 64 gigabytes per second on a 4.2gHz machine. Out of cache, it hashes at whatever speed your main memory bus can provide to a single core, since that is usually the limiting factor on modern x64 CPUs.
> It has also now been tuned to be the fastest hash on small inputs, too. Despite the fact that it is a full 128-bit hash, it still outperforms “fast” 64-bit hashes across all input sizes.
— https://archive.is/CQOVm (originally https://mollyrocket.com/meowhash)
Discussion on HN: https://news.ycombinator.com/item?id=29038813 & https://news.ycombinator.com/item?id=18262627
;-)
Quoting https://engineering.fb.com/2017/01/26/web/this-browser-tweak...:
> We began to discuss changing the behavior of the reload button with the Chrome team. […] we proposed a compromise where resources with a long max-age would never get revalidated, but that for resources with a shorter max-age the old behavior would apply. The Chrome team thought about this and decided to apply the change for all cached resources, not just the long-lived ones.
> Firefox was quick in implementing the cache-control: immutable change and rolled it out just around when Chrome was fully launching their final fixes to reload.
> Chrome and Firefox’s measures have effectively eliminated revalidation requests to us from modern version of those browsers.
Quoting https://www.sitemaps.org/protocol.html#otherformats:
> The Sitemap protocol enables you to provide details about your pages to search engines, […] in addition to the XML protocol, we support RSS feeds and text files, which provide more limited information.
> You can provide an RSS (Real Simple Syndication) 2.0 or Atom 0.3 or 1.0 feed. Generally, you would use this format only if your site already has a syndication feed.
Stale-while-revalidate: see https://web.dev/articles/stale-while-revalidate & https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Ca...
Immutable: https://datatracker.ietf.org/doc/html/rfc8246 & https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Ca...
And if using a CDN, `s-maxage` (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Ca...) is quite useful. Set it to a long time, and purge the CDN cache on deploy.
Anyone knows of others like that?
Here is mine: https://FreeSolitaire.win/robots.txt
On Wikipedia: https://en.wikipedia.org/wiki/Communications_Decency_Act#Sec...
— “The leanternet principles” <https://leanternet.com/>
— “The 250KB Club - The Web Is Doom” <https://250kb.club/>
/** Precomputed CRC-32 lookup table for half-bytes (aka “nibbles”).
* Trade more compute time for less memory and less code to transmit.
* @see https://create.stephan-brumme.com/crc32/#half-byte
*/
const CRC32_NIBBLE_TABLE = new Uint32Array([
0, 0x1DB71064, 0x3B6E20C8, 0x26D930AC, 0x76DC4190, 0x6B6B51F4, 0x4DB26158, 0x5005713C,
0xEDB88320, 0xF00F9344, 0xD6D6A3E8, 0xCB61B38C, 0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 0xBDBDF21C
]);
/** @return {number} CRC-32 (polynomial 0x04C11DB7) of the input data.
* @param {!BufferSource} data The input data.
* @param {number=} previousValue The previous CRC value, if resuming a computation.
* @see https://en.wikipedia.org/wiki/Cyclic_redundancy_check
*/
function crc32(data, previousValue = 0) {
const bytes = ArrayBuffer.isView(data)
? new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
: new Uint8Array(data);
let crc = ~previousValue;
for (let i = 0; i < bytes.length; i++) {
crc = (crc >>> 4) ^ CRC32_NIBBLE_TABLE[0x0f & (crc ^ bytes[i])];
crc = (crc >>> 4) ^ CRC32_NIBBLE_TABLE[0x0f & (crc ^ (bytes[i] >> 4))];
}
return ~crc;
}
From https://GitHub.com/PaulCapron/pwa2uwp/blob/master/src/zip.jsThe shuffling is random, but only winnable decks are generated (by default). The computer algorithm/solver is described here: https://FreeSolitaire.win/strategy
So it’s pure chance you got an easy shuffle.
> In any regard, I like your implementation.
Thanks, I’m glad you like it! If you have suggestions for improvement, I’m all ears (here or by e-mail) ;-)
> In the end I didn't need to do too much space optimization to keep Solitaire down to two dotstrips
So, a full implementation of Solitaire in ~4KiB. Count me impressed!
I like to show off that my own (as a web app: https://FreeSolitaire.win) is "only" 21KiB, but that’s small fry in comparaison!
Regarding playing on phone: one improvement I have in mind, is to have the stock (aka reserve) and waste piles be on the right side. That would make them easier to reach for right-handed players, I guess. What do you think? (The foundations piles would inversely go to the left. They are rarely manipulated, given that one can double-tap a card to automatically send it to its foundation pile.)
Thank you again for the feedback, that’s always very appreciated!