James Handley's blog on eutony.net

As previously mentioned I finished 2024’s Advent of Code. But I wasn’t sure that I really understood the solution to Day 21, so the purpose of this post is explain it to myself!

Fair warning: This is a long and technical post!

Day 21

Day 21 was a beautiful problem, but an absolute stinker in terms of brain strain. The description below is all lifted off the problem page on AoC, minus the prose.

The problem

There is a numeric keypad

+---+---+---+
| 7 | 8 | 9 |
+---+---+---+
| 4 | 5 | 6 |
+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
    | 0 | A |
    +---+---+

Which needs a provided code – say 029A – to be entered.

This keypad is operated by a remote control robot (Robot 1), which is controlled by a directional keypad. The direction keys move the robot’s arm, and A makes it press whatever button it’s over.

    +---+---+
    | ^ | A |
+---+---+---+
| < | v | > |
+---+---+---+

The robot starts on A, so one way of getting the robot to enter the code 029A would be to press

  • < to move the arm from A (its initial position) to 0.
  • A to push the 0 button.
  • ^A to move the arm to the 2 button and push it.
  • >^^A to move the arm to the 9 button and push it.
  • vvvA to move the arm to the A button and push it.

Obviously there are an infinite number of sequences that could be entered on the remote control keypad, so this puzzle is just concerned with the shortest sequences (i.e. fewest number of key presses).

There are 3 shortest sequences of keypresses for 029A:

  • <A^A>^^AvvvA
  • <A^A^>^AvvvA
  • <A^A^^>AvvvA

BUT Robot 1’s remote control is operated by a second robot (Robot 2), which has its own independent directional control pad. So in order to get the Robot 2 to enter <A^A>^^AvvvA (so that Robot 1 enters 029A) you need to enter a sequence on its keypad such as v<<A>>^A<A>AvA<^AA>A<vAAA>^A.

  • Move Robot 1 0 and press [029A]
    • Move Robot 2 to < and press [<A^A>^^AvvvA]
      • You press v<<A
    • Move Robot 2 from 2 to A and press [<A^A>^^AvvvA]
      • You press >>^A
  • Move Robot 1 from 0 to 2 and press
    • etc…

BUT Robot 2’s directional control pad is operated by a third robot (Robot 3), which again has a remote controlled direction pad.

SO

  1. Robot 1 has to enter 029A on the door keypad
  2. Robot 2 has to enter (say) <A^A>^^AvvvA on Robot 1’s remote control pad to make Robot 1 enter 029A
  3. Robot 3 has to enter (say) v<<A>>^A<A>AvA<^AA>A<vAAA>^A on Robot 2’s remote control pad to make Robot 2 enter <A^A>^^AvvvA on Robot 1’s control pad, which make Robot 1 enter the code on the door keypad
  4. I, operating Robot’s 3 remote control, need to press (say)
    <vA<AA>>^AvAA<^A>A<v<A>>^AvA^A<vA>^A<v<A>^A>AAvA^A<v<A>A>^AAAvA<^A>A to make Robot 3 enter v<<A>>^A<A>AvA<^AA>A<vAAA>^A on Robot 2’s remote control pad, which make Robot 2 enter <A^A>^^AvvvA on Robot 1’s control pad, which will make Robot 1 press 029A

It was at this point my brain ran out of steam. Actually it kind of ran out at Robot 2.

For Part 1 of the problem this was the setup, and you had to determine the smallest number of keypresses needed on Robot 3’s remote control pad to get Robot 1 to enter the code.

Solving part 1

The first gotcha is that once you get more than a couple of robots, the keypress order matters.

So, if I need to go left 1 and up 2 there are 3 equal length ways to do it:

  • <^^
  • ^<^
  • ^^<

BUT, if I add extra robots, suddenly ^<^ becomes much a much longer sequence than <^^.

  • <^^ = Move finger to left, activate, move finger up, activate, activate
  • ^<^ = Move finger to up, activate, move finger left, activate, move finger to up, activate

There is a whole extra sequence of keypresses in the second. It turns out to be even more subtle than this, and analytically beyond my brain – but that’s ok because we can just try them all out and choose the shortest – fine for part 1.

So my solution for this part was essentially brute force.

Treating each digit of the door code independently (which it is):

  1. Calculate all the (sensible) sequences which can be entered on the Robot 1’s control pad to move it from the current and next digit in the code (e.g. A to 0), and keep only the shortest. So in the first case that’s just <.
  2. Calculate all the (sensible) sequences which can be entered on the Robot 2’s control pad to make it enter each sequence identified in step (1), with a A at the end of each, and again keep only the shortest. For instance v<<A>>^A
  3. Calculate all the (sensible) sequences which can be entered on Robot 3’s control pad to make it enter each of sequences in Step (2). Again keep only the shortest.

Calculating the sequences is pretty straightforward – for any pair of keys, we either move up or down zero or more times, and either left or right zero or more times. But we never need to move up and down, or left and right within one sequence. So it’s just a case of recursing the options, at each step adding “having moved up/down” and “having moved left/right” as two possible sub-sequences.

It all hangs on the fact it is essentially a recursive problem – working out the sequence to enter <A^A>^^AvvvA is no different to the calculation for <vA<AA>>^AvAA<^A>A<v<A>>^AvA^A<vA>^A<v<A>^A>AAvA^A<v<A>A>^AAAvA<^A>A

So my main solving code ended up as


public static List CalculateSequences(char[][] keypad, string sequence)
{
  List options = [""];
  for (int i = 0; i < sequence.Length; i++)
  {
    List newOptions = [];
    // Navigate returns all the ways of getting from 'n1' to 'n2'
    var currentKey = i == 0 ? 'A' : sequence[i - 1];
    var nextKey = sequence[i];
    foreach (var option in Navigate(keypad, currentKey, nextKey ))
    {
      newOptions.AddRange(options.Select(o => o + option));
    }
    options = newOptions;
  }

  return options;
}

public static string CalculateShortestSequence(string sequence)
{
  StringBuilder shortest = new StringBuilder();
  // Do one key at a time.
  for (int i = 0; i < sequence.Length; i++)
  {
    var currentKey = i == 0 ? 'A' : sequence[i - 1];
    var nextKey = sequence[i];
    // Calculate the potential key presses for R1's control to
    // move from current to next
    var keypadOptions = Navigate(NumericKeyPad, currentKey, nextKey);

    // Calculate the presses on R2's control for each
    // of the R1 potential sequences
    var kp2Options = keypadOptions
           .SelectMany(seq => CalculateSequences(DirectionKeyPad, seq));
    kp2Options = kp2Options
           .Where(seq => seq.Length <= kp2Options.Min(seq => seq.Length))
           .ToList();

    // Calculate the presses on R3's control for each of
    // R2 potential sequences.
    var kp3Options = kp2Options
         .SelectMany(seq => CalculateSequences(DirectionKeyPad, seq));
    kp3Options = kp3Options
         .Where(seq => seq.Length <= kp3Options.Min(seq => seq.Length))
         .ToList();

    // Take shortest of these R3 sequences as our candidate.
    shortest.Append(kp3Options.OrderBy(seq => seq.Length).First());
  }

  return shortest.ToString();
}

Even with just only 3 robots, I was running into runtime issues with the number of sequences calculated, hence having to discard all the non-shortest sequences at each level of recursion.

Part 2

As usual Part 2 upped the ante considerably, in this case having 25 interim robots instead of just 2!!

Clearly the approach for part 1 was never going to work.

My solution (with help from Reddit) hinges on 4 critical observations:

  1. You don’t need to know the actual sequences to solve the puzzle, just the length of the shortest sequence
  2. Each digit press is independent. That is to say, it doesn’t matter what keypresses have gone before – the only relevant factors are the start position and end position.
  3. When a key is pressed on a certain keypad, every robot on every keypad ‘above’ it in the chain must be on A. This means there is a sort of “reset” up the chain on every button press.
  4. The shortest sequence between any 2 pairs of keys therefore only needs to be calculated once for each level of the chain, and can thereafter be re-used (memoized/cached).

The final point here is critical. Once you’ve worked out the cost of moving Robot 2 from (say) A to < and pressing it, the lowest cost sequence for this move for this robot will be the same every time!. This isn’t very interesting for Robot 2, but for robot 3 we move from A to < 3 times – and only need to calculate it once. It also turns out there is a pretty small set of key pairs for any given robot – just 20, so even with 25 robots we only need to calculate and store a maximum of 500 entries. But we can also calculate them “on demand” – hence the memoization.

And in case it isn’t already clear, this is a recursive problem:

  • I need Robot 1 to enter 029A
    • So I first need to move Robot 1 from A to 0 and press it.
      • Ah, so I need Robot 2 to enter <A
        • So I first need move Robot 2 from A to < and press it
          • Ah, so I need Robot 3 to enter v<<A
            • So I need to move Robot 3 from A to v and press it
              • Ah, so I need Robot 4 to enter v<
            • Finally, move Robot 3 from < to A and press it
        • Now Robot 2 needs to move from < to A and press it
    • Yay – we entered 0 – next step move Robot 1 from 0 to 2 and press it.

Remember, when Robot 1 presses a digit, all the other robots will be on A

Our recursion therefore works by asking the question “How many key presses are required to cause ‘me’ to press a key (given I’m starting on a key) if there are n robots above me?”:

  • The sequence required is <
    • How many key presses are required to achieve A<, with 25 robots above?
      • The sequence on my control pad is v<<A*
        • So how many keypresses are required to achieve Av with 24 robots above?
        • And how many keypresses are required to achieve v< with 24 robots above?
        • And how many keypresses are required to achieve << with 24 robots above?
        • And how many keypresses are required to achieve <A with 24 robots above?
      • Add these up, and that’s the cost

* For simplicity we’re ignoring the fact multiple sequences exist – in the real thing we have to test them all.

The base case of the recursion is the human at the top – the final robot will always have a count of 1 (as the button is directly pressed).

So far so Part 1 – but now the magic kicks in.

I worked out the cost of [Av with 24 robots], and I can store that, so next time I’m asked [Av with 24 robots] I can return the cost without having to traverse the whole chain again. This is not desperately useful for a Robot so near the bottom, which may only be asked this question once – but higher up the tree the twenty questions like:

  • [Av with 5 robots]
  • [A^ with 5 robots]
  • [A< with 5 robots]
  • [A> with 5 robots]
  • [vA with 5 robots]

Are going to be asked a lot. And once calculated the result is, in effect, instant.

So – the resulting recursion code is about 20 lines long, I’ve tweaked a little to try and remove some obscurity. The Navigate is the same as for Part 1 – it returns every sensible sequence for navigating from key 1 to 2 on the specified pad.

private long Cost(char a, char b, int robots)
{
  // Check the cache
  if (cache.TryGetValue((a, b, robots), out long inCache))
  {
    return inCache;
  }

  var lowestCost = long.MaxValue;
  
  // Determine All ways of moving from a to b
  var options = Navigate(DirectionKeyPad, a, b);
  foreach (var option in options)
  {
    long cost = 0;
    if (robots == 1)
      cost = option.Length; // just the direct button presses, and an 'A'
    else
    {
      for (int i = 0; i < option.Length; i++)
      {
        char nextA = i == 0 ? 'A' : option[i - 1];
        char nextB = option[i];
          cost += Cost(nextA, nextB, robots - 1);
      }
    }
    if (cost < lowestCost)
      lowestCost = cost;
  }
  cache[a, b, robots)] = lowestCost;
  return lowestCost;
}

It just needs an extra function on top to calculate all possible sequences for Robot 1, and kick off the recursion with robotCount = 25. There's also a bit of guff to read the puzzle input and generate the output in the format required.

You can look at the Full listing on GitHub - SolveB is the entry point.

Well, for the second time in my life, I “50 starred” last year’s Advent of Code. By the way, if you’re anyway connected with computing, and haven’t seen Eric Wastl’s keynote presentation Advent of Code, behind the scenes I highly recommended it.

Anyway, it was mainly plain sailing this year, except for 2 stinkers which took me hours to finish – the latter of which I had to look up some hints on reddit before I got it. I thought I’d post my solutions and process (in part of make sure that I understand my solution!)

Day 17

The first one was Day 17. The problem here was that I was getting the right answer in my tests, but the wrong answer with the actual problem. I was convinced it was my maths which was wrong, but it was actually my code – specifically a hidden 32 bit truncation of a 64 bit number. So a bit annoying (no pun intended). It was actually a really nice problem – there was an octal (3 bit) computer which had 3 registers, and a program input of 16 octal numbers. You had to determine the starting value of register A in order for it to generate the program input as it’s output. The way I tackled this was to analyse the program to work out what it was doing, and realise that at the end of each ‘loop’ it left bit shifted A by 3 (aka dividing by 8). This meant that the first number output could only be influenced by the most significant 3 bits of A, i.e. 8 values.

So when you find a value which works for the first program output number, you recurse to the next one, and check it’s 8 values. Of course, you sometimes need to go back up the recursion tree if you can’t find a solution (so ‘1’ in the MSB might give you the right output for the first number, but no value 0-7 in the next 3 bits gives you the second, so you need to go back up to the first one again).

My solution to day 17

The other one was Day 21 – but you’ll have to wait for the next exciting instalment.

Just discovered this random draft from ~2016 of a skit I wrote on “Summertime Blues” by Eddie Cochran.

The context is when I was training for ordination at St Hild College. Every year we had a residential Easter school, which at the time was at the University of Durham, and one evening was given over to a revue. In the event, this didn’t see the light of day, but I obviously got as far as drafting it on here! At the time I had the actual tutor’s names.

Well I’ve a got to read Barth and I’ve got to read Bonhoffer
And I need to write an essay but I guess I ain’t no scholar
So I tried to call my tutor, to try and change the date
but he said “No dice son, you can’t hand it in late
Sometimes I wonder what I’m a gonna do
but there ain’t no cure for the Easter School blues

The college tutors told us that “you’ve got to do some mission,
You need to go down into Durham and do some people fishing”
But I went down to the river, and hid inside a hole
So you can’t graduate ‘cos you didn’t save a soul
Sometimes I wonder what I’m a gonna do
but there ain’t no cure for the Easter School blues

It’s just one week but it sure ain’t no vacation
I really want to skip it and go straight to ordination
So I tried to call the bishop, to see what she could do
but she said
[in normal voice, fading to silence]
According to Ministry Division regulations, I’m afraid all ordinands are required to spend at least 5 nights a year on a residential…

I did also have a stab at Sound of Silence, inspired by the very noisy pipes (plumbing gently creaking) where we were staying, and the fact that Durham actually has cobblestones. But I also think it got borderline inappropriate at one point, which is probably why I canned it.

I decided to take the plunge and revisit Tomb Raider, as it’s available for the Switch in a remastered version. Looks like it was actually released last year, with IV-VI out next week (on Lara’s birthday).

It’s strange because I half remember it – I clearly finished Tomb Raider IV in 2001, by implication on a PS2 – but I want to say I played the original on a PC? It was back in 1996 (nearly 30 years ago!), so I think I can be forgiven for not remembering.

Anyway, huge nostalgia tip – swan dives and that handstand when pulling up on a ledge. Jump scare central too, so atmospheric. Especially when it suddenly switches to the exciting/scary “something’s about to happen” music. The updated graphics are excellent, except (as others have commented) when trying to navigate dark passages. I am switching between the graphics modes regularly as I explore the dark caves. One of the things they’ve remastered is the textures – so ivy now comes out of the wall, rather than being a flat texture. I also know I’m going to encounter a T-Rex soon!

The controls (again, as others have commented) are deeply frustrating after playing games like Fortnite. I did briefly try the “modern” controls, but there were even worse. I’m ending up saving the game after every tricky jump, just because it’s so tedious having to take 5 or 10 goes to get up a room.

The other thing that’s really interesting is the disclaimer at the beginning:

“The games in this collection contain offensive depictions of people and cultures rooted in racial and ethnic prejudices. These stereotypes are deeply harmful, inexcusable, and do not align with our values at Crystal Dynamics.

“Rather than removing this content, we have chosen to present it here in its original form, unaltered, in the hopes that we may acknowledge its harmful impact and learn from it.”

(from eurogamer.net)

You do also have to acknowledge the idealisation (sexualisation?) of Lara – it is readily apparent that she was drawn by a man! Huge boobs – check. Crop top – check. Tiny waist – check. Tiny tight shorts – check. But, on the flip side, she was, I think, the first ‘proper’ female hero in a video game, and Tomb Raider must be one of the earliest games to pass the Bechdel test? And she is highly intelligent and resourceful (admittedly with a penchant for shooting animals and grave robbing). I’d be lying to say that my twenty year old self didn’t have a bit of a crush on her, but as soon as you start playing actually the focus is on the gameplay and puzzles, not Lara herself.

Anyway, in terms of the gameplay, too soon for a definitive opinion – thus far enjoying it! I don’t think I’d recommend it to anyone who didn’t play the original though.

Sun Jan 12 2025

Fair to say that, based on the last week or so, neither my son nor I are going to make our millions on crypto.

  • ETH is down 10%
  • DOGE is down 13%
  • SUI is down 8%

What is quite interesting is just how unstable the currency is, which I kind of already knew. A few days ago ETH had jumped to a 1% increase for an hour or so. In general they’ve been bubbling along at around -10% since we bought them.

Anyway, it’s a long-term game (but I do have standing instructions from my son to sell his DOGE it if gets to +75% and he’s not around to ask).

Fri Jan 10 2025

Two or three years ago I switched my current account over to Starling Bank, and it has revolutionised the way I manage my money.

What initially drew me to Starling was the the ethical policies, 0% fees overseas usage (ATMs and paying by card), and – yes – because of the shiny fintech challenger bank thing, which I liked the look of. I was previously with Smile – which has a better ethical stance, but I didn’t like the fact it had to be bailed out by hedge funds. Of course, The co-op bank (and hence Smile) is now owned by the Coventry Building Society, which pushes it back up the ethical list. Triodos bank is also very near the top of my list (and I have savings accounts with them), but again their current account is just lacking features. I also liked the fact that Starling was founded by a woman.

What has kept me with Starling is that is it is absolutely fantastic product. The app is so easy to use, and the product has clearly been designed with a smartphone as the primary use case. This is in sharp contrast with the more traditional banks, who, it seems to me, have evolved online services as a way of providing the offline services online. It’s quite hard to put into words, but it’s the difference between starting from “we need to provide statements – ok, lets add that. We need to provide bank transfers, ok, lets add that” and “What would a bank account on a phone look like? What’s the landing page? what information needs to be in your face?”. Starling have clearly started with a clean slate and worked out what people want in a banking app – and have nailed it. I also really like the instant notifications – I don’t need to check my statements anymore each month, as I’ve reviewed each transaction along the way. Last “nice to have” is the spending breakdown; you can categorise each transaction (“groceries”, “health”, “coffee”) and see stats on what you are spending on what.

All that said, there is one killer feature for me which puts it in a different league: Spaces.

Spaces

Spaces are a way of dividing up or allocating money in your account – a bit like having another bank account, except it’s all the same physical account underneath. This may not seem like such a big deal, but it is has been a revolution to me. It doesn’t really give you anything you couldn’t do with multiple accounts and/or spreadsheets – except that you don’t need multiple accounts or spreadsheets!!

The important functionality is:

  • Spaces are named, and each has its own balance
  • Standing orders and direct debits can be paid from a space
  • You can set up virtual debit cards, which pay directly out of the space
  • You can automatically regularly transfer money in – either to top up to a set balance, or to pay in a set amount
  • The money in spaces is still physically in the same account, so attracts interest (or, at least, it did) and means you can go ‘overdrawn’ in your main balance without any fees, if there is enough money in spaces
  • If you don’t have enough money in a space to pay a standing order, it will notify you, as as long as your transfer in money the same day, the payment will be made.

It’s probably easiest to explain how I use them

  • I have a tithe space – every month 10% of my salary gets transferred in, and then subsequently most gets sent by standing order from this space to church, mission partners, or whatever. If any surplus builds up I can see it, and make sure I give it away at the appropriate opportunity.
  • I have a bills space – every month the space is topped up to the amount needed to cover all my regular monthly bills (council tax, mortgage, phones, electricity), and these bills are then paid over the month directly from the space.
  • I have a Christmas and presents space, which gets a transfer each month that builds up over the year. I use this money to buy presents throughout the year, and also is my budget for Christmas presents, food, cards, etc.
  • I have an internet virtual space, with a virtual card that I use for all my online shopping. The balance on this space is £0, and I transfer money into the space just before each purchase. This means I don’t need to worry about my card being cloned or abused – there is never any money ‘on the card’ to be stolen, and deleting and creating a new one is 3 clicks on the app.
  • I have a subscriptions space, where I have totted up all my yearly subscriptions (magazines, journals, etc), divided by 12, and transfer in that amount every month. All the subscriptions are then paid from this space as the year goes on.
  • I have spaces for other annual bills (such as house insurance) which again get topped up by 1/12th each month, and paid direct from the space each year.
  • I have a toy fund space where e.g. birthday money goes, which is just disposable income for video games, or whatever.
  • I have a general save space, where at the end of each month I can transfer in any positive balance in my main account.
  • I have a credit card space – every time I buy something on my credit card, I transfer that amount to this space. The full balance on the card is then paid off by direct debit.
  • And other ad-hoc spaces if there are any pots of money I want to keep separate.

What this gives me is a main balance which always reflects the amount of money I actually have to spend (once the essentials are covered), and all my money is one place. When I was with Smile, I had a tithe current account, and two or three savings account. But you had to remember which account number was which, and they each had different statements, chequebooks, cards, paying in slips, …

Cons

Of course, nothing is perfect, and there are some things I don’t like about Starling.

  • It is essentially app only – if my phone dies no bank account access
  • No chequebook (but then I can’t remember the last time I wrote a cheque)
  • The spending stats are a nice idea, but I don’t find they work very well with spaces
  • The statements are slightly awkward to access, and don’t have any reference to spaces
  • They no longer pay interest on their current account

That last one is actually a pretty big deal, as I will typically have several hundred pounds across my spaces. As they were all accruing interest, this was fine – no need for separate saving account.

Also worth saying it is online only – so no branches. Cheques can be paid in using the app, but cash has to go in via the Post Office.

So..

I really enjoy being a customer of Starling bank (and I have never previously said that about any bank). I am aware that all of the above assumes having enough money to make ends meet, and I don’t take that for granted.

But the app is a pleasure to use. I am on top of my money without any real ongoing effort now it’s all set up.

I made a few tweaks to my website over the weekend – chief one being to decrease the static page refresh time and update packages, but ran into all sorts of problems trying to build the Docker image.


Error: Could not load the "sharp" module using the linuxmusl-arm runtime
Possible solutions:
- Manually install libvips >= 8.15.3
- Add experimental WebAssembly-based dependencies:
npm install --cpu=wasm32 sharp
npm install @img/sharp-wasm32
- Consult the installation documentation:
See https://sharp.pixelplumbing.com/install
at Object. (/app/node_modules/sharp/lib/sharp.js:113:9)
at Module._compile (node:internal/modules/cjs/loader:1740:14)
at Object..js (node:internal/modules/cjs/loader:1905:10)
at Module.load (node:internal/modules/cjs/loader:1474:32)
at Function._load (node:internal/modules/cjs/loader:1286:12)
at TracingChannel.traceSync (node:diagnostics_channel:322:14)
at wrapModuleLoad (node:internal/modules/cjs/loader:234:24)
at Module. (node:internal/modules/cjs/loader:1496:12)
at mod.require (/app/node_modules/next/dist/server/require-hook.js:65:28)
at require (node:internal/modules/helpers:135:16)

> Build failed because of webpack errors

I have had this issue in the past (when I was first moving over to nextjs), but have built the site several times since then, but couldn’t for the life of me remember how to fix it. So I did all the usual stuff to fix it – cleared caches, updated packages… no joy. Builds and runs fine natively on the Pi itself, but the nextjs build fails in Docker with the above error no matter what.

After many hours going down a rabbit hole of node_modules (which I thought was being copied, and causing the issue), it turns out it was all to do with how I was building the container. I had experimented in the past with a fancy cross-platform build (so I could build the Pi container on my Windows PC), which I subsequently abandoned but left the instructions in my Readme.

docker buildx build --platform linux/arm/v7 .

Drop the platform specification, and it builds perfectly.

docker buildx build .

I’m not sure why this is – I know cross platform builds can be… interesting shall we say, but I didn’t think I was doing a cross platform build! Anyway, all working now. (The reason I have the command in my Readme is that I also tag it and push it up to Docker repository).

Incidentally, Stack Overflow was no help – so this is posted in case someone else benefits from my pain!

Sun Jan 05 2025

I am now an investor in cryptocurrency!

Ok, so that’s probably putting it a bit strongly. My younger son really wanted to buy some Dogecoin, so we finally relented and let him spend some of his Christmas money on cypto.

I decided for fun that I would match him in a different currency so we can have a mini competition.

He’s old enough to understand the risk associated – that he may lose all the money, is likely to get back less than he invested, and may not be able to sell it back to pounds when he wants to. Nevertheless he’s seem the 500% growth curve for Doge this year and wants in!

It’s as much about entertainment as anything else – the total amount we’ve spent between us is less than a computer game would cost, and I’m optimistic that they will be worth at least something in a few years time.

So, he has Dogecoin, I have Ether, and I also bought some Sui to make it a 3 horse race. 24 hours in, they are all still worth about what we paid after fees (ETH slightly up, DOGE and SUI slightly down).

Speaking of investment I also bought a modest number of Raspberry Pi shares at the IPO earlier this year. After the initial spike these settled down, but just before Christmas made a huge leap and have stayed up (+133%). I won’t lie and say I’m not tempted to sell, but I bought them to invest in a company I want to back, and plan to keep hold of them long term. It’s essentially part of my pension plan, but nice to see growth.

Back in January 2024 I’d identified some things which we thought were going to change in 2024, and most have come to pass.

  • Bedroom redecorated (which a bonus of fixing squeaky floorboards)
  • Jafar the snake is doing nicely (his “birthday” is the 5th Jan)
  • My car is now fully electric
  • We’ve switched to Zen Internet (referral link) fibre-to-the-home broadband, which has been a fab experience
  • Related to this, we’ve gone fully digital VOIP with our landline
  • I got my Tattoo
  • And I’ve started playing bass guitar (somewhat set back by putting a screwdriver through my finger the day after I bought it)

The real biggy for me was moving away from Virgin Media (they’ve been our Internet, phone, and TV provider since 2000, when it was NTL). I don’t buy into the fibre hype (coax cable, which is what Virgin ran from the cabinet to the router/modem, has plenty enough bandwidth) – but I’d got increasingly dissatisfied with the cost and the internet connectivity issues. Our monthly bill has gone from £59 for 125 MBps (asymmetric) broadband to £38 for 300 MBps symmetric (£32 for Zen, about £6 for VOIP). Not quite like for like, as Virgin included a set-top box, but not with any channels we watched. But in nearly a year we’ve had one short outage I think, but otherwise no degradation of service.

Didn’t manage to knock down our garage or build an extension. I also didn’t digitise any old negatives.

But did tick another thing off my bucket list, which was that we went on a Canal holiday which was also great.

This year? To be honest no big changes planned. We might sort out the garage, and we might start to think a bit more seriously about an extension.

Sat Apr 06 2024

Well, I am now the proud “owner” of a full electric car. I went for a BYD Atto 3 in the end, so I hope the Chinese government doesn’t decide to apply my full emergency brakes while I’m on the M5!

I say “owner” because I’m actually leasing it through work, so it’s technically a company car – but it’s mine in the sense that I’m paying for it and am the one on the insurance.

My venerable (well, 8 yo) Vauxhall has gone the way of motorway.co.uk, so now no petrol for me.

Initial thoughts – I like it, a lot. It’s so quiet and responsive, and now I’ve got the hang of not having to change gears or use the clutch it’s nice. The acceleration is something else, and it’s not even in sports mode.

With the Octopus Go tariff, my annual mileage (~6,000 miles) will cost about £75 – which is roughly the same as a full tank of petrol on the Vauxhall. I was filling up every 4 to 6 weeks probably, so that’s a win in my books. Plus filling up now happens overnight on the drive, not at a petrol station!

The quid pro quo is obviously the range. The theoretical range is 200 miles, but that’s downhill with the wind behind you on a warm day and running the battery completely flat. On a long journey, the distance between stops is more like 120 miles, given that you’re not supposed to run it below 20%, and charging is only fast to 80%. So broadly speaking it’s a 30-60 mins stop for every 2 hours of motorway driving. On my commute to Skipton (31 miles each way, with the A59 being closed) I get down to about 20% after 4 trips, i.e. 120 miles, but it is cold weather.

I guess this is where the rubber hits the road – almost every other aspect of an electric car is an improvement on petrol cars, but if I’m serious about wanting to reduce my environmental impact then actually having to be inconvenienced is when it counts.