victoria-like: a Victoria II-style economic sim, and getting killed on Hacker News

4 min read

I am guaging interest in victoria-like, a grand-strategy sandbox inspired by Victoria II. Vic2's economic simulation is the best grand strategy game ever shipped (except for perhaps Capitalism, which I have never actually played). The one problem was unless you had an invitation to a good old fashioned LAN party in your neighborhood, multiplayer has always been unlikely to be an option for Vic 2. That could change with this project.

Put another way, Vic2 was simply a single-player executable, whereas victoria-like is built like a small live service.

The victoria-like world advances on a fixed tick. Runs are deterministic, so replaying the same commands against the same seed reproduces the same world state, which makes bugs reproducible too. Every command is validated before it's applied, and state changes go out to clients over WebSocket. It is a networking-first fan redesign.

Terminal recording of calling the explain endpoints for a good's price, a country's budget, and a province's employment, each returning a human-readable factors list

Today it runs three scenarios (tiny-2country, phase1-albion-server, medium-8country), persists to PostgreSQL with Redis health checks, and survives a restart mid-tick by resuming from the last snapshot. It does not yet have full historical scenarios, or deep diplomacy, or a balanced economy, or a polished Unity UX.

If you want to poke at it:

make up           # start PostgreSQL + Redis
make run-albion   # reset world, load the Phase 1 Albion demo, start ticking
curl http://localhost:5001/api/world/countries

Terminal recording of curling /health, then /api/world/countries, then watching the countries endpoint every second as Albion's treasury ticks down

Albion, tis of thee (how to curl)

I ran the Albion demo scenario locally to grab real output rather than paraphrase it. /api/world/countries — Albion running a deficit, a couple minutes into a fresh world:

$ curl -s http://localhost:5001/api/world/countries | jq
[
  {
    "id": "3626b620-4c9e-427e-81ee-d5f906610d99",
    "name": "Albion",
    "tag": "ALB",
    "tax_rate": 22,
    "treasury": -311.34,
    "province_count": 2,
    "controller_actor_id": "10000000-0000-0000-0000-000000000001",
    "controller_username": "albion-player"
  }
]

Now the explain endpoint for that same country's budget, called a couple seconds later — notice the treasury is already more negative than the line above; the world was still ticking while I copy-pasted:

$ curl -s http://localhost:5001/api/explain/country/3626b620-4c9e-427e-81ee-d5f906610d99/budget | jq
{
  "subject_type": "country_budget",
  "subject_id": "3626b620-4c9e-427e-81ee-d5f906610d99",
  "title": "Albion budget",
  "summary": "Albion treasury is £-314.31.",
  "factors": [
    { "label": "Treasury", "detail": "Treasury is £-314.31.", "impact": "negative" },
    { "label": "Tax rates", "detail": "Poor 22%, middle 18%, rich 14%.", "impact": "info" },
    { "label": "Spending", "detail": "Estimated weekly state spending is £11.44.", "impact": "negative" },
    { "label": "Policy mix", "detail": "Education 55%, military 35%, administration 45%.", "impact": "info" }
  ],
  "metrics": {
    "treasury": -314.31,
    "tax_rate": 0.22,
    "estimated_weekly_spending": 11.438,
    "population": 86000
  }
}

And /api/explain/good/grain, the example from the top of the post:

$ curl -s http://localhost:5001/api/explain/good/grain | jq
{
  "subject_type": "good",
  "subject_id": "grain",
  "title": "Grain price",
  "summary": "Grain is £0.88.",
  "factors": [
    { "label": "Supply and demand", "detail": "Demand 43.00 vs supply 42.00.", "impact": "negative" },
    { "label": "Price pressure", "detail": "Target pressure is 1.02x base price.", "impact": "info" },
    { "label": "Weekly clamp", "detail": "Price movement stayed within normal bounds.", "impact": "positive" },
    { "label": "Largest producer", "detail": "Northshire", "impact": "info" },
    { "label": "Largest consumer", "detail": "Northshire", "impact": "info" }
  ],
  "metrics": {
    "price": 0.88,
    "previous_price": 0.8840595238095238,
    "price_delta": -0.00405952380952381,
    "supply": 42.0,
    "demand": 43.0,
    "fulfillment_rate": 0.9767441860465116,
    "pressure": 1.0238095238095237
  }
}

That reminds me, the US is 40 Trillion dollars in debt. We should do something about that...

A detour: getting killed on Hacker News

I posted this as a Show HN, and within minutes it was dead.

"Dead" on HN doesn't mean downvoted into oblivion by readers — it means the post is invisible to normal visitors entirely. Hit the link as a logged-out reader and you get a page with no title, no text, nothing — same experience as a broken URL. The API confirms it plainly: fetching https://hacker-news.firebaseio.com/v0/item/<id>.json returns "dead": true with a score of 1 (just my own submission vote) and no title or url field at all.

This is almost never a human moderator acting on your specific post. HN runs an automated filter that's aggressive about brand-new accounts submitting a link — especially a link to their own project, which pattern-matches to spam even when it obviously isn't. My account is fresh, so this is close to the default outcome for a first submission, not a judgment about the content.

Fixing it is a known, two-lane process:

  1. Email hn@ycombinator.com. Link the item, ask them to reconsider or un-kill it. The mod team (dang and others) is generally responsive and reasonable once a human looks at it instead of the filter.
  2. Get vouched. Users with enough karma can flip on "showdead" in their profile, which makes dead posts visible in listings with a "vouch" link. Enough vouches revives the post without mod intervention. If you know someone with a higher-karma account, this is the faster path.

What doesn't work, and will make things worse: asking people to pile on upvotes. HN's vote-manipulation detection is at least as aggressive as its new-account filter, and getting flagged for that is a much deeper hole than a routine auto-kill.

I've sent the email. If you're reading this after it landed, the link above should resolve to an actual discussion. If not — well, you can still visit the github directly