OSR 2d6 Checks for more than Reactions

I propose using 2d6 (+possible ability modifier – possible difficulty) the resolve situations that can not just be role played in OSR games (where ability modifiers are -3 to +3).

General
-4: Failure, with extra negative consequences
-5-6: Failure
7: Partial success or failure with some unexpected twist
8-9: Success
10+: Success, with some extra good outcome

Bluff
-4: Not believed, hostile reaction or plays along
5-6: Not impressed
7: Bluff is not called, but reaction is unexpected (and not in a very good way)
8-9: Bluff is believed
10+: Bluff is believed and target is extra helpful

Breach or Destroy
-4: No success, exhausted some resources (equipment or possibly HP)
5-6: No success
7: Partial success, some malfunction or unexpected side effect
8-9: Success
10+: Success with style or some advantage

Climbing, Swimming
-4: Falling, Drowning
5-6: Did not start, had to go back if previously made progress
7: Some progress
8-9: Reached goal
10+: Reached goal in style or with some advantage

Fish, Hunt & Gather Food
-4: Found nothing eatable, exhausted some resources (possibly eating something bad)
5-6: Found next to nothing
7: Found one days ration
8-9: Found 1d4+1 days rations
10+: Found 2d4 days rations

Jumping
-4: Fall
5-6: Hesitate (on retry, -7 is Fall)
7: Partial success if possible, otherwise hesitate (on retry, -6 is Fall)
8-9: Success
10+: Success with style or with some advantage

Luck (like setting an ambush or a bait)
-4: Things turn out very much the opposite of the desired outcome
5-6: The desired thing does not happen
7: Be careful what you ask, you just might get it
8-9: The desired thing happens
10+: Things turn out remarkably well the way it was supposed to

Make item or mechanism
-4: It fails later, or loss of resources/injury immediately
5-6: No success
7: Not quite fit for purpose, 50% chance of malfunction or requires some support
8-9: Success
10: Unexpectedly good result

Make Shelter
-4: Shelter fails later on, loss of resources
5-6: Inadequate, possible loss of resources if used
7: Decent shelter if something is paid/used/wasted
8-9: Good shelter
10+: Shelter with some benefit

Perform
-4: Failure, making a fool of oneself, possible injury
5-6: No one is impressed
7: Audience is undecided or split
8-9: Good performance
10+: Surprisingly impressive performance, some advantage follows

Recall Knowledge (Lore, History, Geography)
-4: Remembers incorrectly, sure about oneself
5-6: No memory
7: Recall something relevant but not quite useful
8-9: A good general idea about the topic
10+: Knows significant details

Track
-4: The tracked party is aware of being tracked and can choose to escape or ambush
5-6: Lose track
7: Sudden encounter with tracked party
8-9: Localized tracked party at a distance
10+: Undetected, close enough for ambush (or just observing)

Background

Classic OSR games use 2d6 + CHA modifier for Monster Reaction and Retainer Reaction. There are multiple outcomes, not just success and failure.

OSR games don’t really have skills but sometimes things need to be randomly resolved.

Why not using the 2d6 + ability modifier, and comparing to a table of outcomes, not only for reactions? I see some advantages with this. The multiple outcomes drives the story forward in different/random directions, rather than the open/closed gate mechanism of success/fail skill check. Also, the focus is on what the characters want to do in the story, not what skills the characters may have.

A first nice thing about OSR is that things can play out without rolling dice. This is what we call player skill. But occationally I find it unreasonable as a DM to judge the outcome based on the players description on their actions alone. This is where the second nice thing with OSR comes into play: also the DM can be surprised and needs to adapt and improvise.

Difficulty and Ability

The primary purpose of these Reaction-like checks is to produce random reasonable outcomes in significant situations. If the characters are already good (or bad) enough, or the task is easy (or hard) enough to simply decide the outcome, no dice should be rolled at all. Thus, the default is that the DM and the players do not really have any real insight into the probabilities of different outcomes (it would suffice to roll 1d5 with no modifier).

It is not necessary to add an ability modifier. It is not like it is the right of the player/character to add a strong ability score. DM shuld not consider difficulty much and probably most of the time should not add difficulties. After all, the purpose is to take the story in an unknown direction.

Thieves/Rogues

Thieves (or Rogues) have skills of their own. Those are not to be replaced or made redundant by above rules. If a fighter can climb a wall using these rules the thief probably succeeds automatically, and if the thief needs to roll for his special ability no other class need to even attempt.

Custom Outcomes

Obviously nothing stops you from defining your custom outcomes for a specific situation, in advance or when the situation comes up. Something like:

-7: Sentenced to death by hanging next morning
8: Queen approves (back to prison)
9-10: King approves (back to prison)
11+: Both Queen and King approves (released)

Other options

There are options to rolling 2d6 + ability modifier.

  • 1d6 + modifier (which is seen in B/X for kicking open doors for example): gives very much significance to the ability score and not too many possible outcomes.
  • 1d12 + modifier: I have never seen it but it could work just as well.
  • 1d20 + modifier: gives too little significance to modifier in my opinion, and creates longer more arbitrary intervals of outcomes. Also the natural 1 and 20 are very uncommon and I prefer more variation in results more often.
  • 1d20 under ability value: feels too much like BRP to me.
  • 3d6 under ability score (as for Phantasmal Killer in 1e): Mostly just produces two outcomes and feels overly complicated

So I think 2d6+modifier makes sense, and it is established in old D&D versions (also for Clerics Turn Undead). The BECMI employer reaction table (Rules Cyclopedia, p132) looks like:

2: Resuse, insulted
3-5: Refuse
6-8: Roll again
9-11: Accept
12: Accept, impressed

This scale makes the middle results much more likely and the extreme results less likely than the scale I have proposed above. I think “6-8 roll again” (that will be almost 50% of the cases) is not optimal. The scale I propose leaves more of the options more likely, even when an ability modifier is applied.

If you really prefer 1d20+mod to 2d6+mod, I propose:

-4: Failure, with extra negative consequences
-5-9: Failure
10-11: Partial success or failure with some unexpected twist
12-16: Success
17+: Success, with some extra good outcome

Testing Paul John whisky

First check out my general whisky tasting list.

I got a Paul John whisky tasting kit. There are five whiskies, one is peated, so I will start with the other four, here listed in preference order

  1. Edited
  2. Bold
  3. Classic Select (cask strength)
  4. Brilliance

Brilliance vs Edited
Color: Edited is darker, I would say both are quite pale
Nose: I like brilliance, fresh and malty perhaps with sweet citrus to it. Edited is a different story: leather, oil and dirt, not bad at all, but more challenging.
Mouth: Brilliance tastes very young, a bit raw wood and strange sweetness. Also Edited tastes quite much wood, quite light compared to what I expected after smelling it.
Winner: Very comparable quality, I pick Edited.

Bold vs Classic Select
Color: Classic Select is darker, also after being diluted
Nose: Bold is a bit leather, sweet, quite subtle, somthing perhaps tropical about it. Classic select, at first I was confused but it has a more classic bourbon aroma, with something young/sour about it.
Mouth: Bold taste as it smells, young wood and leather. It has a long lingering woody/metallic taste. Classic select is clearly sour in the mouth (I cant write fresh).
Winner: Bold wins.

Edited vs Bold (for Gold)
Color: Very similar
Nose: Bold is heavier, young wood, not necessarily a good thing. Edited is more classic (scotch). Quite similar.
Mouth: Both tastes decent but quite immature, Edited is the more soft and sophisticated one.
Winner: Edited.

Brilliance vs Classic Select (for Bronze)
Color: Classic Select is darker.
Nose: Brilliance very light, fruity like citrus with something unusual tropical about it. Classic Select more sweet, and back to Brilliance it is more raw/wood.
Mouth: Quite much bourbon in Classic Select now, Brilliance is unrefined wood and fruit.
Winner: Classic Select

Paul John vs Other Whisky

Bold vs Johnny Walker Gold
Color: JW darker
Nose: JW is more mellow and oily, Bold more tropical/raw wood and spicy
Mouth: Bold is more rough, young, fruity. JW sweeter, richer, softer and more complex.
Winner: JW wins.

Brilliance vs Mackmyra Brukswhisky
Color: Brilliance is darker
Nose: Brilliance has a woody, sour aroma (with good intentions some citrus fruit). Mackmyra is a little sweeter, more honey, and less agressively woody.
Mouth: Brilliance is really sour, with a dry wood lingering. Mackmyra a bit softer but also more bitter.
Winner: These are bad in different ways, with a bit of doubt, I prefer Paul John Brillance.

Edited vs Johnny Walker Gold
Color: JW is darker
Nose: JW is more oily, leather and dirt. Paul John is lighter, more sour (not writing fresh) and raw wood.
Mouth: Edited is quite classic malt whisky, a bit raw. JW a bit chemical and odd-tasting.
Winner: With little margin, Paul John Edited wins.

Edited vs Glenfiddich 12
Color: Same color
Nose: Glenfiddich is more dry, salty and malty. Edited is more sour raw wood.
Mouth: Glenfiddich is more soft and mature. Edited is more rough, unrefined.
Winner: Glenfiddich 12.

Classic Select vs Motörhead
Color: Motörhead is darker
Nose: Both a bit on the fruity and sweet side. Motörhead more soft and subtle, John Paul more raw wood.
Mouth: Motörhead quite sweet, soft and gentle in flavour, John Paul a little bit more kick, and more odd and woody. I add more water to it.
Winner: I prefer Motörhead: more classic and soft.

Brilliance vs Bushmills Original
Color: Similar, both pale
Nose: Bushmills lighter, Brilliance more terpentine.
Mouth: Bushmills more delicate and complex. Brilliance more sour and raw.
Winner: I prefer Bushmills.

Bold vs Makers Mark
Color: Markers Mark much darker
Nose: Makers Mark is sweeter, perhaps even lighter. Bold is a bit dirtier and oilier.
Mouth: Makers Mark has a strong bourbon character and at least I need water with it. Bold is quite classic in comparison. Back to Makers mark it is softer with water but still this strong bourbon flavour is an aqcuired taste (and it tastes like glue).
Winner: Bold is better.

Classic Select vs Crown Royal Rye
Color: Same
Nose: Crown Royal has a sweet fruity aroma with some flowers. Classic select is a dirtier, woodier experience.
Mouth: Crown Royal definitely has a bourbon flavour, spiced with flowers and fruits. Paul John is rougher and more tropical wood.
Winner: Crown Royal

Bold vs Jim Beam Rye
Color: Jim Beam slightly darker.
Nose: Paul John has a classic, somewhat oily, almost peated aroma. Jim Beam is bourbon, vanilla.
Mouth: Paul John has a quite classic flavour as well, a bit thin, sharp and raw. Jim Beam is very spicy in its bourbon way. In comparison Paul John is rather soft.
Winner: Paul John wins.

Bold vs Bushmills 10
Color: Bushmills a little paler
Nose: Bushmills is light fruits, like green pears. Paul John really smells heavy and solid.
Mouth: Bushmills light and soft in flavour, flawless but without much of an impression. Paul John is heavier, more of an acquired taste.
Winner: Paul John

Edited vs Chivas Regal 12
Color: Similar
Nose: Chivas Regal is lighter, best thing I can write is classic. Edited dominated by young wood, a bit tropical.
Mouth: Chivas is very classic and balanced. Edited has a little bit more kick, more dry young wood and more character. After Edited, there is something cheap blend about Chivas.
Winner: Chivas Regal (Paul John is too odd to me)

Paul John Peated Select Cask

I think what I have experienced as raw wood in a bad way for unpeated Paul Johns work out better with the peated one.

PJ vs Bowmore 12
Color: PJ a little paler, and also cask strength.
Nose: PJ has a soft, fruity peated aroma, quite pleasant. Bowmore a bit more oily and malty.
Mouth: I try PJ first at cask strength and it is distinctively peated. I try Bowmore and there is something unatural chemical about it, and I simply dont find it very tasty. Paul John is more fresh and coherent.
Winner: Paul John.

PJ vs Laphroaig 10
Color: Similar, Laphroaig perhaps slightly darker.
Nose: Laphroaig is more dry, PJ more fruity.
Mouth: Laphroaig has a rather smooth and dry, obviously dominated by peatiness. PJ is less integrated, it has a sweet – not bad – experience which kind of competes with the peat. PJ is interesting and not bad, but Laphroaig is more rich, complex and lingering.
Winner: Laphroaig

PJ vs Mackmyra Reserve Svensk Ek Extra Rök
Color: Mackmyra is much darker
Nose: Mackmyra is more deep, rich and powerful. Paul John is more fruity. Both smells a bit like a dry piece of wood getting burnt in a machine saw. Mackmyra reminds more of a sweet wine and Paul John is more odd.
Mouth: PJ (almost at cask strength) is rather raw with some peat. Mackmyra also raw, perhaps more smoke than peat, and a bit sweeter. PJ is lighter and its flavour disappears a bit in comparison with Mackmyra. Mackmyra on the other hand keeps needing more water. With more water Paul John has a more burnt (rather than raw) flavour, a quite straight experience but not too impressive. Mackmyra is more rich, complex, with more woody notes and it lingers longer.
Winner: Mackmyra

PJ vs Hven Tychos Star
Color: Hven is darker
Nose: Hven is a bit softer, PJ is a bit more woody in a sweet burnt way
Mouth: Hven is a bit classic, with some sour peat and some bitterness. Paul John is sweeter and fresher.
Winner: Paul John

PJ vs Bunnahabhain 8 Heavily Peated
Color: Similar
Nose: Very different, Bunnahabhain smells old closet and Paul John like a freshly built piece of furniture.
Mouth: Bunnahabhain is smoth, rich, a bit salty and lingering. Paul John is rather raw and thin.
Winner: Bunnahabhain

Simple Loops in JavaScript

I let SonarQube inspect my JavaScript code and it had opinions about my loops. I learnt about the for-of-loop. Let us see what we have.

Below four loop-constructions are for most practical purposes the same.

  // good old for-loop
  for ( let i=0 ; i<array.length ; i++ ) {
    const x = array[i];
    ...
  }

  // for-in-loop
  for ( const i in array ) {
    const x = array[i];
    ...
  }

  // for-of-loop
  for ( const x of array ) {
    ...
  }

  // forEach
  array.forEach((x) => {
     ...
  });

Well, if they are all practially the same, why bother? Why not pick one for all cases? Well, in the details, they are different when it comes to

  • simplicity to write / verboseness
  • performance
  • flexibility and explicitness

Lets discuss the loops.

The good old for-loop

The good old for-loop requires you to write the name of the array twice, and you need to explicitely increment the loop variable and compare it the length of the array. This is very easy, but it is possible to make silly mistakes.

In many/most cases it is unnecessarily explicit and verbose. However, as soon as you want to do things like:

  • skip first, or any other element
  • access several items in the array each (most commonly adjacent items: 01, 12, 23, 34, 45)
  • break / continue
  • modify the array – even the length of it – during the loop
  • sparse arrays, with undefined, it is obvious what you get

this becomes very natural with the good old loop. Doing it with the others will make it appear a bit contrived or the result may not be so obviously correct.

There is also something very explicit about the order. It may be true (or not?) that every implementation of JavaScript will always execute the other three loops in order. But you need to know that, to be absolutely sure, when reading the code. Not so with the good old for-loop. If order is a critical part of the algorithm and you may want to be explicit about it.

This is also the fastest loop.

The for-in-loop

for-in enumerates properties and loops over them. Do not use it for arrays:

  • it makes more sense to use for-in for Object, so the reader of the code may think your array is an object
  • are you 100% sure your array has no other enumerable properties, ever?
  • performance – this is by far the slowest loop
  • it is quite verbose

The for-of-loop

The for-of-loop is a bit “newer” and may not work in old browsers or JavaScript engines. That can be a reason to avoid it, but even more a reason why you do not see it in code you read.

I would argue this is the most practical, clean and simple loop, that should be used in most cases.

It is slightly slower than the good old for-loop, but faster than the other alternatives.

Array.forEach

I have been ranting about functional style code elsewhere. forEach is kind of an antipattern, because it is a functional construction that does nothing without a side-effect. A functional way to do something non-functional.

The callback function gets not ONE argument (as shown above), but actually 4 arguments. If you pass some standard function into forEach that can give you very strange results if the standard function happens to accept more than one argument and you did not know or think about it.

You get both index and array, so you can do horrible things like:

  array.forEach((current,i,array) => {
    const last = array[i-1];
    ..
  });

I have seen worse. Don’t do it. Functional programming is about being clear about your intentions. Use a good old for loop, or write your own higher-order-loop-function if you do the above thing often.

According to the documentation forEach loops in order. JavaScript is singlethreaded. But other languages may parallellize things like forEach, so I think the right way to think about forEach is that order should not matter. Best use for forEach are things like:

  ['gif','jpg','png'].forEach(registerImageFormat);
  players.forEach(updatePosition);

forEach is slower than the good old for-loop and for-of.

Sparse Arrays

I made an experment with a sparse (and worse) array:

  const array = ['first'];
  array[2] = 'last';
  array.x = 'off-side';
 
  let r = 'for';
  for ( let i=0 ; i<array.length ; i++ ) {
    r += ':' + array[i];
  }
  console.log(r);
 
  r = 'for-in';
  for ( const i in array ) {
    r += ':' + array[i];
  }
  console.log(r);

  r = 'for-of';
  for ( const x of array ) {
    r += ':' + x;
  }
  console.log(r);
 
  r = 'forEach';
  array.forEach((x) => {
    r += ':' + x;
  });
  console.log(r);

The output of this program is:

  for:first:undefined:last
  for-in:first:last:off-side
  for-of:first:undefined:last
  forEach:first:last

If this surprises you, think about how you code and what loops you use.

Performance

For a rather simple loop body here are some benchmarks

~160 M loopsMacBook Air 2014
node 14.16.0
RPI v2 900MHz
node 14.15.3
i7-8809G
node 12.18.3
i7-8809G
node 14.16.0
for ( i=0 ; i<array.length ; i++ )280ms3300ms200ms180ms
for ( i of array )440ms6500ms470ms340ms
for ( i in array )6100ms74000ms5900ms4100ms
array.forEach560ms10400ms480ms470ms

On one hand, a few milliseconds for a millions loops may not mean anything. On the other hand that could be a few milliseconds more latency or UI refresh delay.

Benromach: 7 wood finishes

I got the opportunity to try 7 different Benromach, all quite young, matured (finished) on different types of wood and casks. This is the result, from best to worst.

  1. PX Wood: 2002-2010
  2. Port Wood: 2000-2012
  3. Madeira Wood: -2008 (7YO+)
  4. Sassicaria Wood: 2002-2009
  5. Hermitage Wood: 2001-2010
  6. Pago Capellanes Picay Wood: 2002-2009
  7. Tokaji Wood: -2006 (5YO+)

In conclusion I can say I am quite unimpressed. All were quite thin in flavour and many had a significant taste of sulphur. There was little classic malty character overall. I also note that the commonly used casks/finishes ended up winning, and the more odd woods failing.

I actually blind tested these whiskies.

First round

In the first round I randomly picked 3 pairs of whisky (the last 7th bottle did not participate in the first round). This is the quarter finals.

Hermitage vs Port
Color: Same color.
Nose: Hermitage is more sweet and like desert wine. Port is less sweet and not peaty, but a hint in that direction. Mouth: Both tastes a bit of sulphur. Hermitage is thin, not very nice. The Port could pass as a light sherry matured whisky, it is richer.
Winner: Port.

Madeira vs Tokaji
Color: Madeira little darker.
Nose: Madeira is sweet classic sherry, a bit thin. Tokaji is thin, a bit fruity and a bit sour.
Mouth: Madeira is sweet, soft with a bit of caramel. Tokaji has much sulphur, quite dry wood and sour.
Winner: Madeira.

Sassicaria vs Pago Capellanes Picay
Color: Pago C a little darker.
Nose: Sassicaria smells wine in an elegant way, a little malty. Pago C has a woody sour smell.
Taste: Sassicaria is soft, balanced with a hint of sulphur. Pago C has much sulphur and is a bit rough wood.
Winner: Sassicaria.

Round 2

In the second round I let the 3 winners and the untested (PX Wood, by chance) whisky compete in semi finals. I randomly picked the two matches and blind tested.

PX vs Sassicaria
Color: Perhaps PX is slightly more pale.
Nose: PX has a wine/fruit aroma with a hint of sulphur. Sassicaria a bit sweeter and a bit malty.
Mouth: Both have some sulphur. I find PX a little fruity and salty, while Sassicaria is more dull.
Winner: PX

Madeira vs Port
Color: Port is darker
Nose: Both have an elegant wine and fruit aroma. Madeira a bit softer.
Mouth: Port is balanced with raisin and caramels, hint of sulphur. Madeira is lighter, more balanced and a little bit more rough.
Winner: Port.

I also randomly picked 2 of the 3 losers from round 1 and did a blind test between them.

Hermitage vs Pago Capellanes Picay
Color: Hermitage a bit paler.
Nose: Hermitage has en elegant wine aroma. Pago C is rougher with much sulphur.
Mouth: Hermitage has somewhat malty and balanced flavour, with some sulphur. With water it becomes quite decent but rather dull. Pago C has much sulphur and tastes immature. It is softer with more water, but still not good.
Winner: Hermitage.

Round 3

In round 3 we have the final, the game for 3rd place, and the game for (avoiding) last place.

Tokaji vs Pago Capellanes Picay (the two worst)
Color: Tokaji slightly paler
Nose: Tokaji sour and sulphur. Pago C more mellow.
Mouth: Tokaji mostly tastes sulphur and is disgusting. Pago C is somewhat softer, also mostly sulphur.
Winner: Pago C (I wasted most of both in the sink after deciding the winner)

Sassicaria vs Madeira (for the Bronze – I thought, see below)
Color: Similar
Nose: Sassicaria is like dry wine. Madeira is more fruity and sweet.
Mouth: Sassicaria has much sulphur, also some malty caramel. Madeira is more balanced with less sulphur.
Winner: Madeira

Port vs PX (for the Gold)
Color: Port is darker
Nose: Port smells raisins and little caramel. PX more balanced wine.
Mouth: Port is thin, with a hint of sulphur, but quite good. PX is caramel, little malt, and a hint of sulphur.
Winner: PX (with small margin)

Extra Round

I had to settle position 3 and 4. I blind tasted these two.

Madeira vs Hermitage
Color: Hermitage slightly darker
Nose: Some more fruitiness in Madeira, Hermitage more powerful, not necessarily a good thing.
Mouth: Madeira is with some reservatation a decently tasty whisky. Hermitage is a sulphur stinking rought mess.
Winner: Madeira (as already predicted in the original Bronze match).

Other Whisky

I will compare these 7 whiskies to other whisky. Check out my full head to head whisky list.

Benromach PX vs Glenmorangie Quinta Ruban
Color: Glenmorangie is darker.
Nose: Glenmorangie is fruitier, like peach or something sweet, and more rich and soft. Benromach more like a sherry whisky and with a hint of sulphur.
Mouth: Benromach is not exactly soft and rich, but somewhat balanced, with a hint of sulphur. Glenmorangie is more sweet, more soft, less sulphur. However, they are quite similar.
Winner: Glenmorangie Quinta Ruban.

Benromach Madeira vs Bushmills Banyuls
Color: Banyuls is darker.
Nose: Banyuls is sweeter, more bourbon. Benromach is more wine and sour.
Mouth: Bushmills richer, sweeter and more powerful. Benromach rather thin and dry in comparison. Bushmills, with more flavour, also has more of a lingering sulphur.
Winner: Bushmills Banyuls

Benromach Tokaji vs Grants
Color: Tokaji darker
Nose: Grants smells light malt and vanilla, Benromach something more undefined.
Mouth: Grants tastes light malt and vanilla. Benromach richer, more sweet/sour. Grants is softer, more chemical.
Winner: Grants (never appreciated Grants so much before, but it was quite close)

Benromach Hermitage vs Grants
Color: Hermitage is darker
Nose: Grants more vanilla and malt, Benromach more like sour desert wine.
Mouth: Grants kind of synthetic, Benromach somewhat balanced sweet and fruity.
Winner: Benromach (for more flavour and more interesting, Grants would have been the safe choice if I was offered a drink).

Benromach Tokaji vs J&B:
Color: J&B paler.
Nose: Benromach some undefined sherry fruity character, J&B mostly synthetic.
Mouth: Both tastes like cleaning products. J&B more soft and sweet. Benromach more acid.
Winner: Benromach (there is some interesting whisky flavour in it, but J&B is the safe choice).

Benromach Port vs Bushmills Banyuls
Color: Same (quite dark)
Nose: Benromach quite light fresh wine, after a while a bit more oily. Bushmills caramel and vanilla sweet, more powerful.
Mouth: Benromach quite sweet, a bit rough but also with some quality fruity flavour and sweetness, and a hint of sulphur lingering. Bushmills more sour, rougher, less flavour and more sulphur.
Winner: Benromach

Benromach Port vs Dalmore 10 Vintage:
Color: Very similar (dark)
Nose: Both quite thin, Benromach more raw cask sulphur and fruity, Dalmore more classic but something odd synthetical about it.
Mouth: Dalmore has a thin, sweet classic flavour. Benromach seems raw and unrefined.
Winner: Dalmore

Benromach PX vs Dalmore 10 Vintage
Color: Dalmore slightly darker
Nose: Benromach a bit more raw and fruity, Dalmore more classic yet synthetic
Mouth: Benromach rougher, Dalmore softer. The synthetic thing in Dalmore is probably some funny wood remains.
Winner: Dalmore

Tokaji vs Johnny Walker Red Label
Color: Very similar
Nose: Red Label very light, a bit ethanol. Tokaji more sour (and some sulphur I would say)
Mouth: Red Label soft, not very much flavour, a bit honey. Tokaji is sour, rough and with a significant sulphur lingering.
WInner: I prefer Red Label.

Port vs Paul John Brilliance
Color: Paul John is paler.
Nose: Paul John is quite light, a bit fruity, and not so little raw wood. Benromach Port is more oily and heavy.
Mouth: Paul John is a bit dry in the mouth, yet sweet, some bitterness. Benromach is heavier, more flavour, perhpaps softer but also more sulphur. I add water to both, Benromach gets softer but Paul John gets thinner with more wood.
Winner: Benromach Wins

PX vs Paul John Classic Select
Color: Benromach a little darker
Nose: There is more sherry character (with a hint of sulphur) to PX, and a more woody character to Paul John.
Mouth: Classic Select is more soft (classic even), PX rather rough immature sherry.
Winner: Paul John.

Sassicaria vs Johnny Walker Red Label
Color: JW a little paler, or at least less reddish.
Nose: JW is light, a bit chemical. Sassicaria a bit fruit and a hint of sulphur.
Mouth: JW is soft and tastes reasonably good. Sassicaria has much sulphur.
Winner: JW Red Label.

Conclusion

This are all thin, immature whiskies mostly with sweet flavour. They are not particularly soft, and unfortunately sulphur is the common theme here.

Workers & Resources: Soviet Republic

I started playing WRSR. Here are some findings I made.

Antonopol

My first republic started with a zero population, and I started building a coal mine, coal power plant close to the NATO-border with the intention of exporting electricity for dollars.

  • Coal Power plants use Coal, not Coal Ore. I ended up importing Coal, not using the Coal Ore of the connected mine, for a long time without realising my mistake.
  • It is imperative to make sure there are always enough worker in your Coal Power Plant.
  • Dollars are nice, but a positive Rubles cash flow is probably a better thing to aim for first.
  • A central heating station does not use very much coal. Completely unecessary to connect it to a mine, or as I did, build a railway to it.
  • Trains have huge capacity, and it can be tricky to make them load/unload/leave as you want.
  • Since I intended to have plenty of electric power I used electric trains. You can probably save money going with cheaper lines and locomotive in the early game.
  • Kindergarden, after a while it is not enough with one.
  • Buses: I build one residential village, with one bus station. From there I built bus lines to my specific industries and mines. The workers get on the first bus that arrives, regardless where it goes! For the moment I think each bus line should first go to a small important work place (such as the powerstation) and after that to a large less important work place (such as a mine). That should maximise the chance that your key workplaces are well supplied with well educated workers (this needs to be tested).
  • Electricity: perhaps it is better to just import electricity from the soviet border (and start your republic with some factories importing raw materials).
  • Starting with population is probably a better thing. It seems you get “dormant villages”, with a church that you can otherwise not build, that is probably quite fine.

Bokovskopol

My second republic starts with some villages. Trying a Coal/Iron/Steel economy.

  • Trying to supply 2 power plants and 1 steel mill with Coal, I ended up in a situation where the power plants were not properly supplied and regularly had to buy Coal.
  • If two trains load Coal the same resources at the same aggregate loading, both may be half full, and none ready to leave.
  • If connecting a power plant and an aggregate loading to the same Coal processing plant, there is a risk that the powerplant will be starved by the loading trains, despite there is product.
  • It is tempting to use trucks instead of trains, perhaps easier, but I am not sure it was so smart.
  • It is fine to start importing electricity from your neighbour. But you can’t import that much from a single neighbour. If you build a refinery you may realise that you soon need more power.
  • Don’t forget walking paths!

Caterinagrad

I try an Oil-empire relying on imported energy (for a while). Starting close to the Soviet border where there is both electricity and railroad, and in an area with many oil resources seems good.

  • Bauxit Mines benefit much form buying excavators!
  • You can chain aggregates and storages to essentially make them larger. You still need to plan, and perhaps plan for the future.
  • When you build an advanced industry like a refinery or an aluminum plant, it will take long time before you have scaled up to full resource input and full work force. Make sure you always have all input resources available.
  • When borrowing money you start paying back immediately. So you cash flow will be bad, and you must likely need to borrow more money to repay the first loan. I tend to borrow money monthly, enough for paying back my old loans and for the investments I need.
  • Refineries are good
  • Trains are good, and not weather dependent a trucks
  • Heating stations (and other essential buildings) should be allowed to buy their inventory if you fail to supply yourself.
  • Stockpile everything you consume and produce in industries. It is rather cheap. A steel mill requires power, people, coal and iron at the same time. Don’t be out of coal or iron.
  • Have many gas stations and technical services.

Dorkutsk

Dorkutsk is a Nuclear republic exporting electricity. After 5M Rubels of investments on an empty map I have what it takes to run a single reactor nuclear power plant on full power and export electricity for profit.

Tasting Johnny Walker

For a while I have been trying whisky head to head, all kinds of whisky, writing notes and making a ranking.

I came to wonder, why is blended whisky not as good as single malt? For the same money of course. I mean, a master blender can make a whisky from all the destilleries he wants following fewer rules, than someone making a single malt. The master blender should be able to produce a better product for the same money.

Is single malt really better? Better value?

I decided to buy a range of Johnny Walker blends: Red, Black, Gold, 18YO and Blue. I will try them head to head against single malts in the same price range (except for JW Red).

Here follows my head to head tasting notes. For the ranking, I am including Johnny Walker in my regular list (linked above).

JW Red Label vs J&B: I do a blind tasting. B is paler than A. B smells just lika a blend and very little of what I appreciate with whisky. A is marginally better, or I am just fooled by the darker color. I taste A, and I dont find it that bad. Over to B, it is worse, definitely. Back to A, it is not good, but it has something. A wins, and i guess it is JW (and it was).

JW Red Label vs Grants: Very similar color, perhaps Red being slightly darker. On the nose, very similar, perhaps Grants smells more like a real whisky. Also, in the mouth, there is something about Grants that convinces me more. Yes, Grants is more like the real thing, and I like it better.

JW Red Label vs Talisman: JW much darker in color. There is something about the aroma that makes me prefer the slightly softer and less chemical RW. Yes, it is the same with taste, JW is somewhat richer and softer and less chemical.

JW Black Label vs Old Pulteney 12: If I buy these today in my store they are exactly the same price. They are both 12YO. I blind taste. One (B) is more dark and red in color, the other (A) a bit more pale and brown. Not so much difference. Putting both to my nose I was sure both were Black Label! So it is not that easy to pick out the single malt. A, the slightly more pale whisky, has a richer, more complex and more soft creamy caramel aroma. B smells more alcohol and I find it harder to identify anything particular. I taste B, it is a bit salty, quite soft, a some bitterness lingering. I taste A, and it has a much more particular flavour: nutty and creamy, less balanced and subtle. Over to B again, it strikes me as somewhat peated and smoked.

I feel very confident that B is Johnny Walker. And I was correct.

Apart from the taste itself, Johnny Walker is a different experience to drink. It is first peated on the nose, it then comes softly into the mouth, grows and fades away. It is all very orchestrated. Old Pulteney is more raw and unrefined, yet soft, but perhaps not so balanced. If someone told me: they are the same price because they are equally good, that would be a bit of a relief actually.

But my rules are; there has to be a winner. And I choose Johnny Walker. First the elegant experience from the first smell to the final lingering taste. But it is also a very solid whisky with character: salty and a hint of peat, not a sweet sellout. Old Pulteney is tasty – definitely, but there is something experimental about it compared to the confidence of Johnny Walker.

I sometimes write “as blend” as a negative about aroma or taste. Whatever that is, Johnny Walker Black Label did not have (much) more of it than Old Pulteney 12.

JW Black Label vs Deanston Kentucky Cask Matured: JW much darker. Deanston has a soft vanilla and bourbon aroma, and JW is a bit thin, on the dry peated side. Deanston also has a soft vanilla and bourbon flavour. Black Label is, not sweet but not so much else. I find this Deanston delicate but thin, and yet the salty/peaty JW is even thinner. I enjoy Deanston more, in every way.

JW Black Label vs JW 18YO: Similar color. Both rather subtle on the nose, Black Label a bit more sour and salty, 18YO a bit more sweet. Same goes for the taste, and first impression is that they are equally complex and rich in flavour. I could say that these are equally good: Black Label is for those who prefer rough salt and peat, and 18YO is for those who prefer sweet flavours. But I think 18YO is better – unless you are looking for peat and roughness.

JW Black Label vs Glenlossie 9YO General Custard: JW very much darker. JW has a salty, slightly peated dry aroma. Glenlossie, light, malty vanilla and a bit pear. Tasting Glenlossie it balanced, a bit subtle, with not so dominant flavours. JW is surprisingly peated, very soft, oily and rich. I think I prefer Black Label.

JW Black Label vs Longrow 13 Red: Very similar color. Longrow has a rough aroma, salt and sea. Over to JW it is a bit candy and kind of sweet. Tasting Longrow a bit peated in a sour way, rich also a little margarine. JW is a bit dull and not quite up to it. Longrow wins.

JW Black Label vs Highland Park 10 Viking Scars: JW darker in color. HP is malty, fresh, light and a bit peated on the nose. JW is more heavy but more subtle. HP tastes good, quite light, dry in the mouth, with some sweetness. JW is soft with distinct peat flavour, but it is more anonymous and uninteresting. HP wins.

JW Gold Label vs Glenfiddich 15 Solera Reserve: Again, these are exactly the same price in my store, and I am doing blind tasting. Color is probably identical, perhaps (A) is somewhat darker. A has a soft, sweet aroma, but B perhaps even more so. They are quite similar. Very similar. Well, I find B more fruity and fresh. A is a bit thicker – that could be more Sherry – which someone else could prefer while I dont. From smell and prejudice only, I would guess JW is A. Lets taste. A is surprisingly dry, perhaps not salted but a littler bitter – I would have expected a sweeter flavour. B is more of an explosion of flavours in the mouth, also some lingering bitterness. Back to A, I am not so impressed, a bit metallic in my mouth. And over to B, it is rather soft and fruity. Yes, I am quite confident now, that A has quite much blend character and that it is JW, and B is Glenfiddich. B wins in any case.

And it turns out I was right. Glenfiddich wins.

JW Gold Label vs Balvenie 12 Double Wood: Again, exactly the same price, but no blind test this time. Very similar color. Balvenie has a soft, kind of nutty and malty aroma, while JW has something alcohol/blend and sharp about it. Tasting both, I definitely find Balvenie easier to enjoy. Balvenie is more malty and full in the mouth, JW is a more sour, bitter and closed experience.

JW Gold Label vs Jameson Black Barrel: JW slightly paler. Jameson has a sweet smooth caramel-bourbon aroma. JW is more subtle, and more dry. It is the same when it comes to flavour, and the difference in character is so massive that it is hard to compare. In the end, there is something sweet and naive about Jameson and the more sophisticated JW wins, a narrow victory.

JW Gold Label vs Glenmorangie 10: JW much darker. JW is also heavier and more oily on the nose. Glenmorangie is more vanilla and caramel. They taste surprisingly similar. JW has a bit more of leather/oil flavour and also some more bitternes. Glenmorangie is softer and richer in flavour, and it wins (and it kind of wins the soft/sweet game of blended gold label).

JW Gold Label vs Balvenie 14 Caribbean: JW is slightly darker. Balvenie has more bourbon aroma, JW is more leather and oil. It is kind of the same when tasting them, Balvenie is the sweeter and softer, Gold Label has more character. Unless all you want is soft and sweet, JW is the better and more interesting whisky.

JW Gold Label vs Glenfiddich 12: Isn’t this the comparision of giants? Glenfiddich is a little paler. First impression is that Gold label has a thicker and more oily aroma, Glenfiddich is more subtle dry malty aroma. Glenfiddich is simple yet excellent in the mouth. JW has that oily, leathery, dirty kick (like Loch Lomond) – it is a surprisingly dominant characteristic for a blend like this. This is very close. JW is sweeter, thicker, richer. Glenfiddich is fresher, saltier and more complex. I personally prefer Glenfiddich, but I somehow have a feeling that I fail to appreciate why JW is the better whisky. But I like fresh and salt, so Glenfiddich it is.

JW Gold Label vs Glen Moray: JW a bit darker, and on the nose a bit oily, dirty, and almost peated. Glen Moray lighter, fruitier, a classic malt aroma. Tasting Glen Moray, it is rather dry and it lingers quite nicely. But it is rather sublte and very balanced. JW a bit peated, a little bitter and very balanced. I think I prefer Glen Moray, it is simple and good, and JW simply does not impress and I don’t like the flavour too much.

JW Gold Label vs Nevis Dew Deluxe 12YO: JW is darker. Nevis Dew has a light thin aroma. JW is richer, more oily and more sweet. Nevis Dew tastes surprisingly fresh, sweet and soft (although thin). JW is heavier, dirtier and more bitter in flavour. I prefer Nevis Dew.

JW Gold Label vs Chivas Regal 12: JW darker. Chivas has a soft aroma, mostly vanilla (with caramel and bourbon). JW more powerful, more oily and dirty. I taste Chivas and it is just like smelling it, vanilla and caramel, soft, not much to either like or dislike. But it is easy to drink. Drinking JW more happens, it is actually slightly peated and there are more flavours. It leaves me with an aftertaste of blended whisky alcohol, and I quite don’t like the flavour of it. I prefer Chivas.

JW Gold Label vs Glenallachie 10 Murray McDavid: JW is darker, with a distinctive leather aroma. Glenallachie is a little softer, on the fruity side, and also lighter. I taste JW and I find it soft and quite complex, the problem is that it does not taste so good. Glenallachie is lighter, less rich, also not quite so tasty. This is quite close, but I prefer Glenallachie.

JW 18YO vs Glenlivet 18YO: Again I blind taste, and JW is a bit more expensive. Very similar color. A has a smooth, rich, malty caramel aroma, very nice. After that, B strikes me as a blend: thin and much alcohol smell. I try more with B, and there is a nice subtle sweetness, sure there is. I taste B, it is softly everywhere in the mount, nothing bad at all, and very typical scotch (speyside) malt whisky. I taste A, it is saltier, rougher, less sweet, yet soft. My honest conclusion must be that A is the better whisky. If you just want light, smooth and slightly more sweet you might prefer B. I am quite sure B is JW (and it was).

JW 18YO vs Glenmorangie 10: JW is darker. Glenmorangie is a bit lighter and fresher on the nose, JW is more sweet and deep. Tasting JW I find it quite subtle and delicate (not heavy/rich), but it tastes very very good. Over to Glenmorangie, it is as complex and rich as JW, but JW simply tastes better. It makes Glenmorangie bitter. JW wins.

JW 18YO vs Glenfiddich 18: Same color. Glenfiddich has a more dry (like hay) aroma, and JW is more sweet (like sweet wine). They taste very different (in line with the aroma). JW has a very elegant sweetness and balance. Glenfiddich is like a rebel, tasting artichokes and salt, yet very soft. I prefer Glenfiddich: it makes JW taste bitter and boring.

JW 18YO vs Macallan Fine Oak: JW darker in color and stronger aroma, but more like a blend. Taste is quite similar, but Macallan is rich and soft enough to win.

JW 18YO vs Deanston Kentucky Cask: Deanston is much paler, but it has more aroma: a somewhat spicy and fruity vanilla aroma. JW is more subtle, it comes after a while, mostly elegantly sweet. JW has a soft, malty sweet flavour, very little bitterness and a hint of sweetness. Deanston is more like bourbon, caramel and vanilla, but it is a little bit strange in flavour. Deanston lacks the balance and sofistication of JW, and JW wins.

JW 18YO vs Aberfeldy 16: JW a little bit darker, very similar. JW has a very classic whisky aroma, very little surprises. Aberfeldy a little more fruit and wine. JW perhaps a hint of peat, and a hint of mint, and not so little character. Aberfeldy tastes good, creamy and caramel. JW a little more dry, very soft and balanced. A hint of mint, and JW is more dry and malty than Aberfeldy. These whiskies are rather similar. JW is a bit more oily and heavy, Aberfeldy a little bit more fresh. Very narrow victory to JW.

JW Blue Label vs Glenlivet 21YO Archive: I blind taste, and JW is a bit more expensive. Very similar color, A is probably slightly paler, and its aroma is actually dominated by smooth peat. B has more the aroma of malt, honey and caramel. I taste B and it is rich, full of flavour, and very well balanced. I taste A, it is softly dominated by peat, but it is more thin and it fades away. Well, anyone who simply prefers more peat will prefer A, but then there are more peated whiskies to find. I really appreciate both, and they are both very tasty, but by an criteria I can argue for, B is the better whisky. And I am quite sure B is Glenlivet (I was right).

JW Blue Label vs Highland Park 18: JW is about twice the price, and I blind taste. Very similar color, both are beautiful kind of dark brown, if I had to make a difference, A is darker. A has a thick aroma of leather and oil. B is surprisingly light and thin after A. There is some peat in B, and there is some bourbon, even fruitiness in A.

I taste B and find it very soft and easy to enjoy, with hints of peat, salt and Island whisky. I taste A and also find it soft, but it more raw and salty, yet less peated. There is also some sourness to A (that could be a hint of peat). Over to be, is is more soft and refined, and more openly peated.

I am happy to compare these two whiskies, they are similar enough, yet different.

I come back after a while and in A I feel more fruity aroma, almost like sherry. B more clearly has peat and island character. Tasting both, back and forth, A is much sweeter, in a sherry way, and more powerful, while B remains the softer (yet peated) whisky.

After trying different positions, arguing with myself, and getting back to them i different order I must decide that A is better than B. And I am very sure A is Highland Park (and it was).

JW Blue Label vs Longrow: JW is darker. On the nose JW is softer and Longrow saltier (and perhaps more peated). Tasting both, my first impression is that Longrow is thinner, more sour, and more peated. Yes, the very balanced, soft, rich and complex JW tastes better than Longrow (which is very unrefined and raw in comparison).

JW Blue Label vs Dufftown 18: Same quite dark color. Dufftown is very balanced, rich and elegant on the nose. JW clearly peated compared to Dufftown. JW kind of richer (and peated) in flavour, but it fades quite quickly, Dufftown a bit sweeter and more lingering, but lighter. I could argue both ways here, Dufftown is more elegant and easy to enjoy and JW is a bit heavier and both have more and less quality in different ways. I will give JW a narrow victory.

Optimizing Objects in JavaScript

I have web applications with JavaScript business objects coming from constructors, like:

function Animal() {
  this.type      = null;   // 'Cat'
  this.color     = null;   // 'Black'
  this.legs      = 0;      // 4
  this.carnivore = false   // true
}

These objects may be created on the web, but quite quickly this happens:

  1. Client
    1. creates an Object
    2. serializes Object with JSON.stringify()
  2. The JSON text is sent over the network from client to the server
  3. Server
    1. uses JSON.parse() to get the object back
    2. validates the object
    3. stores it (perhaps by doing JSON.stringify())
  4. Client (perhaps the same) asks the server which sends it over the network
  5. Client
    1. uses JSON.parse to get the object back
    2. keeps the object in memory for application logic use

This works fine! If you do not add prototypes/functions to your constructors (like Animal.prototype.eat()) the client can use the object it got from JSON.

Since I send millions of such objects in this way over the network every day, I can’t help asking myself if what I do is reasonably efficient, or rather wasteful?

One idea I have had is that for this purpose I could turn Objects into Arrays (when shipping over the network, or perhaps storing them), like:

// As Object                          // As Array
{                                     [
  type      : 'Cat',                    'Cat',
  color     : 'Black',                  'Black',
  legs      : 4,                         4,
  carnivore : true                       true
}                                     ]

Another idea has been to create an object with “new Animal()” rather than using the raw Object I get from JSON.parse().

Possible benefits could be

  1. Arrays are smaller to store on disk
  2. Arrays are smaller to send over the network
  3. A real Animal Object may be stored more efficiently in client RAM than the raw Object
  4. A real Animal Object may be faster to operate on, in the client, than the raw Object

So rather than just sending, receiving and processing raw JSON, I could be sending and receiving Arrays, and create objects using their constructors.

Test Results

I implemented some Node.js code to test my ideas. I was using objects like:

// As Object                                 // As Array
{                                            [
  "theWorst":0.1560387568813406,               0.1560387568813406,
  "lowerQuartile":0.2984895507275531,          0.2984895507275531,
  "median":0.47865973555734964,                0.47865973555734964,
  "higherQuartile":0.7832137265963346,         0.7832137265963346,
  "theBest":0.8893834668143412                 0.8893834668143412
}                                            ]

When there is a memory range (below), the low value is after the GC has run, and the high value is the peak value. JSON means an object received from JSON.parse. Object means an Object created with a constructor.

Intel i7-8809GRAM/DiskCPU
1M Arrays94MB
-> gzip43MB7.7s
-> gunzip1.1s
1M Objects154MB
-> gzip48MB5.6s
-> gunzip1.3s
Receive & Convert data
Arrays->Arrays100-240MB0ms
Arrays->Objects76-240MB334ms
JSONs->JSONs123-310MB0ms
JSONs->Objects76-382MB280ms
Access & Use data
Arrays21ms
JSONs25ms
Objects9-11ms

Well, I find that:

  1. It is surprising that GZIP is more expensive on the smaller array than the larger object file.
  2. Costs (CPU) to compress/decompress much higher (~10x) than the cost of “packing/unpacking” JSON-data in JavaScript code.
  3. If we are using gzip for network traffic the benefit of sending the more compact arrays rather than the more wordy objects, is questionanable (higher CPU cost, 10% smaller end result).
  4. Arrays like this require basically the same amount of RAM in Node.js as disk space.
  5. Objects like this require less RAM in Node.js than the corresponding JSON file.
  6. Both when it comes to RAM usage and performance on the client side, Arrays are better than raw JSON objects, but worse than real objects from a Constructor.
  7. Unless an object is used many times on the client (10+) it is not worth it from a strict performance perspective to make it with its constructor, instead of the raw JSON.

When it comes to the different strategies I thus find:

IO/Stored formatJavaScript formatConclusion
ArrayArrayanimal[1] or animal[COLOR] (where COLOR is a global constant) is generally not acceptable compared to animal.color. And it is not justified from performance perspective either.
ArrayJSONThis would not happen
ArrayObjectGiven the extra cost of gzip, and the significant complexity of serializing/deserializing, this is hardly a good general strategy. It requires the least disk space, the least network traffic, and the least RAM on the client though.
JSONArrayThis would not happen
JSONJSONThis is the most simple, readable way of doing things, at a surprisingly low overhead. You can not use prototype though.
JSONObjectIf you find a simple and reliable way to create objects with a construtor and populate it from a JSON object, this method is probably best for performance and efficiency.

Conclusion

JSON is very simple and using it thoughout your full stack is very productive. Unless you really need to optimize things, write your code for pure raw JSON objects.

Great JavaScript Stuff 2020

I never write about great new JavaScript features on this blog. That is because there is really nothing you can not do without great new features, and I prefer writing compatible code (that runs in Internet Explorer).

However some code is backend-only, and if Node.js supports a feature I can use it.

So, here are two great new things in JavaScript that I will start using in Node.js.

Optional Chaining

It is very common in JavaScript with code like:

price = inventory.articles.apple.price;

If inventory, articles or apple is null or undefined this will throw an error. One common way to do this is:

price = inventory &&
        inventory.articles &&
        inventory.articles.apple &&
        inventory.articles.apple.price;

That is obviously not optimal. I myself have implemented a little function, so I do:

price = safeget(inventory,'articles','apple','price');

The elegant 2020 solution is:

price = inventory?.articles?.apple?.price;

Who wouldn’t want to do that? Well, you need to be aware that it will “fail silently” if something is missing, so you should probably not use it when you dont expect anything to be null or undefined, and not without handling the “error” properly. If you replace . with ?. everywhere in your code, you will just detect your errors later when your code gives the wrong result rather than crashing.

Nullish Coalescing

It is very common to write code like:

connection.port = port || 80;
connection.host = server || 'www.bing.com';
array = new Array(size || default_size);

The problem is that sometimes a “falsy value” (0, false, empty string) is a valid value, but it will be replaced by the default value. The port above can not be set to 0, and the host can not be set to ”;

I often do things like:

connection.port = 'number' === typeof port ? port : 80;
connection.host = null == server ? 'www.bing.com' : server;

However, there is now a better way in JavaScript:

connection.port = port ?? 80;
connection.host = server ?? 'www.bing.com';
array = new Array(size ?? default_size);

This will only fall back to the default value if port/server/size is null/undefined. Much of the time, this is what you want.

However, you still may need to do proper validation, so if you used to do:

connection.port = validatePort(port) ? port : 80;

you shall probably keep doing it.

Conclusion

If your target environment supports Optional chaining and Nullish coalescing, take advantage of it. Node.js 14 supports it.

Functional Programming is Slow – revisited

I have written before about Functional Program with a rather negative stand point (it sucks, it is slow). Those posts have some readers, but they are a few years old, and I wanted to do some new benchmarks.

Please note:

  • This is written with JavaScript (and Node.js) in mind. I don’t know if these findings apply to other programming languages.
  • Performance is important, but it is far from everything. Apart from performance, there are both good and bad aspects of Functional Programming.

Basic Chaining

One of the most common ways to use functional programming (style) in JavaScript is chaining. It can look like this:

v = a.map(map_func).filter(filter_func).reduce(reduce_func)

In this case a is an array, and three functions are sequentially called to each element (except reduce is not called on those that filter gets rid of). The return value of reduce (typically a single value) is stored in v.

  • What is the cost of this?
  • What are the alternatives?

I decided to calculate the value of pi by

  1. evenly distribute points in the[0,0][1,1] rectangle.
  2. for each point calculate the (squared) distance to origo (a simple map)
  3. get rid of each point beyond distance 1.0 (a simple filter)
  4. count the number of remaing points (a simple reduce – although in this simple case it would be enough to check the length of the array)

The map, filter and reduce functions looks like:

const pi_map_f = (xy) => {
  return xy.x * xy.x + xy.y * xy.y;
};
const pi_filter_f = (xxyy) => {
  return xxyy <= 1.0;
};
const pi_reduce_f = (acc /* ,xxyy */) => {
  return 1 + acc;
};

In chained functional code this looks like:

const pi_higherorder = (pts) => {
  return 4.0
       * pts.map(pi_map_f)
            .filter(pi_filter_f)
            .reduce(pi_reduce_f,0)
       / pts.length;
};

I could use the same three functions in a regular loop:

const pi_funcs = (pts) => {
  let i,v;
  let inside = 0;
  for ( i=0 ; i<pts.length ; i++ ) {
    v = pi_map_f(pts[i]);
    if ( pi_filter_f(v) ) inside = pi_reduce_f(inside,v);
  }
  return 4.0 * inside / pts.length;
};

I could also write everything in a single loop and function:

const pi_iterate = (pts) => {
  let i,p;
  let inside = 0;
  for ( i=0 ; i<pts.length ; i++ ) {
    p = pts[i];
    if ( p.x * p.x + p.y*p.y <= 1.0 ) inside++;
  }
  return 4.0 * inside / pts.length;
};

What about performance? Here are some results from a Celeron J1900 CPU and Node.js 14.15.0:

Iterate (ms)Funcs (ms)Higher Order (ms)Pi
10k88103.1428
40k34193.1419
160k33473.141575
360k661963.141711
640k11114043.141625
1000k17175593.141676
1440k252511603.14160278

There are some obvious observations to make:

  • Adding more points does not necessarily give a better result (160k seems to be best, so far)
  • All these are run in a single program, waiting 250ms between each test (to let GC and optimizer run). Obvously it took until after 10k for the Node.js optimizer to get things quite optimal (40k is faster than 10k).
  • The cost of writing and calling named functions is zero. Iterate and Funcs are practially identical.
  • The cost of chaining (making arrays to use once only) is significant.

Obviously, if this has any practical significance depends on how large arrays you are looping over, and how often you do it. But lets assume 100k is a practical size for your program (that is for example 100 events per day for three years). We are then talking about wasting 20-30ms every time we do a common map-filter-reduce-style loop. Is that much?

  • If it happens server side or client side, in a way that it affects user latency or UI refresh time, it is significant (especially since this loop is perhaps not the only thing you do)
  • If it happens server side, and often, this chaining choice will start eating up significant part of your server side CPU time

You may have a faster CPU or a smaller problem. But the key point here is that you choose to waste significant amount of CPU cycles because you choose to write pi_higherorder rather than pi_funcs.

Different Node Versions

Here is the same thing, executed with different versions of node.

1000kIterate (ms)Funcs (ms)Higher Order (ms)
8.17.01111635
10.23.01111612
12.19.01111805
14.15.01819583
15.1.01719556

A few findings and comments on this:

  • Different node version show rather different performance
  • Although these results are stable on my machine, what you see here may not be valid for a different CPU or a different problem size (for 1440k points, node version 8 is the fastest).
  • I have noted before, that functional code gets faster, iterative code slower, with newer versions of node.

Conclusion

My conclusions are quite consistent with what I have found before.

  • Writing small, NAMED, testable, reusable, pure functions is good programming, and good functional programming. As you can see above, the overhead of using a function in Node.js is practially zero.
  • Chaining – or other functional programming practices, that are heavy on the memory/garbage collection – is expensive
  • Higher order functions (map, filter, reduce, and so on) are great when
    1. you have a named, testable, reusable function
    2. you actually need the result, just not for using once and throwing away
  • Anonymous functions fed directly into higher order functions have no advantages whatsoever (read here)
  • The code using higher order functions is often harder to
    1. debug, becuase you can’t just put debug outputs in the middle of it
    2. refactor, because you cant just insert code in the middle
    3. use for more complex agorithms, becuase you are stuck with the primitive higher order functions, and sometimes they don’t easily allow you to do what you need

Feature Wish

JavaScript is hardly an optimal programming language for functional programming. One thing I miss is truly pure functions (functions with no side effects – especially no mutation of input data).

I have often seen people change input data in a map.

I believe (not being a JavaScript engine expert) that if Node.js knew that the functions passed to map, filter and reduce above were truly pure, it would allow for crazy optimizations, and the Higher Order scenario could be made as fast as the other ones. However, as it is now, Node.js can not get rid of the temporary arrays (created by map and filter), because of possible side effects (not present in my code).

I tried to write what Node.js could make of the code, if it knew it was pure:

const pi_allinone_f = (acc,xy) => {
  return acc + ( ( xy.x * xy.x + xy.y * xy.y <= 1.0 ) ? 1 : 0);
};

const pi_allinone = (pts) => {
  return 4.0
       * pts.reduce(pi_allinone_f,0)
       / pts.length;
};

However, this code is still 4-5 times slower than the regular loop.

All the code

Here is all the code, if you want to run it yourself.

const points = (n) => {
  const ret = [];
  const start = 0.5 / n;
  const step = 1.0 / n;
  let x, y;
  for ( x=start ; x<1.0 ; x+=step ) {
    for ( y=start ; y<1.0 ; y+=step ) {
      ret.push({ x:x, y:y });
    }
  }
  return ret;
};

const pi_map_f = (xy) => {
  return xy.x * xy.x + xy.y * xy.y;
};
const pi_filter_f = (xxyy) => {
  return xxyy <= 1.0;
};
const pi_reduce_f = (acc /* ,xxyy */) => {
  return 1 + acc;
};
const pi_allinone_f = (acc,xy) => {
  return acc + ( ( xy.x * xy.x + xy.y * xy.y <= 1.0 ) ? 1 : 0);
};

const pi_iterate = (pts) => {
  let i,p;
  let inside = 0;
  for ( i=0 ; i<pts.length ; i++ ) {
    p = pts[i];
    if ( p.x * p.x + p.y*p.y <= 1.0 ) inside++;
  }
  return 4.0 * inside / pts.length;
};

const pi_funcs = (pts) => {
  let i,v;
  let inside = 0;
  for ( i=0 ; i<pts.length ; i++ ) {
    v = pi_map_f(pts[i]);
    if ( pi_filter_f(v) ) inside = pi_reduce_f(inside,v);
  }
  return 4.0 * inside / pts.length;
};

const pi_allinone = (pts) => {
  return 4.0
       * pts.reduce(pi_allinone_f,0)
       / pts.length;
};

const pi_higherorder = (pts) => {
  return 4.0
       * pts.map(pi_map_f).filter(pi_filter_f).reduce(pi_reduce_f,0)
       / pts.length;
};

const pad = (s) => {
  let r = '' + s;
  while ( r.length < 14 ) r = ' ' + r;
  return r;
}

const funcs = {
  higherorder : pi_higherorder,
  allinone : pi_allinone,
  functions : pi_funcs,
  iterate : pi_iterate
};

const test = (pts,func) => {
  const start = Date.now();
  const pi = funcsfunc;
  const ms = Date.now() - start;
  console.log(pad(func) + pad(pts.length) + pad(ms) + 'ms ' + pi);
};

const test_r = (pts,fs,done) => {
  if ( 0 === fs.length ) return done();
  setTimeout(() => 
    test(pts,fs.shift());
    test_r(pts,fs,done);
  }, 1000);
};

const tests = (ns,done) => {
  if ( 0 === ns.length ) return done();
  const fs = Object.keys(funcs);
  const pts = points(ns.shift());
  test_r(pts,fs,() => {
    tests(ns,done);
  });
};

const main = (args) => {
  tests(args,() => {
    console.log('done');
  });
};

main([10,100,200,400,600,800,1000,1200]);

Roleplaying in Middle Earth & magic

Middle Earth is a fantastic fantasy world and it can be used for tabletop roleplaying games. There are games designed with Middle Earth in mind (MERP by Iron Crown, The One Ring by C7, Adventures in Middle Earth by C7), but they are all out of print. Given the vast amount of Middle Earth content available elsewhere it should be quite fine to use any fantasy roleplaying system not written for a specific setting, right? I particularly like the simplicity of OSR. Well, it is that thing with magic.

Magic in fantasy roleplaying games

Magic in fantasy RPGs is most often about spells. Sometimes they are spectacular and action oriented. Often there are clerics getting their powers from deities, and sorcerors taming raw magic power.

This is not obviously a good match for Middle Earth. Clerics praying to Valar for spells is kind of unheard of. Saruman and Gandalf use magic, but not so easily and not very spectacularly, and they are Maia (half god-like spirits) not men. Powerful elves have some magic abilities. But regular men being educated wizards casting fireballs is quite not in the books.

Magic in Middle Earth

I am presuming a (late) Third Age campaign.

There is definitely magic in Middle Earth. Many magical items are mentioned. There are things like the river horses that swept away the nazgul outside Rivendell, the tempest Saruman used to stop the fellowship from crossing the misty mountains, and whatever was done to Theoden.

However, most magic is very old, connected directly with Elves, or connected to Maia.

When Sauron appeared in Dol Guldur he was thought to be a Necromancer. So the free people of Middle Earth found the existence of a necromancer a possibility (more likeely than the return of Sauron). If a powerful necromancer could have appeared there should also exist magic practitioners.

The question is, how and to what extent can magic be available to the player characters, and their enemies?

What are we looking to solve?

Obviously, if GM and players agree, then so is it: Clerics worhipping Valar and fireballs. However, I think we can do better.

Also, if we want much magic (like in Forgotten Realms) then perhaps it is better to play in setting with more open magic (like FR). But I think we can do better.

Sam feared that Gandalf would turn him into something unnatural. In the movie Gimli warns the hobbits of the elf witch who lives in Lorien […] all under her spell and are never seen again. No one in the fellowship (except Gandalf) had imagined the Balrog in their darkest dreams. So I argue that it is in the essential nature of Middle Earth that unexpected magic and supernatural things can happen. If you mostly remove magic you actually turn your Middle Earth game into less than it deserves to be.

I would like to have a Middle Earth where magic is not at all commonplace, but where it can feasibly and arguably exist. Ideally, I would like to interpret and explain magic so that I can mostly use simle OSR rules, with moderation.

Ideas and possibilities

I will now present some arguments for why (OSR style) magic could be used to some degree in a late Third Age Middle Earth RPG campaign.

Alatar and Pallando: Tolkien wrote in a letter about the two blue Istari: I suspect they were founders or beginners of secret cults and ‘magic’ traditions that outlasted the fall of Sauron. This is clearly an opening for the existence of sorcerors or wizards in Middle Earth, even though they played no part in the books.

Religion: We don’t read in the books about clerics praying and sacrificing to Valar. But the Third age is 3000 years old, and it is not hard to imagine that the free peoples were actually worshipping and praying. That works of fiction do not mention religion does not mean religion can not exist. The most important building in Gondor was obviously not a cathedral, that we know. But can there be no shrines, nowhere, at all?

However, worshipping is one thing, being granted spells is a different story.

Valar: Since the end of Second Age, Valar has a kind of non-intervention policy. However, they sent the Istari to Middle Earth on a mission. Someone sent Gandalf back as the white wizard after the fight with the Balrog. So I think it is unnecessarily restrictive to imagine they have no power whatsoever in Middle Earth.

Maia: The Maia helped Valar create the world, so they are powerful magical spirits creating and changing reality. All of them are not named and they are not numbered. Gandalf said: There are older and fouler things than Orcs in the deep places of the world. The Balrog had been hidden for long times when the dwarves disturbed it. I think as a GM you have quite some space to use unmentioned Maia as source of magic powers.

End of Third Age: The Valar has been quite absent for three millennia. Sauron is rising but driven from Dol Guldur, Smaug is killed, and large parts of Middle Earth (Arnor) is largely desolate and open. The Istari is not supposed to use force, but Saruman has other plans. This is a situation with two factors:

  • it is a power vacuum – there for somone (Maia or other) to fill
  • the rules are rewritten – Istari are failing their mission

And things can have been going on for centuries quite secret in the background.

Multiverse: The first chapter of Silmarillion does not start with These events took place in a little corner of the multiverse. No other creation myths start like that either. Nevertheless the multiverse idea is that different game settings exist in simultaneously and that the deities can be present in several of them. If Middle Earth is really left alone by the Valar, why would not some other power show interest in it?

Leave it open

I am not suggesting that you as a GM write down exactly who is granting or teaching what magic powers in Middle Earth and tell your players all about it. That serves no purpose and the players need not know.

What you tell the players is that just as the fellowship did not know about the Balrog, they also don’t know about all powers of Middle Earth.

You can tell that the Istari – or other unknown Maia – during the last millennia of the third age may have taught, shared or granted magic to smaller groups of rather unknown spellcasters. The characters know nothing of this, of course, but the players may ask.

You are now free, with moderation, to introduce spellcasters as part of your adventures.

And if a players wants to be a cleric, wizard, sorceror or warlock, it can be done. It may come with risks though

  • being accused of witchcraft and black magic is always dangerous
  • that magic teacher or spell-granting-deity, who is it really?

Sauron decieved the Numenoreans to worship Morgoth and make human sacrifices.

Conclusion

I think it is possible to run a Middle Earth campaign with a simple OSR system (or your favorite game) and use the magic system of that game mostly the way it is. That does not mean that magic appears in Middle Earth just as it does in Forgotten Realms (or some other hi-magic setting). It just means that magic is possible.

I don’t suggest you to turn Middle Earth into a hi-magic setting. But I also think it is a mistake to have so little magic that there is nothing mysterious or unexpected to the players and their characters to discover.