Sunday, November 10, 2019

Data Driven Galaxy

I spent a ridiculous amount of time with Galaxy’s singleplayer scenarios, and had some gripes. As with its predecessor Galactic Empires, the early phase is essentially a guessing game. You have no idea how many ships each planet will have, or which planets are valuable to conquer, and so you must guess how many ships you need to conquer each of the nearby planets. If you opt to have neutral worlds build their own ships, then you can’t afford to guess conservatively, nor can you afford to guess wrong, nor to scout and wait for information. Every turn where you aren’t conquering planets is a turn that the planets worth conquering build up their defenses and therefore take that much longer for you to conquer, which has a cascading effect.

Galaxy makes it even worse with a random gunnery factor that rarely flips the outcome of a battle completely in your favor, but often costs you an invasion you should have won.

I was ready to move on, but I had a realization. This is BASIC. I can fix it! And I did. Download my version here:
https://drive.google.com/uc?authuser=0&id=138Q7lb-xGQ88EScZkI3V2ZuiSd-1OxY4&export=download

My addition here is some new options, specifically to address my gripes with the singleplayer scenarios.

The “reveal status” and “gunnery factor” options are my additions.


There is one tradeoff; I had to disable the save/load functionality, because it relies on low-level memory access calls that I don’t quite understand. Not a huge sacrifice, I think, as I’ll just be playing on an emulator where save states work fine.

The “reveal status” option will show you the industrial capacity and number of ships orbiting all neutral planets, eliminating the need to guess or scout. The “override gunnery factor” option disables the random gunnery factor in combat and ensures it will be predictable and equal for both sides. A value of 80 will approximate the firing accuracy in Galactic Empires, while a value of 71 is approximately the mean gunnery factor in Galaxy. Larger values will disproportionately benefit the defenders in any battle.

The fixed gunnery factor does not eliminate randomness from combat; when ships fire, each ship has a random chance to hit a target, determined by this formula:
[Gunnery Factor]/100 * SQRT(Targets/(Shooters + Targets))

So, let’s say you have a gunnery factor of 71, and you send 13 ships to attack a planet which will be guarded by 10 by the time yours arrive. Their 10 defenders will get the first round of shots, and the accuracy will be:
71/100 * SQRT(13/(10+23))
0.71 * SQRT(13/33)
=~ 0.4456


It might seem like we can expect them to kill 4-5 of our attackers on their first volley. However, their 10 defenders will fire in sequence, and with each successful kill, the number of targets decreases, and their shooting accuracy goes down accordingly. In practice, this just means we can expect 4 kills more often than 5. Accuracy is still a random chance; big deviations from the mean distribution aren’t common, but can happen.

With my modified version, I took a crack at the epic 40-world game, to see if I could do it in only 50 turns. I wasn’t hopeful; in Galactic Empires I had failed to do it in 100, but perhaps Galaxy would tip the scales in my favor a bit once I had eliminated the guesswork and could focus on strategy and logistics.





That’s a lot of information to start with. Normally the PROD/SHPS columns would be invisible until the planets were conquered, but now it’s practically perfect information. None of the worlds here had greater production than my starting world, which was good.

Everything went into an Excel spreadsheet, and I used the Time/Distance calculator to get the travel time to each world from A.

From this, my plan:



Indigo circles indicate industrially worthless worlds that I had best left alone until I had some economy going, and most of them best left alone until the endgame. Green and red circles indicated viable planets within a 2-turn’s travel from world A, with the red V being a heavily defended one expected to have 54 ships by the earliest time I could reach it, but also having 8 industry, making it critical to take immediately.

I sent, to each of the green and red planets, a number of ships equal to 130% of the expected defense, rounded up, which incidentally totalled 139, exactly as many ships as world A started with. On the following turn, # fell, and I sent 10 more ships to the lightly defended world $. Then on turn 2, everyone else arrived.



Everyone was victorious, and for the most part narrowly. My calculations were validated! I updated my map.



V was the second-most industrious planet in my empire after A. I figured that V’s ships could capture O, and the 10 new ships from A could take ^. On the next turn I had them and everyone else direct their ships behind my strike fleet toward $, which I planned to use as my new forward base.

There was one unexpected downside of my perfect information mod – previously, with neutral planets’ statuses hidden, picking out my own planets from the list was a cinch. Now I had to scan the list line by line, and be very careful not to miss any of my own.



Sure enough, my fleet took planet $, paving the way for more reinforcements. At this point, no industrious planet was going to be easy to take, except possibly for O and ^ which already had inbound ships.



Turn 5, my first reinforcements arrived at $, and I diverted them toward planets Z and =, while continuing to feed planet $ with the rest of my worlds.



Turn 6, I conquered two more planets, and sent more $ reinforcements toward G.



This expansion continued, though slowed down as the easier planets fell. I was already far past the point where I could conquer multiple planets in a turn by splitting up my fleet; each turn, the total number of ships arriving at $ was, at best, enough to conquer one weak planet, and when it wasn’t enough, I’d have to wait an additional turn for more . One time, an invasion failed, but I was able to conquer its diminished defense force on my next try, so only one turn was wasted.

By turn 20, my map of the galaxy looked like this:





Only five industrious planets left to conquer, one with a fleet inbound, but the remaining four would all have over 120 ships defending them by the time I could send anything their way, and I was only producing 61 ships per turn. At this point, I was also bumping into the 50-order limit, which limited the number of ships I could redirect to the $ world-base per turn.

By turn 25, the galaxy looked like this:





Only three industrious planets were left unconquered, and one had an inbound fleet. Of the other two, L was the tougher, guaranteed to have over 250 by the time I could reach it from my base, with another 9 for each turn spent building more ships or conquering other planets. @ would have over 175, and produced 6 ships per turn. I produced 67 ships per turn.

At this point, I started redirecting my ships toward D, as a new base for assaulting L and @. There were still some ships on-route to $, which on their arrival I split up and sent toward the non-industrious planets farthest from D, as I’d have to conquer them sooner or later.

On turn 27, I took planet J with a fleet of 221 attackers against 170 defenders. There were 34 survivors. I kept funneling my ships toward planet D, as I watched the non-industrious planets fall.

By turn 31, the galaxy looked like this:



Ships were en route to T and @. L remained the big one, with 278 ships, and I was producing 72 per turn. I send out three more small fleets from D to take K, I, and ), but otherwise kept funneling my new ships toward D.

On turn 32, an invasion force of 254 of my ships attacked 190 defenders on planet @, defeating them and capturing it with 31 survivors. World T was also taken, without a fight. I was now producing 78 ships per turn, which I kept moving toward D over the next few turns, as the last few non-industrial worlds fell.

Then, finally, on turn 35, I had conquered every planet except for L. I had 421 ships on D, and there were 314 on L. This turned out not to be quite enough to conquer it, but a mop-up fleet on the next turn was.

Combat on turn 35

Combat on turn 36

Galaxy conquered on turn 37


So amazingly, it is possible to beat the hardest scenario in only 36 turns. With just a bit more luck, it might have been possible to do it a turn or two faster.

This, of course, must come with some caveats. First and foremost, I had perfect information that would normally be denied to me, and so I could plan and execute a well-optimized strategy, and without much risk of my strategy being ruined by an unlucky gunnery factor roll. No time was wasted pursuing barren planets, nor was any time wasted by sending a single fleet against a defense force too big for it to handle. My initial fleet conquered seven industrious planets in the absolute shortest amount of time it was possible to, expanding my ship production abilities from 10 to 33 per turn. In these first few turns it is paramount that everything goes very smoothly, and as unmodified Galaxy shows, there are just so many ways things can go wrong. Even in the mid-game, there isn’t much room for error; you can afford to use scouts if you’re careful, but still can’t afford too many failed invasions, which can always happen if the gunnery factor rolls unfavorably to you.

Secondly, I had a rather lucky galaxy setup.  There were only two especially industrious planets other than my starting one – V and L, and V was inside my immediate reach from the start. If there hadn’t been a hyper-industrious planet attainable within the first few turns, then my early ship-building ability would have been slowed, and my ability to start conquering planets outside of my initial reach would have been delayed, which, again, would have cascaded into more and more delays for each subsequent planet. If there had been a second hyper-industrious planet outside my initial reach, then it would have taken at least 4 turns to capture (as L did), and in the time spent waiting to take it, L would have had time to build up its defenses and would take even longer to capture. Had V been as industrious as it was and also out of my initial reach, then I very much doubt I would have had any chance of winning in only 50 turns.

7 comments:

  1. How about an imperfect information mod? Instead of reporting exactly how many ships or manufacturing is on a planet, fudge it by some random factor.

    ReplyDelete
  2. If I was going to remake this, I would want to build this "fudge factor" in and make it part of the narrative. You receive reports of an ultra-manufacturing planet, but by the time you get there everyone is dead and it is barren, the victim of an Armageddon.
    You pass over a planet that you think is barren, but it turns out to host a species with advanced cloaking technology... Etc.

    ReplyDelete
    Replies
    1. The good news is, you can! With CiderPress, you can extract the code off the disk image, edit it in a text editor, and import it back into the disk image with the "Import BAS from text" option. Or you could edit the code within the emulator itself (it will still be in memory when you quit the game), but the first way is easier.

      The bad news is you'll still have to write code in AppleSoft BASIC, and contend with terse variable names, spaghetti code, primitive debugging tools, a 48kb limit, etc.

      Delete
  3. So I am reaching Galaxy (and will link to you a LOT, since I did not and will not play Galactic Empire. I just wanted to say that a good way to reduce the "imperfect information" is to send 1 ship by planet at the beginning. You will have an exact idea of how strong each world is, which will allow you to have an idea about how productive they are.
    Of course, it only works well in Single Player, and then there is the gunnery factor ^^.

    ReplyDelete
    Replies
    1. The problem is that you really can't afford to wait for the scouts to come before starting your attack. In the above game, it would take two turns for your scout to arrive at planet V, which was instrumental to victory, and then you'd know it has 54 ships. You might conquer it by turn 4, if you correctly guessed it had an industry of 8 or higher and sent enough ships to beat 70, and if the gunnery factor didn't screw you over, but now you're two turns behind, your initial conquest won't have as many planets, you'll be denied two turns worth of ships for each of those worlds, and every other planet in the galaxy will be reinforced two turns' worth. The effect cascades very quickly. If you can beat scenario 9, I'd love to hear how you pulled it off.

      Incidentally, Galactic Empires just shot up into my "popular posts" list. Did you have something to do with that?

      Delete
    2. This comment has been removed by the author.

      Delete
    3. Ah yes, I skimmed through too fast yesterday night, and reading with more attention now I get what you mean. Indeed, you suggest the "scout with 1 guy" strategy in an earlier post, but against worlds with massive production it is not quite enough.
      I probably generated 2 hits yesterday, and 3 hits today (French time) from my different devices.

      Delete