GitHub Repo

Let’s see if I can sort out the HyperspaceOperation a bit.

When changing finishInteraction to accept a Transaction parameter, I stopped pushing here:

    private fun replaceTheShip(trans: Transaction) {
        trans.add(ship)
        trans.add(ShipChecker(ship))
        trans.remove(this)
        trans.accumulate(Transaction.hyperspaceEmergence(ship,asteroidTally))
    }

That’s a companion method on Transaction, and it looks like this:

    companion object {
        fun hyperspaceEmergence(ship: SolidObject, asteroidTally: Int) :Transaction {
            return HyperspaceOperation(ship,asteroidTally).execute()
        }
    }

And there’s this helper object:

class HyperspaceOperation(val ship:SolidObject, val asteroidTally: Int) {
    fun execute(): Transaction {
        return if (hyperspaceFails()) {
            destroyTheShip()
        } else {
            Transaction()
        }
    }

    private fun destroyTheShip(): Transaction {
        return Transaction().also {
            it.add(SolidObject.shipDestroyer(ship))
            it.add(SolidObject.splat(ship))
        }
    }

    private fun inHyperspace() = ship.position != U.CENTER_OF_UNIVERSE

    private fun hyperspaceFails(): Boolean {
        return inHyperspace() && hyperspaceFailure(Random.nextInt(0, 63), asteroidTally)
    }

    // allegedly the original arcade rule
    fun hyperspaceFailure(random0thru62: Int, asteroidTally: Int): Boolean {
        return random0thru62 >= (asteroidTally + 44)
    }
}

If we can make this guy accumulate into a Transaction rather than create one, we can unwind this. And I’m not clear at this moment why it seemed right to build the method on Transaction at all, though I remember feeling at the time that it was rather nice. Let’s just push this through.

From this:

    private fun replaceTheShip(trans: Transaction) {
        trans.add(ship)
        trans.add(ShipChecker(ship))
        trans.remove(this)
        trans.accumulate(Transaction.hyperspaceEmergence(ship,asteroidTally))
    }

Extract a temp:

    private fun replaceTheShip(trans: Transaction) {
        trans.add(ship)
        trans.add(ShipChecker(ship))
        trans.remove(this)
        val trans = Transaction.hyperspaceEmergence(ship, asteroidTally)
        trans.accumulate(trans)
    }

Now can we inline the call to Transaction.hyperspaceEmergence?

Yes, resulting in this:

    private fun replaceTheShip(trans: Transaction) {
        trans.add(ship)
        trans.add(ShipChecker(ship))
        trans.remove(this)
        val trans = HyperspaceOperation(ship, asteroidTally).execute()
        trans.accumulate(trans)
    }

IDEA removed the companion entirely. Nice. Now change the signature of execute and push trans down:

class HyperspaceOperation(val ship:SolidObject, val asteroidTally: Int) {
    fun execute(trans: Transaction) {
        if (hyperspaceFails()) {
            destroyTheShip(trans)
        }
    }

    private fun destroyTheShip(trans: Transaction) {
        trans.add(SolidObject.shipDestroyer(ship))
        trans.add(SolidObject.splat(ship))
    }

And call it correctly in ShipMaker:

    private fun replaceTheShip(trans: Transaction) {
        trans.add(ship)
        trans.add(ShipChecker(ship))
        trans.remove(this)
        HyperspaceOperation(ship, asteroidTally).execute(trans)
    }

Tests may fail but I think this is good. Test. All is well. We’re good. Commit: Hyperspace helper object used directly in ShipMaker, Transaction companion removed, accumulates changes into the finish Transaction.

Summary

Small change easily made. Supper time.