<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: asrocky010</title>
    <description>The latest articles on DEV Community by asrocky010 (@asrocky010_7cfd07f11375df).</description>
    <link>https://dev.to/asrocky010_7cfd07f11375df</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4173329%2Fc3c17777-0393-4ed9-934e-56d3d4a08ca1.png</url>
      <title>DEV Community: asrocky010</title>
      <link>https://dev.to/asrocky010_7cfd07f11375df</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/asrocky010_7cfd07f11375df"/>
    <language>en</language>
    <item>
      <title>Delayed Gratification Isn't About Saying No - It's About Choosing Which Yes You Want More</title>
      <dc:creator>asrocky010</dc:creator>
      <pubDate>Fri, 23 Oct 2026 14:32:48 +0000</pubDate>
      <link>https://dev.to/asrocky010_7cfd07f11375df/delayed-gratification-isnt-about-saying-no-its-about-choosing-which-yes-you-want-more-40dj</link>
      <guid>https://dev.to/asrocky010_7cfd07f11375df/delayed-gratification-isnt-about-saying-no-its-about-choosing-which-yes-you-want-more-40dj</guid>
      <description>&lt;p&gt;The marshmallow test is one of the most misread studies in popular psychology. The story goes: kids who resisted eating one marshmallow for 15 minutes grew up to be richer, healthier, and more successful. So the lesson people take away is: &lt;em&gt;deprive yourself now, reward yourself later&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That framing is wrong, and it's why most "delay gratification" advice fails.&lt;/p&gt;

&lt;p&gt;Deprivation backfires. When you treat delayed gratification as a willpower battle — white-knuckling every latte, every takeout night, every impulse buy — you will eventually snap. And when you snap, you overspend in the opposite direction. Crash diets produce binge eating. Austerity budgets produce revenge spending.&lt;/p&gt;

&lt;p&gt;The people who are actually good at delaying gratification aren't the ones who suffer. They're the ones who reframe the choice. They don't see "skip the $150 dinner" as a loss. They see it as choosing the version of themselves that retires a year earlier, or the house with the spare bedroom, or the ability to quit a toxic job without a backup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's not saying no to fun. It's saying yes to a bigger fun later.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A few practical shifts that make this easier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Put the two options side by side.&lt;/strong&gt; $150 today feels like nothing. $150 invested every month for 30 years at 7% is roughly $180,000. The number changes the feeling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automate the delay.&lt;/strong&gt; Move your savings to a separate account on payday so you never see the money in the first place. Willpower is a terrible system. Defaults are a great one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep a "fun money" line in the budget.&lt;/strong&gt; This sounds counterintuitive, but the whole point of delayed gratification isn't to live miserably. It's to make sure the spending you &lt;em&gt;do&lt;/em&gt; choose is the spending you actually care about. A budget with zero room for joy is a budget that breaks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increase the gap, don't delete the spending.&lt;/strong&gt; Cut the stuff you don't care about (subscription you forgot, the upgraded plan you never use) so you can keep the stuff you do.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Discipline that feels like punishment never lasts. Discipline that feels like choosing your future self does.&lt;/p&gt;

&lt;p&gt;If you like this kind of plain-English breakdown of classic money books, &lt;a href="https://richreadme.com" rel="noopener noreferrer"&gt;RichReadme&lt;/a&gt; turns the core ideas of finance bestsellers into 5-minute summaries you can actually act on.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Your 20s Aren't About Picking the Right Investment. They're About Being Able to Survive the Wrong One.</title>
      <dc:creator>asrocky010</dc:creator>
      <pubDate>Thu, 22 Oct 2026 14:33:30 +0000</pubDate>
      <link>https://dev.to/asrocky010_7cfd07f11375df/your-20s-arent-about-picking-the-right-investment-theyre-about-being-able-to-survive-the-wrong-3g2l</link>
      <guid>https://dev.to/asrocky010_7cfd07f11375df/your-20s-arent-about-picking-the-right-investment-theyre-about-being-able-to-survive-the-wrong-3g2l</guid>
      <description>&lt;p&gt;If you're in your 20s and you've absorbed the standard investing advice, you've probably heard "you can be aggressive, you have time on your side." That's true, but most people hear it wrong. They hear "take big swings, YOLO the next Tesla or crypto." They don't hear the actual point.&lt;/p&gt;

&lt;p&gt;The real advantage of your 20s isn't that you can stomach a 50% drawdown. It's that you have &lt;em&gt;nothing to lose yet&lt;/em&gt; and decades of paychecks ahead to refill whatever you lose. The math does the work, not your courage.&lt;/p&gt;

&lt;p&gt;Do the unfun arithmetic. Suppose you put $100/month into a low-cost S&amp;amp;P 500 index fund starting at 25, at a 7% real return. By 65, that's about $260,000. If you wait until 35 to start that exact same $100/month, you end with about $130,000. Ten years of &lt;em&gt;delay&lt;/em&gt; cuts the final number in half. You don't need to beat the market. You need to start.&lt;/p&gt;

&lt;p&gt;The mistake people in their 20s actually make isn't being too conservative. It's spending their twenties researching which stock or coin to buy, watching every daily move, and selling when the market drops 20%. That behavior destroys more money than any wrong asset allocation ever will.&lt;/p&gt;

&lt;p&gt;So the actual playbook is boring on purpose:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the full employer 401k match before anything else — it's an instant 50-100% return.&lt;/li&gt;
&lt;li&gt;Open a Roth IRA and auto-contribute whatever you can, even $50/month.&lt;/li&gt;
&lt;li&gt;Put it in a broad low-cost index fund and stop looking at it.&lt;/li&gt;
&lt;li&gt;Spend your energy on raising your income and not inflating your lifestyle, not on stock picking.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You are not supposed to figure out investing in your 20s. You're supposed to start the engine and then get out of its way.&lt;/p&gt;

&lt;p&gt;If you want the long-form, book-backed version of what the best money writers actually tell young people — the version that doesn't sound like a crypto bro — &lt;a href="https://richreadme.com" rel="noopener noreferrer"&gt;RichReadme&lt;/a&gt; breaks down the core ideas from the investing and personal-finance books that matter.&lt;/p&gt;

</description>
      <category>investing</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Zero-Based Budgeting Sounds Awful. That's Why It Actually Works.</title>
      <dc:creator>asrocky010</dc:creator>
      <pubDate>Wed, 21 Oct 2026 14:33:17 +0000</pubDate>
      <link>https://dev.to/asrocky010_7cfd07f11375df/zero-based-budgeting-sounds-awful-thats-why-it-actually-works-4k40</link>
      <guid>https://dev.to/asrocky010_7cfd07f11375df/zero-based-budgeting-sounds-awful-thats-why-it-actually-works-4k40</guid>
      <description>&lt;p&gt;Every money advice column skips the same step: assuming you know where your money goes. The 50/30/20 rule, "pay yourself first," "save 20%," "automate your 401k" — all of it only works if you already have a baseline. Most people don't. They earn $5k/month, spend $5k/month, and at the end wonder where it went.&lt;/p&gt;

&lt;p&gt;Zero-based budgeting is the unsexy fix. Every month, you assign every dollar a job before it arrives: rent $1800, groceries $500, restaurants $200, transit $150, subscriptions $50, investing $800, fun $300, buffer $200. Income minus all assignments = zero. That's it.&lt;/p&gt;

&lt;p&gt;It sounds like accounting homework because it is. But that's the point. The value isn't in the spreadsheet — it's in the moment you have to decide "does this $14/month streaming service actually earn its spot?" Most people, after one honest month, find $200-400/month quietly going to things they don't even use. That alone pays for a Roth IRA contribution many years over.&lt;/p&gt;

&lt;p&gt;Why this beats "50/30/20": that ratio is a target, not a tool. If you don't know your current split, a target is just anxiety. Zero-based budgeting forces the split to become visible first, and the target then becomes obvious.&lt;/p&gt;

&lt;p&gt;You don't have to do this forever. Two or three honest months is usually enough to build the instinct — "this month's food spend is already over where it should be" — and after that you can go back to light tracking. The spreadsheet is training wheels, not a lifestyle.&lt;/p&gt;

&lt;p&gt;The people selling you "set it and forget it" investing are skipping the part where you discover the leaky bucket. Plug the hole first, then automate.&lt;/p&gt;

&lt;p&gt;If you want the book-backed version of how the best personal-finance writers think about money — the slow, boring, actually-works version, not the grind-flip version — &lt;a href="https://richreadme.com" rel="noopener noreferrer"&gt;RichReadme&lt;/a&gt; breaks down the key ideas from the books that actually shifted how people manage their monthly cash.&lt;/p&gt;

</description>
      <category>personalfinance</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Planet Zoo 2's animal list by region: 130 species, 12 regions, and three regions that hold exactly one animal</title>
      <dc:creator>asrocky010</dc:creator>
      <pubDate>Tue, 20 Oct 2026 12:57:03 +0000</pubDate>
      <link>https://dev.to/asrocky010_7cfd07f11375df/planet-zoo-2s-animal-list-by-region-130-species-12-regions-and-three-regions-that-hold-exactly-icf</link>
      <guid>https://dev.to/asrocky010_7cfd07f11375df/planet-zoo-2s-animal-list-by-region-130-species-12-regions-and-three-regions-that-hold-exactly-icf</guid>
      <description>&lt;p&gt;Planet Zoo 2 shipped on &lt;strong&gt;13 October 2026&lt;/strong&gt; with &lt;strong&gt;130 species&lt;/strong&gt;. The question I keep seeing is the simplest one possible: &lt;em&gt;"can I just get the list?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In game you cannot. The Zoopedia is one page per animal — biome, enclosure type, barrier grade, conservation status — and there is no index view that answers "what animals are in this game, and where are they from". So we exported the payload behind it and built the list ourselves. It is public and CC BY 4.0:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The list:&lt;/strong&gt; &lt;a href="https://pz2tools.wiki/animals/" rel="noopener noreferrer"&gt;pz2tools.wiki/animals&lt;/a&gt; — 130 species, 13 fields each&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The same 130, grouped by region:&lt;/strong&gt; &lt;a href="https://pz2tools.wiki/regions/" rel="noopener noreferrer"&gt;pz2tools.wiki/regions&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post is about the second one, because grouping by region turns out to expose a few things the roster page cannot.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the 13 fields are
&lt;/h2&gt;

&lt;p&gt;Every species carries: common name, scientific classification (class / order / family / genus), biome list, region list, enclosure type, Deluxe-vs-base flag, weight (male and female), barrier grade, minimum barrier height, and two barrier flags — climb-proof and allow-water.&lt;/p&gt;

&lt;p&gt;That is the whole vocabulary the game uses to decide whether two animals can live together. Keep that in mind, because it explains the trap below.&lt;/p&gt;

&lt;h2&gt;
  
  
  130 species, 12 regions, 204 assignments
&lt;/h2&gt;

&lt;p&gt;The game has twelve regions: seven on land (Africa, Asia, Europe, North America, South America, Australasia, Arctic) and five oceans (Atlantic, Pacific, Indian, Arctic, Southern).&lt;/p&gt;

&lt;p&gt;Because a species can belong to more than one region, the counts do &lt;strong&gt;not&lt;/strong&gt; add up to 130:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Region&lt;/th&gt;
&lt;th&gt;Species&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Asia&lt;/td&gt;
&lt;td&gt;44&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Africa&lt;/td&gt;
&lt;td&gt;43&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pacific Ocean&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indian Ocean&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Europe&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;North America&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;South America&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Australasia&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Atlantic Ocean&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Arctic&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Arctic Ocean&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Southern Ocean&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;204 assignments across 130 species.&lt;/strong&gt; 82 species list exactly one region; 48 list two or more. The extremes are worth a line each:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hawksbill Turtle&lt;/strong&gt; is the only species that appears in nine regions — and the only one that straddles land and ocean at the same time (Africa, Asia, Europe, North America, South America, Australasia + four oceans).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Moon Jelly&lt;/strong&gt; covers all five oceans, which is why two of the three "single animal" regions contain the same jellyfish.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mountain Hare&lt;/strong&gt; is the only land animal listed for the Arctic. One species. That is the entire Arctic roster for a zoo whose theme is "Arctic".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which leads to the thing most people get wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Region is where an animal is &lt;em&gt;from&lt;/em&gt;. Biome is where it can &lt;em&gt;live&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;This is the single most expensive misunderstanding in the game right now. Region is flavour and roster-planning. The two fields that decide whether a habitat is accepted are &lt;strong&gt;biome&lt;/strong&gt; and &lt;strong&gt;enclosure type&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Two species from the Amazon and the Congo can share an enclosure if both accept Rainforest and both use a Habitat. Two species from the same continent cannot, if one is a fish and the other is a bird. Region never enters the check.&lt;/p&gt;

&lt;p&gt;So the region list is a planning tool, not a rulebook: pick a coherent-looking roster ("East Asia house", "reef wing"), then verify the actual housing with the &lt;a href="https://pz2tools.wiki/cohabitation/" rel="noopener noreferrer"&gt;co-habitation chart&lt;/a&gt; and the &lt;a href="https://pz2tools.wiki/biomes/" rel="noopener noreferrer"&gt;biome hub&lt;/a&gt;, both derived from Frontier's own text rather than from community guesswork.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data gotcha, if you are scraping this too
&lt;/h2&gt;

&lt;p&gt;The region field arrives as a &lt;strong&gt;single pipe-delimited string&lt;/strong&gt;, not an array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"common_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hawksbill Turtle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"continents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Africa|Asia|AtlanticOcean|Australasia|Europe|IndianOcean|NorthAmerica|PacificOcean|SouthAmerica"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything else in the payload that is multi-valued &lt;em&gt;is&lt;/em&gt; an array — &lt;code&gt;biomes&lt;/code&gt;, &lt;code&gt;enclosure_types&lt;/code&gt; — so this one field breaks the assumption you will have written by the second record. Split on &lt;code&gt;|&lt;/code&gt;, then de-duplicate, because some records repeat a token.&lt;/p&gt;

&lt;p&gt;Two more traps in the same payload, both of which cost me time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Empty strings, not nulls, for aquatic species.&lt;/strong&gt; Fish and exhibit animals have &lt;code&gt;barrier_grade: ""&lt;/code&gt;, &lt;code&gt;barrier_min_height_m: ""&lt;/code&gt;, &lt;code&gt;barrier_climb_proof: ""&lt;/code&gt;. Coerce to &lt;code&gt;null&lt;/code&gt; before averaging anything, or your "median barrier height" quietly includes zeros.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;content_pack&lt;/code&gt; is the Deluxe flag.&lt;/strong&gt; Six species — Axolotl, Golden Eagle, Golden Lion Tamarin, Longfin Batfish, Blue and Gold Fusilier, Great Hammerhead — are &lt;code&gt;Deluxe&lt;/code&gt;. Filter them out if you want the "base game only" roster, because the Steam page does not separate them either.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What the region cut is actually good for
&lt;/h2&gt;

&lt;p&gt;Three practical uses, in the order I use them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Deluxe budgeting per theme.&lt;/strong&gt; The Pacific and Indian Ocean lists hold three Deluxe species each; every land region holds one or two except Australasia, which holds none. If you are building a reef wing without buying Deluxe, the Australasia + Atlantic combination is the cheap path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Knowing when a theme is a dead end.&lt;/strong&gt; The Arctic has one animal, so an "Arctic zone" is a Mountain Hare plus borrowed Taiga species (Eurasian Brown Bear, Eurasian Lynx and friends accept Taiga/Tundra). It works, but it is not a zone — it is one habitat wearing a costume.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Reading biome overlap instead of guessing.&lt;/strong&gt; Asia's 44 species lean Rainforest (20 of 44); Africa's 43 lean Savannah (14). Those two numbers tell you which biome hub to open first when you start a continent-themed zoo, and they also tell you why a "Savannah Asia" build is thin: the species exist, the climate does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest caveat
&lt;/h2&gt;

&lt;p&gt;This is derived data, not datamined code. The export came from the official Zoopedia payload on &lt;strong&gt;1 October 2026&lt;/strong&gt;, twelve days before launch, and the game has already patched once since. Region assignments are stable so far; the co-habitation verdicts were the ones that moved, and those changes are logged on the &lt;a href="https://pz2tools.wiki/updates/" rel="noopener noreferrer"&gt;updates page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Every row links back to the Frontier sentence it came from, and the rule set is published at &lt;a href="https://pz2tools.wiki/editorial-policy/" rel="noopener noreferrer"&gt;pz2tools.wiki/editorial-policy&lt;/a&gt;. If a verdict looks wrong, you can point at the sentence instead of at me.&lt;/p&gt;

&lt;p&gt;Raw CSV and JSON for all of it: &lt;a href="https://pz2tools.wiki/animals/" rel="noopener noreferrer"&gt;pz2tools.wiki/animals&lt;/a&gt; (CC BY 4.0), mirrored on &lt;a href="https://github.com/odebo/planet-zoo-2-dataset" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; and archived with a DOI at &lt;a href="https://doi.org/10.5281/zenodo.23263612" rel="noopener noreferrer"&gt;10.5281/zenodo.23263612&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>gaming</category>
      <category>pcgaming</category>
      <category>data</category>
      <category>opendata</category>
    </item>
    <item>
      <title>A seeded shuffle for 580 items: reproducible sets without a server</title>
      <dc:creator>asrocky010</dc:creator>
      <pubDate>Tue, 20 Oct 2026 12:17:04 +0000</pubDate>
      <link>https://dev.to/asrocky010_7cfd07f11375df/a-seeded-shuffle-for-580-quiz-questions-reproducible-practice-sets-without-a-server-1642</link>
      <guid>https://dev.to/asrocky010_7cfd07f11375df/a-seeded-shuffle-for-580-quiz-questions-reproducible-practice-sets-without-a-server-1642</guid>
      <description>&lt;h2&gt;
  
  
  The bug report that made me delete Math.random()
&lt;/h2&gt;

&lt;p&gt;A user wrote two sentences: "I got the same question twice in one set, and the answer order changed when I clicked back."&lt;/p&gt;

&lt;p&gt;I opened the page, ran the app, got ten questions, and could not reproduce either problem. Closed the tab, reopened it, got a different set. Of course I did. That is the whole problem with randomness in a quiz: every bug report arrives with a seed that no longer exists.&lt;/p&gt;

&lt;p&gt;This was the shuffle:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;shuffle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;~~~&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endraw&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Three&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;looks&lt;/span&gt; &lt;span class="nx"&gt;fine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wrong&lt;/span&gt; &lt;span class="nx"&gt;twice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;The&lt;/span&gt; &lt;span class="nx"&gt;comparator&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nf"&gt;inconsistent &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;it&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;same&lt;/span&gt; &lt;span class="nx"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;so&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s result depends on its internal algorithm and array length, not on a probability you can reason about. It is also biased: elements near the middle of the array move less than elements at the ends. And because the comparator runs an unpredictable number of times, you cannot replay it even if you log the output.

## Fisher-Yates is the shuffle you actually want{% raw %}

~~~js
function shuffle(a) {
  for (var i = a.length - 1; i &amp;gt; 0; i--) {
    var j = Math.floor(Math.random() * (i + 1));
    var t = a[i]; a[i] = a[j]; a[j] = t;
  }
  return a;
}
~~~

Every permutation is equally likely, it is O(n), and — this is the part that matters — it makes exactly n-1 calls to the random source. That predictable call count is what lets you swap the source for a seeded one.

## Swapping the source: 12 lines of PRNG

~~~js
function xmur3(str) {
  for (var i = 0, h = 1779033703 ^ str.length; i &amp;lt; str.length; i++) {
    h = Math.imul(h ^ str.charCodeAt(i), 3432918353);
    h = (h &amp;lt;&amp;lt; 13) | (h &amp;gt;&amp;gt;&amp;gt; 19);
  }
  return function () {
    h = Math.imul(h ^ (h &amp;gt;&amp;gt;&amp;gt; 16), 2246822507);
    h = Math.imul(h ^ (h &amp;gt;&amp;gt;&amp;gt; 13), 3266489909);
    return (h ^= h &amp;gt;&amp;gt;&amp;gt; 16) &amp;gt;&amp;gt;&amp;gt; 0;
  };
}

function mulberry32(a) {
  return function () {
    a |= 0; a = (a + 0x6D2B79F5) | 0;
    var t = Math.imul(a ^ (a &amp;gt;&amp;gt;&amp;gt; 15), 1 | a);
    t = (t + Math.imul(t ^ (t &amp;gt;&amp;gt;&amp;gt; 7), 61 | t)) ^ t;
    return ((t ^ (t &amp;gt;&amp;gt;&amp;gt; 14)) &amp;gt;&amp;gt;&amp;gt; 0) / 4294967296;
  };
}

var seedFn = xmur3(seedString);
var rand = mulberry32(seedFn());
~~~

Neither function is cryptographic and neither needs to be. They need three properties: same string in, same sequence out; uniform enough that 580 items do not clump; and fast enough that reshuffling ten options costs nothing.

## Where the seed comes from

Three sources, one function:

- **A per-tab seed in sessionStorage.** Generated once, so a reload keeps the set but a new tab does not.
- **A seed in the query string** (`?seed=8f2c1a`). This is the one that pays for itself. A bug report now contains the exact set, and "I got the same question twice" becomes reproducible in one click.
- **A date string for the daily set** (`2026-10-20`). Everyone who opens the warm-up that day gets the same ten questions, which makes the answer explanations shareable.

~~~js
function seedForRun(opts) {
  if (opts.seed) return opts.seed;
  if (opts.daily) return new Date().toISOString().slice(0, 10);
  var k = &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;quiz&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;seed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;;
  var v = sessionStorage.getItem(k);
  if (!v) { v = Math.random().toString(36).slice(2, 8); sessionStorage.setItem(k, v); }
  return v;
}
~~~

## The three things that broke after I "fixed" it

**1. Calling the generator during render.** I built the RNG inside the render path, so every re-render (a timer tick, a tooltip, a resize handler) advanced the sequence. The question order changed while the user was reading. Fix: build the queue once, store it as data, render from the array.

**2. Reusing one seed for every new set.** "New set" called the same seeded shuffle with the same seed and handed back the identical ten questions. The user thought the button was broken. Fix: the seed is per run, the RNG object is per run, and "new set" mints a new seed and writes it to the URL with replaceState — so the URL always describes what is on screen.

**3. Shuffling the options separately from the bank.** The bank order was seeded, the option order was not, so option B was "the right answer" in 73% of the items in our own data. A quiz-taker who notices that pattern stops reading the options. Fix: one RNG per run, used for both, and a build-time check that flags any answer position above ~30%.

That last number is the only one from this project worth generalising: if answer positions are not shuffled, or are shuffled with a bad comparator, they drift. Ours drifted to 73% on B across 580 questions. Nobody wrote that on purpose; it accumulated.

## What it bought

- Bug reports became replayable: a six-character seed in the URL.
- Screenshot tests became stable: the same URL renders the same question and the same option order.
- A teacher can hand out one link and know the whole room sees the same ten items.
- The daily set is cacheable and shareable, because its seed is a date.

None of this needs a server, a database, or a build step — about 40 lines of vanilla JS and one rule: **the random source is an argument, not a global.**


---

The dataset used for the checks in this post is 17 rows of temperature and cooling windows; a fixture that small is enough to catch a biased comparator, because a bad shuffle shows up as a repeated row long before it shows up in production.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Passive Income Isn't a Hack. It's What Happens After You Do the Unsexy Work.</title>
      <dc:creator>asrocky010</dc:creator>
      <pubDate>Mon, 19 Oct 2026 14:35:46 +0000</pubDate>
      <link>https://dev.to/asrocky010_7cfd07f11375df/passive-income-isnt-a-hack-its-what-happens-after-you-do-the-unsexy-work-4h83</link>
      <guid>https://dev.to/asrocky010_7cfd07f11375df/passive-income-isnt-a-hack-its-what-happens-after-you-do-the-unsexy-work-4h83</guid>
      <description>&lt;p&gt;Everyone chasing "passive income" today actually wants a magic button: stop working, money still arrives. That version doesn't exist, and the people selling it to you are the ones earning the passive income — from you.&lt;/p&gt;

&lt;p&gt;Real passive income is what's left over &lt;em&gt;after&lt;/em&gt; you've done a huge block of active work that most people won't do. It comes from assets that keep selling or earning long after the first hour you put in: a book, a course, a piece of software, a rental property, an audience, a dividend index fund. Each of those requires months (or years) of unpaid work before the first dollar trickles in.&lt;/p&gt;

&lt;p&gt;The math helps. A broad S&amp;amp;P 500 index fund yields roughly 1.5% in dividends. To get $1,000/month in "passive" dividends from that alone, you need about $800k invested first — which itself came from ~15 years of saving 40%+ of a normal salary. That's not a hack. That's a wage earner who delayed gratification hard.&lt;/p&gt;

&lt;p&gt;The other path — building something once that sells forever — is the same story in different clothes. A book, a template, a small SaaS tool: you work crazy hours for free for 6-12 months, then it earns in the background. People only call it "passive" because they skipped the part where you suffered.&lt;/p&gt;

&lt;p&gt;So the honest order is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pick one asset type you're willing to work on for a year without pay.&lt;/li&gt;
&lt;li&gt;Build it, publish it, ship it, even when it's bad.&lt;/li&gt;
&lt;li&gt;Make it repeatable — digital product, index fund, rental, content archive.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Then&lt;/em&gt; the income starts arriving while you sleep.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Skip step 1-3 and you're not building passive income. You're auditioning for a scam.&lt;/p&gt;

&lt;p&gt;If you want to read how the best investing and money-thinking books frame this — not the get-rich-quick version, but the slow compounding version — &lt;a href="https://richreadme.com" rel="noopener noreferrer"&gt;RichReadme&lt;/a&gt; breaks down the key ideas from the books that actually moved the needle for people.&lt;/p&gt;

</description>
      <category>investing</category>
      <category>personalfinance</category>
    </item>
    <item>
      <title>FIRE Isn't About Retiring at 35. It's About Buying Back Your Optionality.</title>
      <dc:creator>asrocky010</dc:creator>
      <pubDate>Sun, 18 Oct 2026 14:38:05 +0000</pubDate>
      <link>https://dev.to/asrocky010_7cfd07f11375df/fire-isnt-about-retiring-at-35-its-about-buying-back-your-optionality-1116</link>
      <guid>https://dev.to/asrocky010_7cfd07f11375df/fire-isnt-about-retiring-at-35-its-about-buying-back-your-optionality-1116</guid>
      <description>&lt;p&gt;FIRE (Financial Independence, Retire Early) has a reputation problem. The internet sells it as thirty-somethings on a beach sipping coconut water, and that cartoon is easy to mock. Strip the meme away and the actual idea is deeply unglamorous — and deeply powerful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The math is just one number.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There's no secret. If you can live on 4% of your investment portfolio each year and let the rest grow, you're financially independent. That means your nest egg needs to be roughly 25x your annual spending. Cut your spending by $10k a year and you don't just save $10k — you erase $250k from your target.&lt;/p&gt;

&lt;p&gt;That's why savings rate matters more than returns. Going from saving 10% of your income to 50% doesn't double your runway — it collapses your working years from around 50+ down to about 15-17. The difference between 10% and 50% is not "tighter budget", it's a decade of your life you get back.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The real prize is optionality, not idleness.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most people who hit FIRE don't stop working. They stop working &lt;em&gt;for other people's priorities&lt;/em&gt;. Suddenly you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;turn down a toxic client instead of enduring them for the paycheck,&lt;/li&gt;
&lt;li&gt;take six months off to care for a family member,&lt;/li&gt;
&lt;li&gt;work for near-zero pay on something that actually matters to you,&lt;/li&gt;
&lt;li&gt;say "no" to a meeting that didn't need to exist.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the whole point. You're not buying a permanent vacation — you're buying a &lt;em&gt;veto&lt;/em&gt; over how your next decade gets spent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You don't need to live on rice and beans.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The extreme version (100% savings, driving a 1998 Corolla, working two side hustles) is a caricature that scares normal people off. Even a far less dramatic path — bump savings from 10% to 25-35%, max out tax-advantaged accounts, automate everything — starts a visible countdown. Most people don't need "retire by 35"; they need the &lt;em&gt;option&lt;/em&gt; to opt out when life demands it.&lt;/p&gt;

&lt;p&gt;If that framework sounds familiar, I unpack summaries of the books that actually taught me these ideas on &lt;a href="https://richreadme.com" rel="noopener noreferrer"&gt;RichReadme&lt;/a&gt; — short, animated breakdowns of the investing and personal-finance titles that are actually worth your time.&lt;/p&gt;

</description>
      <category>investing</category>
      <category>personalfinance</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Planet Zoo 2 co-habitation: I checked all 1,221 pairings. Every aviary species has zero compatible partners.</title>
      <dc:creator>asrocky010</dc:creator>
      <pubDate>Sun, 18 Oct 2026 07:26:07 +0000</pubDate>
      <link>https://dev.to/asrocky010_7cfd07f11375df/planet-zoo-2-co-habitation-i-checked-all-1221-pairings-every-aviary-species-has-zero-compatible-4m0b</link>
      <guid>https://dev.to/asrocky010_7cfd07f11375df/planet-zoo-2-co-habitation-i-checked-all-1221-pairings-every-aviary-species-has-zero-compatible-4m0b</guid>
      <description>&lt;p&gt;Planet Zoo 2 shipped on &lt;strong&gt;October 13, 2026&lt;/strong&gt;. Since then the question I see most often is some version of &lt;em&gt;"why do these two animals fight when the game says they can share a habitat?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Frontier answers that in exactly one place: the &lt;strong&gt;Social &amp;amp; Reproduction&lt;/strong&gt; paragraph on each species' Zoopedia page. It is prose, not a table. So I read all 130 of them and turned every possible pairing into data.&lt;/p&gt;

&lt;p&gt;Here is what came out — including one result I did not expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rules (published, so you can argue with them)
&lt;/h2&gt;

&lt;p&gt;Every verdict on the &lt;a href="https://pz2tools.wiki/cohabitation/" rel="noopener noreferrer"&gt;co-habitation chart&lt;/a&gt; comes from a three-step rule applied to Frontier's own text:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Two species can only compete for the same enclosure if they &lt;strong&gt;share a biome and an enclosure type&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If the official text describes &lt;strong&gt;either&lt;/strong&gt; species as solitary → &lt;strong&gt;Not compatible&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If &lt;strong&gt;both&lt;/strong&gt; are described as group-living → &lt;strong&gt;Likely OK&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Anything the text does not state → &lt;strong&gt;Unverified&lt;/strong&gt;. I do not fill gaps with confident-looking green ticks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The rules are public at &lt;a href="https://pz2tools.wiki/editorial-policy/" rel="noopener noreferrer"&gt;pz2tools.wiki/editorial-policy&lt;/a&gt;, and every row links back to the Frontier sentence it came from — so you can disagree with Frontier instead of with me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;130 launch species produce &lt;strong&gt;1,221 pairs&lt;/strong&gt; that even qualify (same biome + same enclosure type):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;th&gt;Pairs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Likely OK&lt;/td&gt;
&lt;td&gt;376&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unverified&lt;/td&gt;
&lt;td&gt;106&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Not compatible&lt;/td&gt;
&lt;td&gt;739&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Reading the same paragraphs for social structure gives &lt;strong&gt;55 solitary · 39 social · 23 mixed · 13 "not stated"&lt;/strong&gt; species.&lt;/p&gt;

&lt;p&gt;Two things fall straight out of that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;739 of 1,221 pairs are "no".&lt;/strong&gt; The advice "just put all the savannah animals together" is wrong roughly two thirds of the time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only 59 of 130 species have a single "Likely OK" partner.&lt;/strong&gt; The other 71 have none.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The one that surprised me: every aviary species has zero
&lt;/h2&gt;

&lt;p&gt;PZ2 has 12 species that use a flying enclosure. In the matrix, &lt;strong&gt;all 12 have exactly 0 likely partners&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aviary species&lt;/th&gt;
&lt;th&gt;What Frontier's text says&lt;/th&gt;
&lt;th&gt;Likely partners&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Greater Flamingo&lt;/td&gt;
&lt;td&gt;group-living&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long-Tailed Parakeet&lt;/td&gt;
&lt;td&gt;group-living&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;White-Backed Vulture&lt;/td&gt;
&lt;td&gt;group-living&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Great Hornbill&lt;/td&gt;
&lt;td&gt;not stated&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Javan Green Magpie&lt;/td&gt;
&lt;td&gt;not stated&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secretarybird&lt;/td&gt;
&lt;td&gt;not stated&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Toco Toucan&lt;/td&gt;
&lt;td&gt;not stated&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;White-Tailed Sea-Eagle&lt;/td&gt;
&lt;td&gt;not stated&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Eurasian Bittern&lt;/td&gt;
&lt;td&gt;solitary&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Golden Eagle&lt;/td&gt;
&lt;td&gt;solitary&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long-Eared Owl&lt;/td&gt;
&lt;td&gt;solitary&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shoebill&lt;/td&gt;
&lt;td&gt;solitary&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is not a scraping bug and it is not a rounding artefact — it is what the launch roster looks like. Three of the twelve &lt;em&gt;are&lt;/em&gt; described as group-living birds; the other nine are solitary or not described at all. Since both sides of a pair have to be group-living for "Likely OK", the column stays empty for the whole aviary group.&lt;/p&gt;

&lt;p&gt;The practical version: &lt;strong&gt;in PZ2's launch data, an aviary is a single-species enclosure.&lt;/strong&gt; If you want a mixed one you are doing it on &lt;strong&gt;Unverified&lt;/strong&gt; — which may be perfectly fine, but you should know that is what you are doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The leaderboard
&lt;/h2&gt;

&lt;p&gt;There is a clear "everyone gets along with them" tier:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Species&lt;/th&gt;
&lt;th&gt;Likely OK partners&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Grey Wolf&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Asian Elephant&lt;/td&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bactrian Camel&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;African Savannah Elephant&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cape Buffalo&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Then a flat shelf of &lt;strong&gt;16 species at exactly 20&lt;/strong&gt;: Sable Antelope, Springbok, African Wild Dog, Thomson's Gazelle, Masai Giraffe, Reticulated Giraffe, Spotted Hyena, Lion, Meerkat, Gemsbok, Common Ostrich, African Penguin, Common Warthog, Black Wildebeest, Blue Wildebeest, Plains Zebra.&lt;/p&gt;

&lt;p&gt;Savannah shows up in &lt;strong&gt;213 of the 376&lt;/strong&gt; likely pairs (a pair can span two biomes, so this is not a partition). Reef is a distant second.&lt;/p&gt;

&lt;h2&gt;
  
  
  Territorial and aggressive are separate signals
&lt;/h2&gt;

&lt;p&gt;44 species carry a &lt;strong&gt;territorial&lt;/strong&gt; flag and 34 an &lt;strong&gt;aggressive&lt;/strong&gt; one in the official wording. These do not change the verdict — they are shown as context pills on each row, because &lt;em&gt;"these two can share a habitat"&lt;/em&gt; and &lt;em&gt;"these two will be relaxed about it"&lt;/em&gt; are not the same claim.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read this before you plan a zoo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The export is dated &lt;strong&gt;2026-10-01&lt;/strong&gt;, i.e. &lt;strong&gt;before patch 1.0.4&lt;/strong&gt;, whose notes include "Updates to animal cohabitation lists". So some verdicts may already be behind the live game. That caveat is printed on the page itself, and the &lt;a href="https://pz2tools.wiki/updates/" rel="noopener noreferrer"&gt;updates page&lt;/a&gt; tracks it.&lt;/li&gt;
&lt;li&gt;Every verdict is &lt;strong&gt;derived from prose&lt;/strong&gt;, not read out of a hidden compatibility field — the official payload contains no such field.&lt;/li&gt;
&lt;li&gt;Where the game is silent, the tool says &lt;em&gt;unverified&lt;/em&gt;. That is the entire point of it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where to check it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Full filterable matrix, one row per pair: &lt;strong&gt;&lt;a href="https://pz2tools.wiki/cohabitation/" rel="noopener noreferrer"&gt;pz2tools.wiki/cohabitation&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Per-species pages (habitat, barrier grade, size, weight, group size): &lt;strong&gt;&lt;a href="https://pz2tools.wiki/animals/" rel="noopener noreferrer"&gt;pz2tools.wiki/animals&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Pick two animals, get the verdict and the quote: &lt;strong&gt;&lt;a href="https://pz2tools.wiki/calculator/" rel="noopener noreferrer"&gt;calculator&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Plan an enclosure with the numbers: &lt;strong&gt;&lt;a href="https://pz2tools.wiki/planner/" rel="noopener noreferrer"&gt;planner&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The dataset behind it is free and citable: &lt;a href="https://github.com/odebo/planet-zoo-2-dataset" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · DOI &lt;a href="https://doi.org/10.5281/zenodo.23263613" rel="noopener noreferrer"&gt;10.5281/zenodo.23263613&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Unofficial reference site, not affiliated with Frontier Developments. All animal data generated from the official Planet Zoo 2 Zoopedia payload.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gaming</category>
      <category>pcgaming</category>
      <category>data</category>
      <category>opendata</category>
    </item>
    <item>
      <title>Why Index Funds Are The Only Investing Decision Most People Ever Need To Make</title>
      <dc:creator>asrocky010</dc:creator>
      <pubDate>Sat, 17 Oct 2026 14:32:58 +0000</pubDate>
      <link>https://dev.to/asrocky010_7cfd07f11375df/why-index-funds-are-the-only-investing-decision-most-people-ever-need-to-make-14bk</link>
      <guid>https://dev.to/asrocky010_7cfd07f11375df/why-index-funds-are-the-only-investing-decision-most-people-ever-need-to-make-14bk</guid>
      <description>&lt;p&gt;You don't need a system. You don't need a watchlist, a Bloomberg terminal, or a hot tip from a coworker. For the vast majority of people, the entire job of investing collapses into a single decision: buy a low-cost, broad-market index fund, and keep buying it.&lt;/p&gt;

&lt;p&gt;Here is why that is not lazy — it is the rational choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Most professional managers lose.&lt;/strong&gt; Year after year, roughly 85-90% of US large-cap fund managers fail to beat the S&amp;amp;P 500 over a 10-year window. Past outperformance barely predicts future outperformance; the funds that beat the market in one decade are rarely the ones that beat it in the next. If the paid pros with teams and data lose to an index most of the time, what is an amateur working 40 hours a week hoping to add?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Costs compound in the wrong direction.&lt;/strong&gt; A fund that charges 0.5% a year instead of 0.03% quietly skims a quarter of your final balance over 30 years. Expenses are certain; market returns are not. You can control fees, you cannot control returns — so control the one you can.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. You get the whole economy, not a bet.&lt;/strong&gt; An S&amp;amp;P 500 or total-market fund automatically holds every winner as it rises and cuts every loser as it falls. You never have to decide when to sell the next GE or what to do when a company you love gets disrupted. The index does it for you, for free.&lt;/p&gt;

&lt;p&gt;The hard part is not picking the fund — it is not touching it. Ignore the news, the crash calls, and the people on the internet who are certain this time is different. Set up an auto-invest, and go live your life.&lt;/p&gt;

&lt;p&gt;I break down the books that teach this same lesson — Bogle, Bogleheads, Larimore, and others — over at &lt;a href="https://richreadme.com" rel="noopener noreferrer"&gt;RichReadme&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>investing</category>
    </item>
    <item>
      <title>Dollar-Cost Averaging Doesn't Beat the Market — It Beats You</title>
      <dc:creator>asrocky010</dc:creator>
      <pubDate>Fri, 16 Oct 2026 14:32:22 +0000</pubDate>
      <link>https://dev.to/asrocky010_7cfd07f11375df/dollar-cost-averaging-doesnt-beat-the-market-it-beats-you-2b8g</link>
      <guid>https://dev.to/asrocky010_7cfd07f11375df/dollar-cost-averaging-doesnt-beat-the-market-it-beats-you-2b8g</guid>
      <description>&lt;p&gt;Everyone waits for the "right" moment to invest. It rarely comes. That's the whole point of dollar-cost averaging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why you're not Warren Buffett
&lt;/h2&gt;

&lt;p&gt;Timing the market looks easy on a chart. In real life you're betting against your own emotions: you buy when stocks feel exciting and sell when they feel scary — which is exactly backwards. The data is blunt: missing just the 10 best trading days of the last 20 years roughly cuts your long-term return in half.&lt;/p&gt;

&lt;h2&gt;
  
  
  What DCA actually does
&lt;/h2&gt;

&lt;p&gt;Dollar-cost averaging means investing a fixed amount on a fixed schedule — say, $500 every paycheck — no matter whether the market is up, down, or sideways. You buy more shares when prices are low and fewer when they're high. You don't need a crystal ball.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's not a magic return booster
&lt;/h2&gt;

&lt;p&gt;Here's the honest nuance: compared with dumping a lump sum all at once, the lump sum usually wins by a little — markets tend to rise over time. But DCA still wins where it matters: behaviorally. It keeps you invested when you'd otherwise freeze, and it removes the temptation to time the market and sit in cash while inflation quietly erodes your savings.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;You don't have to predict the market. Set an automatic monthly investment into a low-cost index fund and forget about it. The strategy that survives your own fear and greed beats the one that looks best on paper.&lt;/p&gt;

&lt;p&gt;I read the investing classics so you don't have to — short, honest summaries at &lt;a href="https://richreadme.com" rel="noopener noreferrer"&gt;RichReadme&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>beginners</category>
    </item>
    <item>
      <title>The '1 to 0' in Planet Zoo 2's Zoopedia: 20 shoal species and the flag behind them</title>
      <dc:creator>asrocky010</dc:creator>
      <pubDate>Fri, 16 Oct 2026 04:19:49 +0000</pubDate>
      <link>https://dev.to/asrocky010_7cfd07f11375df/the-1-to-0-in-planet-zoo-2s-zoopedia-20-shoal-species-and-the-flag-behind-them-4a16</link>
      <guid>https://dev.to/asrocky010_7cfd07f11375df/the-1-to-0-in-planet-zoo-2s-zoopedia-20-shoal-species-and-the-flag-behind-them-4a16</guid>
      <description>&lt;p&gt;Planet Zoo 2 launched on &lt;strong&gt;October 13, 2026&lt;/strong&gt;, and the question I have seen more often than any other this week is not about habitats, money or crashes. It is about a menu that looks broken.&lt;/p&gt;

&lt;p&gt;Open the Zoopedia entry for the Boeseman's Rainbowfish and the two gender rows read &lt;code&gt;1 to 0&lt;/code&gt;. Not a range like &lt;code&gt;1 to 4&lt;/code&gt; — &lt;code&gt;1 to 0&lt;/code&gt;, on both rows, with nothing in the game explaining it. In the r/PlanetZoo thread about it the guesses ranged from "the game doesn't sex fish" to "it's a bug" to "you can only keep one". None of them is right, and the answer was sitting in Frontier's own data the whole time.&lt;/p&gt;

&lt;h2&gt;
  
  
  One boolean explains it
&lt;/h2&gt;

&lt;p&gt;Every species record in the Zoopedia export carries a per-species flag called &lt;code&gt;shoal_fish&lt;/code&gt;. For the Boeseman's Rainbowfish it is &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When that flag is set, the species is stocked as a shoal rather than as a sexed pair, so there is no male/female split to print and both gender rows collapse instead of showing a range. It is not a bug, and it does not mean "maximum zero".&lt;/p&gt;

&lt;p&gt;The obvious follow-up is how common it is — and because &lt;a href="https://pz2tools.wiki/" rel="noopener noreferrer"&gt;pz2tools.wiki&lt;/a&gt; is generated from a full export of the launch Zoopedia, that is a count rather than a guess:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;20 of the 130 launch species are shoal species.&lt;/strong&gt; All 20 are fish (&lt;code&gt;class: Actinopterygii&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The 20, grouped by the water they need
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Freshwater — Lakes &amp;amp; Rivers (7):&lt;/strong&gt; Boeseman's Rainbowfish, Blunthead Cichlid, Common Rudd, Brown Trout, Clown Loach, Giant Gourami, African Tigerfish.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reef (7):&lt;/strong&gt; Clown Anemonefish, Schooling Bannerfish, Longfin Batfish, Blue and Gold Fusilier, Palette Surgeonfish, Yellow Tang, Bluespine Unicornfish.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open sea (2):&lt;/strong&gt; Pacific Sardine, Pacific Bluefin Tuna.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mixed biomes (4):&lt;/strong&gt; Threespot Damselfish (Mangrove + Reef), Indo-Pacific Sergeant (Open Sea + Reef), Indian Ocean Oriental Sweetlips (Estuarine + Reef), Golden Trevally (Estuarine + Reef).&lt;/p&gt;

&lt;p&gt;The same 20 with water type, biome, size and barrier grade side by side are on the &lt;a href="https://pz2tools.wiki/aquarium/" rel="noopener noreferrer"&gt;aquarium species page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three things that fall out of the list
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Fifteen of the twenty are also Exhibit animals.&lt;/strong&gt; They carry both &lt;code&gt;HabitatAquarium&lt;/code&gt; and &lt;code&gt;Exhibit&lt;/code&gt; in the enclosure field, which means you can show them in a walk-in glass exhibit before you commit to a full tank build. The five that are aquarium-only are Longfin Batfish, Pacific Sardine, Indian Ocean Oriental Sweetlips, Golden Trevally and Pacific Bluefin Tuna — which is exactly the set of shoal species you cannot cheap out on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The eight fish that &lt;em&gt;do&lt;/em&gt; show a gender range are the big-bodied loners.&lt;/strong&gt; The roster has 28 fish: the 20 shoal species above, plus eight that are stocked as individuals — Dolphinfish, Giant Grouper, Red Lionfish, Blackspotted Puffer, Sailfin Snapper, Ocean Sunfish, Clown Triggerfish and Humphead Wrasse. Those are the entries where the sexed-pair menu is the right interface, so the contrast between the two groups is a useful sanity check on the flag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Two of the six Deluxe animals are shoal fish.&lt;/strong&gt; The Deluxe Edition adds Longfin Batfish and Blue and Gold Fusilier on top of Axolotl, Golden Eagle, Golden Lion Tamarin and Great Hammerhead. So if you bought Deluxe, a third of those six new animals will show you &lt;code&gt;1 to 0&lt;/code&gt; as soon as you open their entry.&lt;/p&gt;

&lt;h2&gt;
  
  
  The practical rule
&lt;/h2&gt;

&lt;p&gt;If a fish shows &lt;code&gt;1 to 0&lt;/code&gt; on both gender rows, do not assume the menu is broken and do not assume the animal is bugged. Check whether the species is a shoal species — the &lt;a href="https://pz2tools.wiki/animals/boeseman-s-rainbowfish/" rel="noopener noreferrer"&gt;species page carries the answer&lt;/a&gt; next to biome, enclosure type and barrier grade. If it is, the planning question that actually matters is which other species share its water, and that is a biome + enclosure check you can run pair by pair on the &lt;a href="https://pz2tools.wiki/cohabitation/" rel="noopener noreferrer"&gt;compatibility chart&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Boeseman's Rainbowfish is a good example: eight species share both its biome and its enclosure type, six of those pairings are confirmed group-living by Frontier's own Zoopedia text, and two are unverified. So it is a fish that &lt;em&gt;should&lt;/em&gt; be in a shared freshwater tank — which is the opposite of what &lt;code&gt;1 to 0&lt;/code&gt; suggests if you read it as a limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the numbers come from
&lt;/h2&gt;

&lt;p&gt;Everything above is a field in the same source-verified export: 130 species, 1,221 cohabitation pairs, biome, enclosure type, barrier grade, conservation status and the &lt;code&gt;shoal_fish&lt;/code&gt; flag. It is mirrored on GitHub with a Zenodo DOI so the numbers are citable, and the &lt;a href="https://pz2tools.wiki/animals/" rel="noopener noreferrer"&gt;filterable animal list&lt;/a&gt; is generated from it rather than maintained by hand. If you find a species where the flag and the in-game UI disagree, that is worth writing up — but every &lt;code&gt;1 to 0&lt;/code&gt; case I have checked lines up exactly with the flag.&lt;/p&gt;

</description>
      <category>gaming</category>
      <category>pcgaming</category>
      <category>data</category>
      <category>opendata</category>
    </item>
    <item>
      <title>Why Picking Individual Stocks Is the Loser's Game It Feels Like</title>
      <dc:creator>asrocky010</dc:creator>
      <pubDate>Thu, 15 Oct 2026 14:35:43 +0000</pubDate>
      <link>https://dev.to/asrocky010_7cfd07f11375df/why-picking-individual-stocks-is-the-losers-game-it-feels-like-56mc</link>
      <guid>https://dev.to/asrocky010_7cfd07f11375df/why-picking-individual-stocks-is-the-losers-game-it-feels-like-56mc</guid>
      <description>&lt;p&gt;Every week someone tells me they found "the next Apple." For almost everyone, that urge to pick the winner is the single most expensive instinct in investing. Here's why I stopped trying.&lt;/p&gt;

&lt;h2&gt;
  
  
  The math is stacked against you
&lt;/h2&gt;

&lt;p&gt;When you buy an individual stock, you're betting on one company's future against thousands of full-time professionals — hedge funds, quants, analysts — who have faster data, cheaper trades, and more time than you. The average fund manager can't beat the index over a decade. You think you'll be the exception.&lt;/p&gt;

&lt;h2&gt;
  
  
  Survivorship bias quietly lies to you
&lt;/h2&gt;

&lt;p&gt;You remember the people who hit Amazon or Tesla. You don't remember the thousands who piled into Pets.com, WeWork, or the IPO that quietly vanished. The winners are loud; the graveyard is silent.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually works
&lt;/h2&gt;

&lt;p&gt;The boring version: own the whole market with a low-cost index fund (VTI, SPY, or your equivalent). You get every company's upside, you're guaranteed to capture the market return, and you save yourself hours of research a year. Warren Buffett literally bet a million dollars that a low-cost S&amp;amp;P 500 index fund would beat a hand-picked hedge-fund portfolio — and he won.&lt;/p&gt;

&lt;h2&gt;
  
  
  The good news
&lt;/h2&gt;

&lt;p&gt;You don't need to be right about the next big thing. You just need to stay in the market, keep fees low, and let compounding do the work. The average person who does nothing fancy almost always beats the person who trades a lot.&lt;/p&gt;

&lt;p&gt;I break down the books that made this click for me over at &lt;a href="https://richreadme.com" rel="noopener noreferrer"&gt;RichReadme&lt;/a&gt; — short, no-fluff summaries of the investing classics.&lt;/p&gt;

</description>
      <category>beginners</category>
    </item>
  </channel>
</rss>
