Starting Year Four

Paul R. Potts

13 Mar 2023

Hello Dear Readers,

It’s March 13th and it’s been a long time since I last wrote a newsletter. So, I’m going to try to get something written.

The Power and the Damage Done

The big news in Washtenaw County over the last few weeks has been the power outages. There was an ice storm a few weeks ago that covered the region. A lot of homes in the Ann Arbor area were affected — not a few isolated homes in the woods in Washtenaw County, but a lot of homes in the city proper. Many people had no power for days, some over a week. We were somewhat surprised that our power didn’t go out, as we have had fairly frequent outages here in our little home in a wooded corner of Pittsfield Township.

On Friday the 3rd, we had a day of extreme weather — a blizzard, followed by an ice storm, followed by a Thundersnow. At about 8:00 in the evening our power started to flicker. Then, all hell broke loose. We started hearing loud bangs and zapping noises and flashes from outside, followed by a very loud bang inside. The kids reported seeing sparks flying from the overhead light fixtures. There were weird green flashes and glows coming in through our windows, from multiple directions. As Grace put it, “it looked like the aliens were landing.” Then the power went out completely, but the weird glows continued for a while. We started smelling burning electronics.

Grace and I walked around the yard with a lantern to see if it looked like anything was on fire or there were any obvious hazards from downed wires. The weird glows had faded. We found that our driveway was pretty much impassable because the heavy snow was heavily weighing down a lot of trees and smaller things. Our power lines were still up where they were supposed to be, but the wires from the pole in the easement to our house were hanging unusually low. Still, nothing looked hazardous.

Fortunately, we had prepared somewhat for power outages, prepared at least a little bit for power spikes.

For the outages, we had six Ryobi LED lanterns and six rechargeable 18V lithium battery packs to power them, as well as two little USB chargers that snap onto the battery packs, and six lanterns that use regular D batteries. So we had plenty of light. We had many large plastic jugs of water on a shelf in our utility room. And of course we had a lot of nonperishable food. We have a gas stove which we can light even when the power is out. We have a fireplace. We have wool socks and sweaters and other warm clothes. So there was no chance anyone was going to have to go without food or water, or get too cold. We even had a set of tubs ready for cold water dishwashing, and bleach tablets for a sanitizing rinse. So we were pretty well-prepared to live like we were in a campground cabin for a few days.

We don’t have a generator; we had one a few years ago that a friend gave us, but the kids broke it. I haven’t been super-keen to get another one. A small portable one will only power a couple of appliances, like our refrigerator, and require constant refilling with gas. And a big permanent installation is not at all cheap, requiring a concrete pad, and big changes to our main electrical panel.

The Grid, Off

It actually was a nice weekend, and I always find it a kind of relief when we can reduce the amount of artificial light we use in the evenings. We got some unusually good nights’ sleep. Because the days were sunny, and because our house is quite well-insulated, the temperature indoors never dropped below 60 degrees, even during the night. So no one was terribly cold. Elanor wasn’t very happy not to have access to cartoons, though. She kept turning the light switches on and we could not really explain to her that the probem was not the switches. But for the most part the kids weren’t too unhappy. We even had our usual movie night — we were able to watch a movie that I had up on my laptop, RRR. We couldn’t put it on the big monitor we usually use to watch movies on our Saturday movie nights, though — we had to watch it on my laptop screen. But it was a fun evening anyway.

On Sunday afternoon it didn’t look likely that I’d be able to work on Monday, so using my cell phone as a hotspot for my work laptop, I sent out an e-mail describing the situation. It turned out that our power did actually come back, late Sunday evening. It wasn’t immediately obvious that it was back on at first, because we had unplugged most things, and because about half the breakers in our electrical panel had tripped during the surges. But we got the lights back on, and started taking full inventory of the damage.

Every Outage Like a Setting Sun

Two UPSes were toasted — one of them, when I turned the breaker back on, immediately started arcing and buzzing and smoking again, so I got it unplugged. That was the cause of the smell of burning electronics in the basement. If you give it a shake, you can hear burnt components rattling inside. They must have popped like popcorn. I might take it apart and take pictures when I have a chance. That’s not what is supposed to happen when a UPS fails, but it did, and it’s not the first time I’ve seen a UPS fail to fail the way it is designed to fail. Another smaller UPS failed upstairs. It was the one my work computer was connected to. It didn’t make any noise but it did smoke a bit, and also had fried components rattling around inside it. I’m lucky that I had these UPSes in place — one of them protected my 15-year-old Mac Pro. The other protected my work computer.

A third UPS in the server room seems to have come through the power surges fine. That’s the one with our Synology NAS and the build server I use for all my writing. Everything on the build server and the NAS is backed up twice, on-site and off-site, but I’m very glad it survived; all this stuff would not be cheap to replace.

Yet another UPS, connected to our networking equipment upstairs, seemed to come through fine, but I have long wanted to replace it with something that is higher-capacity, so I’ve now done that.

A lot of light bulbs blew, in various locations all over the house, including our porch lights. So I’ll have to order more light bulbs, so we have enough of various types to replace them all.

The charger that I used to charge the six 18V lithium battery packs blew the same way the UPSes did — there are fried electronic parts rattling around inside of it. The thing we got to help keep us safe us during power outages was blown up by a power outage. Sing “Isn’t it Ironic.” The charger had all six of our 18V “high performance” 6 Ah lithium battery packs attached to it when it blew. We’re honestly lucky we didn’t have a lithium battery fire in our basement. I think the Ryobi packs are relatively safe — fear of lawsuits hopefully keeps the company on the straight and narrow — although they did have a recall for a similar type of battery pack a few years ago.

The overhead ceiling fan/light fixture in the family room is dead — I think we heard that one actually blow up inside with a loud bang during Friday night’s fireworks show. The one in our bedroom died in the same way. So we are still using the LED lanterns in the family room to eat our meals and some small reading lamps in our bedroom.

Our coffeemaker is dead.

Our electric kettle is dead.

The dishwasher is dead. Since we go through an awful lot of dishes, I sprang for a very nice Bose dishwasher, when the dishwasher that came with the house died. It wasn’t cheap. Under normal circumstances we should have been able to get at least another five years out of it.

We thought at first the refrigeratour had survived, because the light still comes on when you open the door, but the touch screen control panel is dead, and so we can’t even attempt to turn it on. I’m not sure exactly how old the refrigerator is. It came with the house, and I think the previous owner, who did the kitchen renovations, bought some of the appliances refurbished rather than new.

Even though it was on a power strip with a surge suppressor, the nearly-new Denon stereo receiver that I bought for the basement library last year is dead. I opened it up and found that there are two small fuses. Testing with a multimeter, of them seemed fine and one was blown. (I’m comfortable opening up stereo equipment to attempt to repair it, but refrigerators? I’d rather have a professional look at it.) I have ordered replacement fuses. If we’re lucky, a new fuse will bring it back to life. If we’re not so lucky, it has further damage due to the surge, and I’ll either have to find a service center locally that can fix it, or find a service center I can ship it to. The surge suppressor it was on is going in the trash — it didn’t do its job well enough.

Our very nice HP laser printer is dead. It also was not cheap — I got a high-capacity small office printer because we use it quite a lot for homeschooling stuff, and added a high-capacity paper tray.

Replacing all of this with new equivalents would cost a lot of money, so we will be talking to our homeowner’s insurance company. They play all kinds of games with depreciation and deductibles, so they probably won’t cover the cost of a new refrigerator. We can also look into whether anything can be repaired. But I think most modern appliances just aren’t made to be repaired.

Our little robot vacuum Larry apparently survived just fine. Strangely, it was missing for a while. I found it half-under a shelving unit in the basement utility room, with a dead battery and a full dust container. It looks like when the power failed, it decided that the best thing to do was to go clean as much as it could until its battery died. Poory Larry. I cleaned him up and put him back on his charger. I’m impressed with his work ethic. While we were sitting around in the dark, he was a maniac — a maniac, I tell you — on the floor. He was cleaning like he’s never cleaned before. That ice-blue line of insanity is a place most never see; a hard-won place of mystery, but home to one brave little robot.

Lost Work Time

While the power was back on, on Monday, the broadband was still down. I was able to get a slow Internet connection through the 4G cellular network. Between this, and scrambling to figure out what was broken and what I had to order immediately, I could not really get any work done on Monday, so I lost a day, and as an hourly contractor I get no paid time off. Later in the week I was able to make a few hours. But DTE’s deferred maintenance, and Xfinity’s poor infrastructure as well, are costing us more than just the cost of replacing fried appliances — they’re affecting my ability to earn income.

DTE’s deferred maintenance and underinvestment is now the stuff of legend. DTE is offering “some” people who had power outages lasting 96 hours or more a $35 credit.

I’ll no doubt have more to say about DTE in the future.

Living Without a Refrigerator

Meanwhile, we’re without a refrigerator. Fortunately, our standalone freezer survived just fine. We are buying fresh food more frequently, in smaller quantities and for the time being, keeping it in coolers right on our back deck.

We are, I hate to admit it, getting takeout and pizza delivery more frequently, even though that is costing us extra money. We’re using paper plates because keeping up with dishes for nine people, without a working dishwasher, is a lot of extra labor; the kids aren’t really stepping up, and Grace and I just don’t have it in us at the moment. The oven still works and the Instant Pot still works. Grace is baking bread regularly again.

We really should have had a whole-house surge suppressor. It’s something I have wanted to have installed, for years now, but since our pandemic lockdown began, we have only been having workers into the house when absolutely necessary. We’ve had HVAC repair folks a couple of times, and we’ve had people in to work on critter control in our attic. But upgrades like this, we didn’t consider critical enough to take the risk. We might have to go ahead and do that this spring. I am not at all confident I could do it myself safely; I have what I think is probably a healthy fear of working with 220V circuits.

Replacements and Upgrades

So far I’ve gotten the following replacements and upgrades:

We had a stupid situation with Best Buy. I ordered them for curbside pickup. We’ve been doing curbside pickup from Best Buy since the pandemic began — lots of items, including movies, and the UPS which is in our server room. When the UPSes arrived at the store I got an e-mail message telling me to come and pick them up. It even included instructions for curbside pickup, telling me to park in one of the pickup spots and sign in, and an employee would bring the items out to the car.

When Grace and I arrived to pick them up, I checked in using the link from the text message I had gotten on my phone. It took me to a web page which said that these items were not eligible for curbside pickup and I would have to go into the store to get them. We’re not doing that, so I attempted to call the store. No one answered in the store itself, and my call was bounced to someone working from home in Nevada. That person told me that she had no way of getting in touch with anyone in the store, because they don’t take any calls, including her call. So, I canceled the order, and we went home empty-handed.

I had not wanted to have UPSes shipped via UPS (haha), because they are extremely heavy items, and if they aren’t very well-packed, they will probably arrive broken (ask me how I know this.) When the refund came through and the money was back in my account, I ordered them from Staples. Staples delivered them the next day and they are now set up. One of them had some little plastic fragments or something rattling around inside it. I wanted to make sure there weren’t any loose screws or connectors, or something like that, so I opened it up. We managed to shake out whatever the bits were, but never found them. It seems to work fine, but the general build quality of almost all modern electronics leaves me not wanting to trust it.

I still would like to add a UPS for my Mac Pro to replace the other UPS that burned up, but it can wait. The Mac Pro is now on a Furman PL-Plus C rack-mount power conditioner. I have plans to phase out the Mac Pro eventually and replace it with something newer. It still works, but it can’t run current software, and even the Apple Mail client is becoming unstable with current e-mail content.

I would also like to add another PL-Plus C or equivalent for my podcast mixer, digital recorder, audio interface, and other music gear, but that can wait a while as well, as they are expensive. For now they are on new-ish APC brand power strip with surge suppression, which should provide a reasonable amount of protection.

If we can get the whole house surge suppressor soon, we will have multiple layers of protection for most of the electronic gear. High-current appliances like the refrigerator will be protected only by the whole house surge suppressor, but it’ll be better than nothing.

That’s probably all I will buy in the short term, at least until we get some feedback from our insurance company.

Tuesday, March 14th

I didn’t quite finish the text above yesterday; I went back over it today and cleaned it up. I have some down time at work today while I’m waiting for the code build pipeline to run, so I’ll give a few general updates

My Health

I am still able to work, but am concerned because of my ongoing symptoms.

Mental: I continue to have “brain fog” and problems keeping myself on track. Some days, I have trouble with words, even common words. My short-term memory has become distressingly poor. I have to keep detailed paper notes during my work day to remind myself what I am working on, and sometimes find myself in a state where I just can’t concentrate at all.

Physical: My most troublesome symptoms continue to be fatigue, numbness and burning in my extremities (mostly my feet), joint pain, and tinnitus. Yesterday, after the change Daylight Saving Time disrupted our somewhat fragile sleep schedule and sense of time, my feet were hurting a lot. It’s hard to describe, but my right foot hurt as bad as it did years ago when I broke it. I asked Grace to massage my feet for a while, and that seemed to help. She noted that my toes were alarmingly cold, which seems to support the theory that my “COVID toes” problem, which arrived suddenly last winter, includes damage to the circulation in my feet. Fortunately it seems somewhat improved today and this evening my toes were warmer and there was less pain.

I have been taking the enzymes nattokinase and serrapeptase as an experimental treatment, along with low-dose aspirin. The enzymes have not been well-studied in clinical trials (likely because they are inexpensive to produce, not patented, and so not backed by any major pharmaceutical companies), but this seems to be a fairly low-risk intervention, based on the theory that symptoms like mine are caused by blood clotting. In other words, I’m making the judgment call that the risks from excess clotting activity associated with long COVID, which can include heart attack, stroke, and damage to a variety of organs, are lower than the risks from taking the enzymes; there are very few reports of side effects from these enzymes. I came across a single report of anaphalaxis.

Are they working? Well, I think it’s difficult to say with certainty, for several reasons: this is a trial of one, and I can’t afford to test just a single intervention over time. But it does seem that I saw a lot of improvement after giving up on a previous regimen involving two antihistamines, which didn’t seem to help much, and starting the enzymes. In general my feet have been a lot better over the past few months, aside from this recent setback. Will this heal them completely over time, or will I have to keep taking them to lower the damage from an ongoing disease process? Millions of people with long COVID symptoms would love to know the answers to these questions, but I don’t have them.

I am able to climb stairs, but it wears me out quickly. Everything feels worse with exercise, when normally exercise would make me feel better. The exception is pain in my knees — every once in a while I’ll develop a lot of pain in my knees, and walking slowly on the treadmill seems to loosen that up, but I have to limit myself to just ten or fifteen minutes; before January 2022, I could walk for a couple of miles without getting tired. I have not felt up to putting together any bookshelves in the basement. Today I had trouble lifting a UPS. The weekend before last, after a fairly ordinary work week, I found myself so tired that I had to spend most of the weekend resting in bed.

I’m having some new weird immune-related symptoms. For example, I had to stop wearing my Fitbit because I started to develop a lot of strange irritation where the band touches my skin. It looks almost like a burn. I might try ordering a fabric band.

The tinnitus gets better and worse day to day. My vision has a similar intermittent problem, which seems to be due to chronic dry eyes. I can improve this for a while with some over-the-counter eyedrops. And I have an ongoing extreme sensitivity to noise that can result in a migraine, something I have very rarely experienced for most of my life, although I did have them in grade school. So, most days are a slog. I am still able to enjoy movies — more on that later — and music, the more harmonically and rhythmically complex the better, but once in a while I have to just lie down with a pillow over my eyes and ears.

Joshua’s New Guitar

Joshua has been playing guitar for over a year, and he’s been working with me pretty frequently, on duets. We only had my acoustic guitar in the house, so we couldn’t really play acoustically together. So a few weeks ago I bought him a new acoustic guitar.

I wanted him to have something decent, so I offered him four choices of instrument, all made by Godin in Canada. Any one of them would have been a decent choice. I really wanted to avoid more instruments made in China, Indonesia, Korea, or Mexico, but a decent guitar made in the United States was out of my price range. The one he chose was a nice Seagull instrument with a solid spruce top. I have not owned a Seagull model before, although I remember playing one in a music store a while ago — it might have been 15 or 20 years ago. I thought it was a decent guitar for the price, so I always wondered if I might wind up with a Seagull someday. It turns out that I didn’t, but Joshua did.

If you’re curious, the exact model is a “Maritime SWS CH CW Presys II.” The SWS stands for “solid wood series,” as the top, back, and sides are made out of solid pieces of wood rather than composites or plywood. I think the “CH” stands for “concert hall,” which indicates the size and shape — it’s about the same size as a dreadnought, but a bit narrower-waisted, and “CW” means it has a cutaway for access to the higher frets. The “Presys II” is the name of the Fishman pickup system that allows it to be plugged in. If you want to hear what it sounds like, here’s a demo video of a very similar instrument — I think the only thing that is different is the preamp.

It sounded a little too bright and brassy when it first arrived, but new acoustic guitars take a little breaking in before the wood really starts to resonate in the midrange and low frequencies. It has broken in a bit more and has a smoother midrange, with natural reverberation and very long sustain. I adjusted the truss rod a little bit to lower the action for him, and he’s continuing to practice regularly. We’ve been able to play together a few times and that’s been a lot of fun.

He has been trying to learn songs like “Good Riddance” and “Wake Me Up When September Ends” by Green Day, as well as some newer songs. I’ve been encouraging him to accompany himself while singing, which really takes steady work, but he’s getting there. Basically, I’m trying to teach him how to practice better, so he can get better faster and stay happy about his progress.

My first acoustic guitar was an old Yamaha that my mom picked up at a garage sale, when I was about twelve years old. The action was terrible. We took it to a shop for repair, and they tried to get it into shape with a neck press, but didn’t have much success, and it was never very playable. I learned a bit, but it always was painful to play. I wanted Joshua to avoid some of that frustration by starting out with something that is actually playable and sounds good. If he takes care of it, it will sound better with time, and might last him decades.

I Keep Practicing

I’ve been playing more as well, after another unintentional hiatus. I was hoping that I might feel ready to join the SpinTunes songwriting competition again, but that just didn’t happen — I realized that with my ongoing fatigue issues, I wouldn’t be able to put in the time. So I’ve been practicing and getting some of my old chops back, but very slowly. I’m hoping that playing an instrument regularly will help slow or reverse some of the cognitive damage that it seems like long COVID is doing.

I’m trying to learn some new songs and improve my own practice regimen. One of the new songs is Peter Gabriel’s “Solsbury Hill.” It has a very intricate, fast finger-picked acoustic guitar part that runs through the entire song. I was getting pretty good at finger-picking a number of years ago, and I still love the way it sounds, but now my progress is very slow. I have fully written-out score, which I actually paid for, showing the picking patterns, and I can play the chord shapes, but I’m having a hard time putting it together and getting it up to speed. The parts don’t go into my brain as readily as they did a decade ago.

It doesn’t help that the song has a somewhat unusual time signature — it can be written as mostly alternating measures of 3/4 and 4/4, but the guitar part uses mostly eighth and sixteenth, so when I’m slowing it way down I try to count the beats as groups of six and eight eighth notes, or even groups of twelve and sixteen sixteenth notes. That seems to help me work out the rhythm, but it is still difficult. It especially doesn’t help that the transcription I purchased, which has parallel music notation and guitar tab, seems to have perfectly accurate guitar fingerings in the tab, but completely incorrect rhythm in the music notation. This guy on YouTube shows a much more accurate transcription, and his is in 7/4.

Time signatures are slightly arbitrary in some sense — you often can write out a piece of music in different time signatures if they are multiples of one another, but there is usually one simplified form that most conveniently captures the rhythm in a way that conveys the intent and feel, and is reasonably “performer-friendly.” In the case of this song, I’m not convinced that alternating measures of 3/4 and 4/4 are the best way to think of it; it makes more sense for me to think of the bulk of the song as longer patterns in 7/4. Just don’t ask me to transcribe anything by Polyphia.

I’d Like to Teach Myself to Sing in Perfect Harmony

My music practice as “backslid” in other ways, too. Back when I was performing with the St. Francis church band, I was able to learn how to sing some simple harmony parts. I was able to apply this to other music — I could figure out harmony parts by ear, although I always have trouble singing them if they are extremely close. But when I was trying to learn to sing the harmony parts for “A Horse With No Name,” my “inner ear” was drawing a blank — I simply could not hear and repeat the pitch of the harmony parts, and they’re not that difficult. That was very frustrating. Finally, after listening over and over to isolated parts and tutorials, over many days, something came back and I could hear and sing the first harmony part, which is a third higher than the melody. I was able to record the two parts with a looper. I have not mastered the second harmony part. It is out of my range anyway, but I might be able to drop it an octave.

“A Horse With No Name” is a song I’d call “deceptively simple.” At first glance it sounds like it has only two chords. It actually has about nine. The 6-string guitar part is in an altered tuning, DEDGBD, and uses three fingerings, and a strumming pattern that is more difficult than appears at first glance. The 12-string guitar part is in standard tuning, using very different fingerings, so the combined chords, which include 6ths and 9ths, are very wide, with “jazzy” coloration, and droning pedal tones. Most transcriptions I’ve seen including some published in “fake books” get the chords very wrong, and even get the melody wrong, which ought to be hard to do, since it is so simple.

The verse melodies use only two notes, so it is pretty easy to sing, although there’s a little complexity to the rhythm in the original recording:

On the first part of the journey  
I was looking at all the life  
There were birds and plants and rocks and things  
There was sand and hills and rings

The first thing I met was a fly with a buzz  
And the sky with no clouds  
The heat was hot and the ground was dry  
But the air was full of sound

The first part of the chorus melody adds a third note:

I've been through the desert on a horse with no name  
It felt good to get out of the rain  
In the desert, you can remember your name  
'Cause there ain't no one for to give you no pain

The second part of the chorus melody consists of “la-las” and takes us all the way up to a full five-note pentatonic scale.

Somehow this progression from two notes to five serves the song very well — the very “dry” verses make our ears “thirsty” to hear some more notes against those spatious, ambiguously moody chords. So despite the superficial simplicity, it’s quite a satisfying song. Although the lyrics make me scratch my head — let’s just say I think they were made up quickly to fit the melody:

The ocean is a desert with its life underground  
And the perfect disguise above  
Under the cities lies a heart made of ground  
But the humans will give no love

As part of preparing for SpinTunes, I wanted to record a full multi-track cover of “A Horse With No Name,” as an exercise, to make sure I know how to use the latest version of Logic Pro, practice recording a percussion track, test out the process of feeding a mix through the bus compressor in my SSL SiX mixer, and verify that I have all the software plug-ins I need and know how to use them. But again, this requires a lot more energy than I have right now, and the ability to sacrifice some sleep without suffering too much in the way of long-term consequences, which I don’t have right now.

Tomorrow I want to talk about some films we’ve seen in the last few months, and more music I’ve been listening to — mostly, an awful lot of “prog rock.”

Wednesday, March 15th

Daylight Hating Time

Are we ever going to get rid of the nightmare that is Daylight Saving Time? It seems like it is harder and harder every year to adjust to this shift. Supposedly there is legislation pending. But the legislation would make Daylight Saving Time permanent. I think it would be much better to make Standard Time permanent, and I’m not the only one.

In particular it is hard on parents of young children. Grace and I can try to shift our sleep schedule over several days leading up to the change, and the older kids can do this, or at least not keep us awake while we do it. But there is no explaining the time change to Elanor and Malachi. They can’t understand why everyone is going to bed while they still feel like racing around the house burning off energy. And so for several nights now, the babies have been keeping us up until almost two o’clock in the morning, reversing the slight improvement in our sleep schedule that we gained during the power outage, when the lack of bright lighting in the evenings helped us get the kids to bed earlier. Not that I’m advocating for year-round power outages, but if I had my way we would use a lot less bright overhead light in the winter and do most of our late-evening activities by candlelight. It would be nice if the LED lanterns were warmer-colored lights (longer wavelength), but they are bright white LEDs, which even on the lowest brightness setting produces shorter blue wavelengths of light, which is associated with disrupted sleep in the evening.

I also have to remember to cover up the white LED on the power button of the new UPS in our bedroom. A single blue or white LED on in the bedroom while I’m trying to sleep can disrupt my night’s sleep considerably, while red and green LEDs have no noticeable effect. I have tried wearing a sleep mask, but it became uncomfortable after a while. Lately I’ve been sleeping with a pillow covering my eyes for the latter part of the evening, and that helps.

Work Update

I am still working. I am grateful that this job has been pretty low-stress to date. There are some downsides to this, though — I am working withough very many people I can go to for assistance. Some key staff that knew a lot about the projects I’m working on have left, and the most knowledgeable members of the current staff are overloaded and it’s been difficult to get any of their time. Project planning seems a bit weak, as I currently don’t have enough tickets to work on, and there are issues in finding projects where I’m permitted to bill my hours.

On the more plus side, I’ve gotten quite a bit of positive feedback about my work. I think it’s possible that I might be offered direct employment at some point, which would presumably include decent health benefits. Assuming I can negotiate a salary close to what I am earning how as an hourly contractor, that would result in a huge improvement in our monthly cash-flow situation, since I am currently spending almost $2,300 a month to continue our health insurance programs via COBRA. This means that in months like this one, with big unexpected expenses, we are bleeding more money from our savings. I hope to be able to recharge our savings a bit in the next few months, but much will depend on what happens with our insurance claim for damaged appliances.

I’m also cognizant of how, when I worked for Argo AI as a contractor, I received much less supervision, and had more freedom to set my own day-to-day priorities and get a lot of code written, than when I was an employee, being badly micro-managed by an abusive boss, and held responsible for more work than I could reasonably complete in a eight-hour work days. I see promising signs that the culture of my current employer is much different, but I am keenly aware that the amount of “overhead” — meetings, training, paperwork — that employees have to keep up with tends to be much higher than the burden on contractors. And being stuck in a job where I don’t get to do enough interesting work is, to me, in many ways just as bad or worse than being stuck ina job where I have too much work. So if I do get an offer, I’ll want to consider it very carefully, and I really should be continuing to explore other options, although as usual doing that is like trying to work a second job during the same hours as my main job.

Some Films — Well, OK, a Lot of Films

I haven’t been keeping up with any kind of journaling about films we’ve watched recently, so I’m going to try to quickly write out some very short capsule reviews. I want to have some kind of record of what we’ve watched, because I know from my own experience I have often wanted to track down films that I recall watching, but could not recall the titles, and that has been very frustrating.

EO (2022 Film)

This surreal live-action Polish film about the life of a donkey is, in my view, highly overrated. It has some wonderful shots, and beautiful outdoor cinematography, but not enough of a story to be really compelling. Although it is superficially a story about a donkey’s life, it keeps leaving the donkey character behind. Sometimes it follows human characters for a while, but never for very long, it leaves them behind, too, before we learn much about their stories. Because of this, in my view the meaning that remains is mostly about the dramatic contrast between the more traditional rural landscapes and ways of living in Poland, and the more modern degraded post-industrial hellscapes.

In both kinds of places, human beings behave horrifically towards animals, and towards each other. That’s not really a new insight, and the implicit animal rights message conveyed by these dissasociated scenes and images doesn’t in isolation, make for a strong film.

At one point we follow a drone through some beautiful shots taken with a red filter, as it soars high above wind turbines and speeds through a wooded landscape in scenes reminiscent from Dave Bowman’s hallucinatory journey in 2001: A Space Odyssey. In another, we follow a Boston Dynamics robot as it runs around in tall grass. We see caged foxes being anally electrocuted and thrown onto a cart; no animals were actually harmed in the making of the film, the title cards assure us. We see a donkey watch a water pouring through the spillway of a dam as the water slows, stops, and then reverses.

What does it all mean? As far as I can tell, not much. It may have something to do with a filmmaker, very late in his career, reflecting on his wish to reverse time before he has to go into the darkness himself, like the eponymous donkey in the grim final scene. I have no idea how the director actually feels about his life and career, but I know how I feel about this film — I couldn’t really assemble the pieces into an enjoyable viewing experience.

I tried to determine before watching it if it would be safe for children. What I read about it initially suggested that it was, but it really is far too dark. I should have chosen something else. Fortunately they lost interest early and didn’t watch it that closely. I should have done the same thing. I probably would have liked this film a lot had I seen it in a theater, in my twenties; I would have come up with all kinds of theories about what it means. These days, I’m more inclined to want to simply enjoy a good story, about either people or animals or both, and this film doesn’t tell one.

The General (1926 Silent Film)

This Buster Keaton film is so entertaining that it’s easy to overlook the fact that it is actually, under the surface, a piece of “lost cause” propaganda. Still, the younger kids seem to love silent film mayhem with its death-defying stunts. The incredible action happening on-board a moving train takes on a slightly different feel in light of the recent train derailments. This one is a lot of fun, but my absolute favorite silent film remains Safety Last! from 1923, starring Harold Lloyd. If you haven’t seen that one, run, don’t walk, to get a copy. Climb a a building and hang from a giant clock if you have to.

Yes, Madam! (1985 Film)

This is a Hong Kong Kung Fu police drama, similar in plot and style to Jackie Chan’s Police Story films. I’m not going to say it’s a great film, because it’s not. The filler scenes are full of really dumb dialogue and clownish stereotypical characters. But it has some truly amazing fight scenes in it. Michelle Yeoh does her own stunts, and many of them appear incredibly dangerous, involving large amounts of broken glass. I think it is probably “stunt glass,” which used to be made of sugar but is now often made of some brittle plastic that breaks like glass but does not produce razor-sharp fragments, but those falls still must have been very dangerous. We watched this film because it is part of the Criterion Channel’s “Starring Michelle Yeoh” playlist. You can find it here. I want to get through a few more of them. I’m especially interested in The Stunt Woman from 1996, which is semi-autobiographical and shows how some Kung Fu stunt work is done.

Deep End (1970 Film)

This is a strange coming-of-age drama directed by Jerzy Skolimowski. I really appreciated the style of the film — it is set in a London swimming pool and bathhouse of a type I didn’t even know existed, and the location and the two main characters were fascinating. But it became much too melodramatic for my taste, and started to seem unconvincing, so I couldn’t finish watching it.

Boy and the World (2013 Animated Film)

This is a Brazilian film and it is largely wordless, and doesn’t need a lot of words. The animation style is wonderfully impressionistic. It gradually builds a very potent case against the industrialization of Brazil, showing what it has done to the traditional culture, land, and work. Ultimately it is an extremely powerful, political film, although it all comes down to a simple story of one boy’s life. I recommend it very highly. The soundtrack is simply wonderful. Benjamin came to us the next day and told us that the film “made him sad,” and we told him that yes, indeed, it was actually a sad film. So he was actually paying attention and processing the message!

Watership Down (1978 Animated Film)

I read reviews that described this film as extremely dark, and two frightening and depressing for children. We watched it anyway, and while the story is pretty dark, the animation is really beautiful and affecting, and despite the deaths of many rabbit characters, it ends on a hopeful note. The kids enjoyed it quite a bit and no one complained of nightmares.

Eleanor’s Secret (2009 Animated Film)

This is a French animated film. The story takes place after the death of two siblings’ eccentric Aunt, as the family stays in her cottage. The younger sibling, a boy named Nat, can’t yet read, and his Aunt’s fondest wish for him was to learn to read. She leaves him the key to a secret room in the middle of the house — a secret room which turns out to be an absolutely enormous library filled with priceless first editions of classic children’s books. He is not very excited about this, but things start to get truly interesting when the characters in the books, including Peter Pan and Alice from Alice in Wonderland, emerge from the books, asking for Nat to help save them from disappearing forever. It’s a wonderful story about how individual books are ephemeral, but the stories in them are kept alive by successive generations of readers who love them, and how that love of reading is passed down in families.

Songs for Drella (1990 Concert Film)

I realize that this really isn’t for everyone. A concert of deadpan songs written and performed by Lou Reed and John Cale, commemorating the life and weird times of Andy Warhol, with minimalist music and nearly-spoken words, is going to be hard for many people to enjoy. I already owned the album, though, and find this to be a beautiful example of how our stories can live on in the retelling of the people who loved us, warts and all, no matter how weird we are.

The Big Bad Fox and Other Tales (2017 Animated Film)

This is an adorable, funny, and sweet French animated film featuring three shorter stories presented in a framework.

April and the Extraordinary World (2015 Animated Film)

Another French animated film, this one features a Jules Verne steampunk setting, and terrific animation and art direction. It includes a number of visual references to other animated films such as Miyazaki’s film Howl’s Moving Castle. Part of the fun of watching it is taking note of all the references, but it will also stand alone as an enjoyable adventure story.

The Wolf Children (2012 Animated Film)

This Japanese animated film is wonderful and we’ve watched it twice.

Penguin Highway (2010 Animated Film)

I enjoyed this Japanese animated film, but I can’t say it is one of my all-time favorites. The story gets very weird. If you’ve seen a lot of anime films, you’ll realize that this one is replaying many common anime tropes, mashed up in a recipe that doesn’t quite ever produce a satisfying dish.

Belle (2021 Animated Film)

This was a very big film in Japan, the highest-grossing anime film of 2021. The kids enjoyed it, but when I realized that it was essentially a re-telling of Beauty and the Beast with the addition of social media, I lost interest. The title should have been a tip-off, as Belle is the name of the protagonist in the 1991 Disney version of Beauty and the Beast, a reference to the original French title, La Belle et la Bête.

Tokyo Godfathers (2003 Animated Film)

I had never seen this film before, but had heard about it. It is now one of my favorite animated films. It’s a strange, gritty story involving people living rough on the streets of Tokyo, who discover an abandoned baby. That might make it sound kind of grim, but it is really a comedy, and not a dark comedy. It features a transgender character, played by a transgender voice actress. As the film opened I was worried that the portrayal was going to be awful, but it is actually terrific, very sympathetic and moving. The screenplay is one of the best I’ve ever seen, in which all the wild threads of the story come together in a perfect knot in the glorious finale. I highly recommend this film.

I know we’ve seen more films than this over the last few months, as we have a movie night every weekend, but I can’t come up with any more titles at the moment, so this will have to do for now.

A Wild Refrigerator Appears

A friend gave us a used refrigerator from Habitat for Humanity! That will make things a bit easier for a while!

We now have two refrigerators in our kitchen, which is a bit awkward. We don’t want to haul away the original refrigerator before we have feedback from our insurance company on what we need to do with it; they may want an appliance repair person to determine if it is repairable, or determine if the failure was due to the voltage surges. Also, the original refrigerator is plumbed in because it has a water dispenser and ice maker. So we can’t just pull that out the way we can pull out a power cord. We have never actually used these features and they have been turned off since we moved in, because we didn’t want babies dumping water or ice all over the kitchen floor. We can’t foresee a future where we would ever want this function in our kitchen, actually, especially that making messes is one of Elanor’s favorite hobbies.

I am not confident trying to shut off, disconnect, and drain the water line. It’s a thin food-grade plastic hose that runs into the kitchen floor, probably into a bump-out in the basement ceiling that seems to hold hot water pipes for heating. We can peer into the bump-out with a flashlight, from the utiilty room, and we can even see into a different portion of the ceiling that remains torn open from the washing machine flood in 2017 days after we moved in, but we cannot find any evidence of this water line. I am pretty sure the previous owner would have installed this himself, the way he installed many things, in as stupid and haphazard and non-code-compliant a way as possible, the same way he installed the drain in the laundry room floor that wasn’t connected to the drain pipe, the bathroom vent fans that don’t seem to actually do anything, and the ordinary-looking power outlet upstairs that had a rather surprising 220 volts AC connected to it.

We might need to get a plumber in to try to figure this out. I don’t want to accidentally start a slow leak in the kitchen floor/basement ceiling. I would just like this water line disconnected and removed completely so it never poses a leak hazard; one wall of our basement library bookshelves sits under the bump-out in the basement ceiling, and the opposite wall sits under a similar bump-out that accommodates the kitchen sink plumbing. There’s really no way to avoid this hazard to our books, since there are pipes running along most of the walls that are suitable for bookcases. I’m not sure it is possible to undo whatever the previous owner did without actually tearing open either the kitchen floor or the basement ceiling.

Thursday, March 16th

I realized that yesterday I missed a staff meeting. The staff meetings occur every couple of weeks during the time I usuall break for lunch. Normally I just delay my lunch, but yesterday I went downstairs a bit earlier than usual and missed the Outlook calendar reminder, proceeded to have lunch, and by the time I got back to my desk, I had missed the whole meeting. Oops. My ability to remember meetings hasn’t been quite right for a while.

I was looking at pictures on my phone and realized that we had another, shorter outage on November 30th, because I took a screen shot of the outage map. We’ve had an awful lot of outages over the last few years.

I recalled a couple more movies we have watched in the past few months:

Avatar (2009 Film)

We watched Avatar, the first one, not the new Way of Water sequel. I had never actually seen it. I did see a short part of it, years ago, in, of all places, an appliance store TV showroom.

It’s a more radical movie, politically, than I expected from a blockbuster. Some of the computer animation already looks a bit dated to me. It’s still impressive. The immersive environments are impressive as well, and the alien life forms. There are some great fight scenes. It’s a blockbuster, with all that implies. At two hours and 42 minutes, is quite a long film but, to its credit, doesn’t drag. I didn’t hate it.

On-Gaku: Our Sound (2019 Animated Film)

Our Sound is one of the funniest, most original anime films I’ve ever seen. Three bored and disaffected Japanese high school boys stumble across an electric bass, entirely by accident. They steal another bass, not realizing that it isn’t a guitar, a couple of amplifiers, and some drums. Now they’re in a band. None of them know anything at all about how to play an instrument or sing. They attempt to make up for this entirely in raw rock-and-roll energy, and it actually kind of works. They certainly have raw rock-and-roll energy.

The real delight in this film is the anarchic way that the art style explodes with creativity to illustrate the music, throwing in all kinds of references to classic progressive rock. The band semi-accidentally winds up scheduled to play their song at a local rock festival. By all rights it should be their moment of greatest humiliation, but the rock-and-roll energy becomes contagious, so it becomes a moment of pure musical transcendence. The film won best feature at the 2019 Ottawa International Animation Festival and has a 100% rating on Rotten Tomatoes. It deserves many more accolades for its deadpan humor and delightfully unrestrained art direction.

Friday, March 17th

Star Trek: Picard Season Three

I should also mention that we’ve been been watching the new season of Picard. Season two was extremely disappointing. This one, so far, is not! I have minor quibbles with the screenwriters about a weird villain character who seems to have no justifying backstory, but mostly I’m very pleased with this season, and we’ve seen several very enjoyable, tightly-paced, exciting episodes in a row. I have high hopes that the remaining episodes will follow this trend. If they do, this will be one of the best seasons of any Star Trek show. This is the final season of Picard, and so it has to wrap up the story arcs of Picard and multiple supporting characters. That’s a lot to accomplish in just six more episodes, but what I’ve seen so far has left me cautiously optimistic.

Update on the Stereo Receiver

I got the replacement fuses for the stereo receiver. They have the exact same part number and markings as the fuse that was blown. Unfortunately after putting in the new fuse, and plugging in the receiver, the fuse blew again immediately with a little arc flash. So, there’s more wrong with the power circuitry than just a blown fuse. I’ll have to figure out a next step for the receiver. Hopefully insurance will help cover either repair or replacement. There’s a single authorized Denon service center in the state of Michigan. It’s almost an hour drive from here but it might be a fun road trip for people who don’t get to do a lot of road trips these days.

Monday, March 20th

The weather was very strange this weekend. The forecast did not call for any snow on Saturday but we had snow squalls blowing through. Grace and I ran errands on Saturday, picking up farm eggs and groceries from GFS. We went through Cristy’s drive-through to get a burger for Grace and a couple of their chicken sliders for me. In general we don’t eat a lot of fast food, but if you find yourself in need of a burger or similar fare in the Ypsilanti area, we recommend Cristy’s.

It wasn’t a huge grocery weekend, as we didn’t need to refill our pantry much, but we did pick up more pasta and cans of crushed tomatoes. Grace also roasted a turkey from our freezer in the standalone electric oven, so we have a lot of turkey meat and turkey broth. I ordered six bags of popcorn from GFS without looking closely at the weight of the bags and it turned out they are absolutely huge. So, we’ll have popcorn for a while. If the kids don’t eat it all this week, we’ll have some left for next Saturday’s movie night.

We constantly try to get through chores and cleanup and dinner early on Saturday so we can leave time for two movies, but it usually doesn’t work out; we’re usually starting movies very late. We watched the next episode of Star Trek: Picard season 3, called “Imposters.” This was another great episode, featuring Michael Dorn as Worf and Michelle Forbes as Commander Ro Laren, two very welcome blasts from the past.

After Picard we wanted to watch something short, so I picked another Buster Keaton silent film on the Criterion Channel streaming service. I don’t know much about his work, so I picked Three Ages because it was 64 minutes long.

Three Ages (1923 Silent Film)

Three Ages is a small comic masterpiece of the silent film era, loaded with silly gags. Some haven’t aged well, since they involve various kinds of bigotry or abuse, including animal abuse, but many of the funniest ones remain timeless. In one of my favorite gags, Buster Keaton re-enacts the story of Androcles and the Lion by giving the lion a pedicure. The lion is played by an actor in an extremely unconvincing lion costume.

The film intercuts three plot lines, set in three historical periods: prehistoric times, Ancient Rome, and the Roaring Twenties. Per Wikipedia:

In all three plots, characters played by the small and slight Buster Keaton and handsome bruiser Wallace Beery compete for the attention of the same woman, played by Margaret Leahy. Each plot follows similar “arcs” in the story line in which Keaton’s character works for his beloved’s attention and eventually wins her over.

Don’t worry too much about following the parallel plots; they are only loosely connected. The film structure is best thought of as a framework linking together a number of very silly chases and situations and sight gags. I think it very likely influenced Mel Brooks when he was making his equally silly 1981 film History of the World, Part I. As an aside, History of the World, Part I ends with a fake trailer for History of the World, Part II, indicating that it is “coming soon.” It took 42 years, but Part II really exists now in the form of a sketch comedy show on Hulu. Mel Brooks is now 96 years old!

The film is quite deteriorated in parts but is still watchable. It is actually viewable for free on the Internet Archive, a non-profit that I support financially with a small donation every month, and I urge you to do the same if you can afford a small donation, and you find their work to be as valuable as I do.

Tuesday, March 21st

Continuing my account of what happened this weekend, on Sunday we had a big bonfire. What with all our deliveries and pick-ups recently — IKEA bookshelves, replacement electronics, wire storage shelves, food pickups, etc. — we’ve been accumulating a lot of cardboard boxes faster than we can recycle them. We also had some flimsy wooden shelving that we disassembled. We’ve had a huge pile of cardboard and wood sitting outside by our burn pit, with more piled up in the house. We’ve been waiting for the stuff outdoors to dry out, but it has snowed, rained, and frozen over and over again, and it might be a long while before it is truly dried. So on Sunday we went ahead and made a big bonfire with dry cardboard and wood and fed in the wet cardboard a bit at a time. It all burned eventually although it took a while. That was fun.

If the weather had been more cooperative, this would have been a great weekend to at least get started on garden bed preparation. We have two metal fire rings we were using as raised beds that were destroyed by delivery trucks. Our driveway is quite wide and there’s a whole separate space for turning around, but they still managed to drive right over our lawn into the garden and flatten the fire rings, even when they are quite visible and aren’t buried by snow. I need to clean them up. I won’t replace them in the same spot. Next year I’ll have to leave some orange fiberglass marker poles in place. Those should be more obvious in a rear-view mirror, although I have a feeling that exhausted and sick delivery drivers will still find a way to fail to notice them.

Back to BASIC

I’m going to wind up this newsletter, since it’s just turning mostly into journal entries, but I’m going to close out with a super-nerdy topic: a BASIC computer game I first came across about 45 years ago. It would have been back in 1978 or 1979 when I owned a copy of a book of BASIC programs, written by a cast of several (including some people who were high school students at the time), and edited by David Ahl, called BASIC Computer Games: TRS-80 Edition. I recently set up a saved search on eBay for that book. In the past, I had occasionally searched for copies, but only found copies that were very expensive, in poor condition, or from overseas sellers, with prohibitively expensive shipping. But just recently a listing appeared that had both the original and the even harder-to-find sequel, for a price I thought was quite reasonable, so I bought them immediately.

I did a little demo of this game for Sam and Pippin, using a TRS-80 emulator. I was trying to show them what it was like to program early home computers back in the day, warts and all. I spent a lot of time typing in programs from magazines and books, and then debugging them, because getting a program typed in perfectly, from a shrunken reproduction of a dot-matrix printout, on the first try, is nearly impossible. Being forced to debug them was what really forced hobbyists, with no previous background in programming, to become experts. I’m pretty rusty and my eyes are much worse than they were in 1978, and I don’t remember some of the little tricks you can use to edit BASIC programs on a TRS-80, so I only was able to get it partially working during that little demo, although I did manage to fix it later.

The program I was demonstrating is called Animal. If you want to give it a try, you can find the source code here. I know that David Ahl has made at least one version of his source code available to the developer of Vintage BASIC for distribution, but I haven’t seen a clear indication that he has placed all the BASIC games, in all their various versions, in the public domain, so I will not include the source code from the TRS-80 edition in this article. If you want to see the exact version of the code that I’ve been running, the Internet Archive has it here. Unfortunately, it’s a pretty fuzzy scan.

Here’s a sample session playing the TRS-80 version of the game using an online TRS-80 emulator to give you an idea of why I found the game interesting, and still do. The original TRS-80 only supported uppercase letters, unless you installed a clever third-party product, but for clarity, in this log, I have left the computer’s output uppercase, but changed my input into lowercase:

PLAY 'GUESS THE ANIMAL'
THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT
ARE YOU THINKING OF AN ANIMAL? yes
DOES IT SWIM? yes
IS IT A FISH? yes
WHY NOT TRY ANOTHER ANIMAL

ARE YOU THINKING OF AN ANIMAL? yes
DOES IT SWIM? yes
IS IT A FISH? no
THE ANIMAL YOU ARE THINKING OF WAS A? penguin
PLEASE TYPE A QUESTION THAT WOULD DISTINGUISH A PENGUIN FROM A FISH
? does it look like it is wearing a tuxedo
FOR A PENGUIN THE ANSWER WOULD BE: yes

ARE YOU THINKING OF AN ANIMAL: yes
DOES IT SWIM? yes
DOES IT LOOK LIKE IT IS WEARING A TUXEDO? yes
IS IT A PENGUIN? yes
WHY NOT TRY ANOTHER ANIMAL

etc.

As you can see, the game cleverly builds up a database of animal names along with questions it can use to filter the database. Each question must have a simple “yes” or “no” answer. With each question the game presents, it eliminates animals until there is a single candidate remaining. If the remaining candidate is not the right answer, it prompts the user to enter a new animal into its database.

It’s not entirely obvious from reading the source code how this works, as old versions of BASIC required variable names that were quite opaque, and the original game did not contain any comments. So, allow me to clarify it a little bit. The initial database can be seen by typing “LIST” at the “ARE YOU THINKING OF AN ANIMAL?” prompt:

ANIMALS I ALREADY KNOW ARE:
FISH    BIRD

Looking at the BASIC source code, you can find where these two starter database entries are defined, and this gives the reader a starting point from which to unpack the way the program works:

600 DATA"4","/QDOES IT SWIM/Y2/N3/","/AFISH","/ABIRD"

We see that the following strings are defined:

"4"
"/QDOES IT SWIM/Y2/N3"
"/AFISH"
"/ABIRD"

These are used by the program’s startup code:

80 CLEAR 5000: DIM A$(200)
90 T=1
100 FOR I=0 TO 3
110 READ A$(I)
120 NEXT I
130 N=VAL(A$(0))

These strings are put into the array of strings called A$. In this early dialect of BASIC, we know that A$ is an array because of the DIM (dimension) statement, which indicates it is a one-dimensional array of 201 elements, and because it is usually accessed using a subscript in parentheses. Why 201 and not 200? That’s another oddity of BASIC; the first element of the array is accessed with the subscript 0, but DIM allocates one extra element so that the highest subscript you can access is the same as the dimension.

Confusingly, plain old A$ is also used in this program to hold user input, and it is a single string, not an array.

Also confusingly, the initial value of N is placed, in string form, in the first string in the array of strings, at subscript 0. This string is updated when new animals are added to the array. Why is it kept here, instead of in a separate variable? I don’t know.

BASIC Considered Painful

It’s funny to think back on it, but from my perspective in 2023, this BASIC code from the 1970s reads more like a assembly language, with a few macros to support commonly used functions such as printing. This BASIC programming is not nearly as bad an example of “spaghetti code” as many of the published programs I used to type in, but even so, it’s more opaque than most assembly-language programs, because most assembly-language programs are thoroughly commented.

Comments ate up valuable memory and required extra typing, so they were often omitted. Many things were sacrificed in the name of saving memory. And don’t get me wrong, I really admire what the folks who developed code for these early home computers were able to accomplish! But let’s not pretend that the surviving artifacts of that era are all that easy to understand.

Aside from the FOR…NEXT loops, TRS-80 BASIC code doesn’t even follow the basic tenets of Structured Programming, much less functional programming or object-oriented programming. Perhaps it’s not surprising that I found it relatively easy to start teaching myself Z-80 assembly language programming, alongside BASIC, back in the late 1970s as well; it wasn’t necessarily harder to understand than highly condensed BASIC code, and was often easier to understand.

I should point out that there are more modern versions of BASIC that do support more modern programming styles. You can get rid of line numbers, and factor your code into functions. The original Microsoft Visual BASIC, which I used back in the early 1990s, was much easier to use, and the programs I wrote in it were much more readable and maintainable.

How the Animal Program Works

Anyway, “DOES IT SWIM?” is our initial question, stored without the question mark, with the header “/Q” indicating that it is a question, and followed by indexes for which table entry to look at next for “YES” and “NO” answers. This follows the initial behavior: if you answer “YES” to the first question, the program will ask whether the animal is a fish (index 2), or else whether the animal is a bird (index 3).

Inserting a few lines to dump out the contents of the A$ array, it becomes clearer what is happening as the program runs:

A$ NOW CONTAINS:
4
/QDOES IT SWIM/Y2/N3
/AFISH
ABIRD

ARE YOU THINKING OF AN ANIMAL? yes
DOES IT SWIM? no
IS IT A BIRD? no
THE ANIMAL YOU WERE THINKING OF WAS A ? BAT
PLEASE TYPE A QUESTION THAT WOULD DISTINGUISH A
BAT FROM A BIRD
? does it catch bugs using sonar
FOR A BAT THE ANSWER WOULD BE ? no

A$ NOW CONTAINS
 6
/QDOES IT SWIM/Y2/N3
/AFISH
/QDOES IT CATCH BUGS USING SONAR/Y 5/N 4
/ABIRD
/ABAT

ARE YOU THINKING OF AN ANIMAL? yes
DOES IT SWIM? yes
IS IT A FISH? no
THE ANIMAL YOU WERE THINKING OF WAS A ? seal
PLEASE TYPE A QUESTION THAT WOULD DISTINGUISH A
SEAL FROM A FISH
? does it breathe water
FOR A SEAL THE ANSWER WOULD BE ? no

A$ NOW CONTAINS
 8
/QDOES IT SWIM/Y2/N3
/QDOES IT BREATHE WATER/N 7/Y 6
/QDOES IT CATCH BUGS USING SONAR/Y 5/N 4
/ABIRD
/ABAT
/AFISH
/ASEAL

Note that the program is rearranging the elements of A$. It’s doing this to maintain a binary tree structure, hidden in the array, that reflects the order in which the questions should be asked. This ensures that it doesn’t ask redundant questions. The questions are the inner nodes of the tree, starting from the root, which is always “Does it swim?” The animals to guess are the terminal nodes, or leaves of the tree.

Most of the opaque logic of the program becomes clear when you realize that it handles inserting items into an array, moving items around to make space for the new items. This becomes inefficient as the number of array entries grows larger, but given that we don’t have enough memory to add thousands or millions of questions to the tree, inserting a new question probably won’t take more than a few seconds, and asking questions should never take very long, because for each question the program just follows an index to read one question out of the array.

And Onward to Python

Just to see how hard it would be, I wrote a Python version. It only took me a couple of hours to get a program that worked correctly, but I spent a few more hours over the next couple of days tidying up the code, refactoring it into smaller functions, and improving the comments; I wanted the chance to sleep on it and come back to it with fresher eyes.

I first started by writing the routine to print out the tree, and once I had that, the rest was very easy, except for the slightly tricky logic that inserts new questions. The function that inserts a new question into the tree needs to keep track of whether the guess that failed is the “yes” leaf or the “no” leaf of the parent question. In the Python version I handle this by the insert_new_yes_branch_q_node() and insert_new_no_branch_q_node() functions. In my first version, I used a smaller number of longer functions, with more branching, but I have refactored it so that the functions are very short, to try to make the logic as easy to follow as possible.

Following the behavior of the BASIC program, the root question node is never replaced — that is, the original program always starts off by asking “DOES IT SWIM?” This means the tree can become unbalanced. It would be an interesting upgrade to the program to have the program always rebalance the tree when it adds questions, so that it always asked the minimum necessary number of questions to reach an animal to guess. If I wanted to do that, I’d probably go ahead and convert it to use idiomatic Python objects, to make it easier to treat the nodes uniformly, and then I’d probably break it into multiple files. But for now I wanted to avoid the extra boilerplate that is required for object-oriented programming in Python. I like many things about Python, but not the way it handles OOP.

My program is over twice as long as the original, if you count lines of text, but a lot of those lines are comments and whitespace. It’s broken into functions. I know that I’d much rather type the Python version into a computer than the BASIC version — and modern tools like Visual Studio Code, which does syntax highlighting and indicate a lot of problems and possible solutions while you’re typing the code, makes it far, far easier to debug than the BASIC version. I’m not going to claim that Python is the ultimate language — there are a lot of things about it I don’t like, mainly having to do with the lack of strict typing, which leads to failure to catch many errors prior to runtime. But at least I have source-level debugging and can watch variables change as I step through code. Looking back at how I used to have to write and debug programs, it is most definitely an improvement in many ways!

"""
A very simple version of the classic Animal guessing game, originally published
in various editions of David H. Ahl's _BASIC Computer Games_ books back in the
1970s.
"""

import sys

# The original program used a BASIC DATA statement to populate an array of
# strings that serve as tree nodes, and refer to each other by array indices.
# This Python version implements the same initial tree nodes using
# dictionaries. There are two kinds of nodes: question nodes, which always
# appear in the tree with two leaf nodes, and guess nodes, which are the
# leaves.
#
# Following a path through question nodes, the program asks a series of
# questions to narrow down the options, until it reaches a guess node, and
# presents an animal name to the user. If the guess is incorrect, the program
# replaces the original guess node with a new question node that has as its
# leaves the original guess node, and a new guess node created with the animal
# name the user types.
#
# In this way, as the user interacts with the program, the tree will grow. The
# original program never replaces the root node, and the tree is never
# re-balanced to minimize the number of questions it takes to get to a guess.
# "Does it swim?" is always the first question. I have kept that behavior, but
# support for re-balancing the tree would be an interesting future upgrade to
# the program.
g_node_fish = {"A":"a fish"}
g_node_bird = {"A":"a bird"}
q_node_root = {"Q":"Does it swim?",
               "Y":g_node_fish,
               "N":g_node_bird}

# Convenience functions for reading and formatting user input of various kinds.
# The original program didn't do much to clean up user input, so we don't
# either, assuming a cooperative user, but we're not as obsessed with saving
# every possible byte, so we do a few things differently:
# - We keep whatever the user types as the animal name, so you shouldn't see
#   incorrect grammar like "a octopus" unless the user typed it that way.
# - We turn animal names into lowercase, so the computer won't ask "Is it An
#   octopus." This could results in incorrect capitalization for animal names
#   containing proper nouns; for example, if the user types in "a Jack Russell
#   terrier," the guess will be "Is it a jack russell terrier?" The alternative
#   would be some kind of validation of animal names, which is out of scope for
#   this simple program.
# - We make sure that when we request a question from the user, it starts with
#   a capital letter and ends with a question mark, so if the user typed "does
#   it have four wings and fly," the question will be stored as "Does it have
#   four wings and fly?"
def get_one_word_answer() -> str:
    return sys.stdin.readline().strip().lower()

def is_answer_affirmative(answer_str:str) -> bool:
    return answer_str[0] == 'y'

def is_answer_tree(answer_str:str) -> bool:
    return answer_str[0] == 't'

def get_answer() -> str:
    return sys.stdin.readline().strip()

def get_animal() -> str:
    return get_answer().lower()

def get_question() -> str:
    q_str = get_answer().lower().capitalize()
    if q_str[-1] != '?':
        return q_str + '?'
    else:
        return q_str

def get_q_answer(new_a_str:str) -> bool:
    print('For ' + new_a_str + ', what is the answer?')
    return is_answer_affirmative(get_one_word_answer())

# Make a new guess node with a new animal name.
def make_g_node() -> dict:
    print('What animal were you thinking of? ')
    return {'A':get_animal()}

# Make a new incomplete question node, with a new question to distinguish
# between the correct animal and the animal we incorrectly guessed.
def make_q_node_with_q_only(correct_a_str:str, incorrect_a_str:str) -> dict:
    print('Please type a yes-or-no question that would distinguish ' \
          + correct_a_str + \
          ' from ' + incorrect_a_str + ':')
    return {'Q':get_question(),
            'Y':None,
            'N':None}

# Complete the question node by setting the old and new guess child nodes. To
# do this we need the answer to the question that distinguishes between the
# correct animal and the animal we incorrectly guessed.
def attach_g_nodes(new_q_node:dict, incorrect_g_node:dict,
                   correct_g_node:dict) -> None:
    # Arrange the guess nodes according to whether the new animal should be
    # be reached by a "yes" answer or a "no" answer.
    if get_q_answer(correct_g_node['A']):
        new_q_node['Y'] = correct_g_node
        new_q_node['N'] = incorrect_g_node
    else:
        new_q_node['Y'] = incorrect_g_node
        new_q_node['N'] = correct_g_node

# Make a new question node, along with its children. This requires asking for
# a new animal name, a new question to distinguish between the correct animal
# and the animal we incorrectly guessed, and the answer to that question.
def make_new_q_node(q_node:dict, g_node:dict) -> dict:
    new_g_node = make_g_node()
    new_q_node = make_q_node_with_q_only(new_g_node['A'], g_node['A'])
    # Complete the question node by setting the old and new guess child nodes.
    attach_g_nodes(new_q_node, g_node, new_g_node)
    # The new question node will be inserted into the tree in place of the old
    # guess node.
    return new_q_node

# Add a new question node to the "yes" branch of an existing question node.
def insert_new_yes_branch_q_node(q_node:dict, g_node:dict):
    new_q_node = make_new_q_node(q_node, g_node)
    # Change the parent's "yes" dictionary entry.
    q_node['Y'] = new_q_node

# Add a new question node to the "no" branch of an existing question node.
def insert_new_no_branch_q_node(q_node:dict, g_node:dict):
    new_q_node = make_new_q_node(q_node, g_node)
    # Change the parent's "no" dictionary entry.
    q_node['N'] = new_q_node

# This function handles a guess node, which is always a leaf node, containing
# an animal name. If the guess is not correct, ask for the correct animal name
# and a question we can use in the future to distinguish between the two
# animals. This is how the game "learns."
def play_g_node(q_node:dict, g_node:dict, followed_yes_path:bool) -> None:
    print("Is it " + g_node['A'] + '?')
    if is_answer_affirmative(get_one_word_answer()):
        print('Great! Try another animal!')
    else:
        # Add a new question node to the existing question node's "yes" or "no"
        # branch, depending on the path we took to reach the guess node.
        if followed_yes_path:
            insert_new_yes_branch_q_node(q_node, g_node)
        else:
            insert_new_no_branch_q_node(q_node, g_node)

# This function handles any pair of parent and child nodes once we've asked at
# least one question, and so know if we're following the "yes" branch or not.
# Gameplay proceeds with mutual recursion between the pair of functions
# play_q_node() and play_node() until a guess node is reached.
def play_node(q_node:dict, node:dict, followed_yes_path:bool) -> None:
    if (node.get('Q')):
        play_q_node(node)
    else:
        play_g_node(q_node, node, followed_yes_path)

# This function handles any question node including the root. Ask the question,
# and then we know whether we're following the "yes" branch or not, and can
# call play_node().
def play_q_node(q_node) -> None:
    print(q_node['Q'])
    if is_answer_affirmative(get_one_word_answer()):
        play_node(q_node, q_node["Y"], True)
    else:
        play_node(q_node, q_node["N"], False)

def play_game(root_q_node:dict) -> None:
    # The root node is always a question node.
    play_q_node(root_q_node)

def get_indent_str(level) -> str:
    return " " * level * 3

# This is a pre-order, depth-first binary tree traversal in disguise. The basic
# algorithm is expressed something like this (in pseudocode):
#
# function handle_node(node)
#     do_something(node)
#     handle_node(node.left)
#     handle_node(node.right) 
#    
# Our traversal to print the game tree differs in the following ways:
#
# - We have two types of nodes, and they are handled differently, rather than
#   the usual design in which all nodes are the same type, and leaf nodes have
#   null left and right child pointers or references.
#
# - We report the current node question before each recursive call to handle
#   the left and right subtrees (in our case, the "yes" and "no" subtrees),
#   instead of just once before both calls. This is to make it clearer which
#   combination of question and answer brings us to each question or guess
#   node, because when printing a large tree there can be a large number of
#   lines from the subtrees printed between the two branches of a question
#   node.
#
# - We have a level parameter, used for indentation.
def print_game_tree(node:dict, level:int):
    if (node.get('Q')):
        print(get_indent_str(level) + 'Question: ' + node['Q'] + ' -> yes:')
        print_game_tree(node['Y'], level + 1)
        print(get_indent_str(level) + 'Question: ' + node['Q'] + ' -> no:')
        print_game_tree(node["N"], level + 1)
    else:
        print(get_indent_str(level) + "Guess: " + node['A'])
    return

print()
print('Play "Guess the Animal." Think of an animal and the computer will')
print('attempt to guess it. The game gets smarter over time as you teach it')
print('about more animals! This program by Paul R. Potts is based on the')
print('original BASIC game as it appears in the book Basic Computer Games:')
print('TRS-80 Edition, edited by David H. Ahl.')
print()
print('If you would like to see the internal tree of questions and animal')
print('names, type "tree" instead of "yes" or "no" when the program asks')
print('"Are you thinking of an animal?"')

while True:
    print()
    print('Are you thinking of an animal?')
    answer_str = get_one_word_answer()
    if is_answer_affirmative(answer_str):
        # Note that the root node is never replaced; the initial question is
        # always the same. Therefore, we don't need to pass a parent node to.
        # play_root().
        play_game(q_node_root)
    elif is_answer_tree(answer_str):
        print("Game tree:")
        print_game_tree(q_node_root, 1)
    else:
        print("Goodbye for now!")
        break

And here’s a sample log from the above program:

Play "Guess the Animal." Think of an animal and the computer will
attempt to guess it. The game gets smarter over time as you teach it
about more animals! This program by Paul R. Potts is based on the
original BASIC game as it appears in the book Basic Computer Games:
'TRS-80 Edition, edited by David H. Ahl.

If you would like to see the internal tree of questions and animal
names, type "tree" instead of "yes" or "no" when the program asks
"Are you thinking of an animal?"

Are you thinking of an animal?
tree
Game tree:
   Question: Does it swim? -> yes:
      Guess: a fish
   Question: Does it swim? -> no:
      Guess: a bird

Are you thinking of an animal?
yes
Does it swim?
yes
Is it a fish?
no
What animal were you thinking of? 
a seal
Please type a yes-or-no question that would distinguish a seal from a fish:
Does it breathe water?
For a seal, what is the answer?
no

Are you thinking of an animal?
tree
Game tree:
   Question: Does it swim? -> yes:
      Question: Does it breathe water? -> yes:
         Guess: a fish
      Question: Does it breathe water? -> no:
         Guess: a seal
   Question: Does it swim? -> no:
      Guess: a bird

Are you thinking of an animal?
yes
Does it swim?
no
Is it a bird?
no
What animal were you thinking of? 
a bat
Please type a yes-or-no question that would distinguish a bat from a bird:
Does it use echolocation?
For a bat, what is the answer?
yes

Are you thinking of an animal?
tree
Game tree:
   Question: Does it swim? -> yes:
      Question: Does it breathe water? -> yes:
         Guess: a fish
      Question: Does it breathe water? -> no:
         Guess: a seal
   Question: Does it swim? -> no:
      Question: Does it use echolocation? -> yes:
         Guess: a bat
      Question: Does it use echolocation? -> no:
         Guess: a bird

Are you thinking of an animal?
yes
Does it swim?
yes
Does it breathe water?
yes
Is it a fish?
no
What animal were you thinking of? 
an octopus
Please type a yes-or-no question that would distinguish an octopus from a fish:
Does it have eight tentacles?
For an octopus, what is the answer?
yes

Are you thinking of an animal?
tree
Game tree:
   Question: Does it swim? -> yes:
      Question: Does it breathe water? -> yes:
         Question: Does it have eight tentacles? -> yes:
            Guess: an octopus
         Question: Does it have eight tentacles? -> no:
            Guess: a fish
      Question: Does it breathe water? -> no:
         Guess: a seal
   Question: Does it swim? -> no:
      Question: Does it use echolocation? -> yes:
         Guess: a bat
      Question: Does it use echolocation? -> no:
         Guess: a bird

Are you thinking of an animal?
no
Goodbye for now!

About This Newsletter

This content is available for your use under a Creative Commons Attribution-NonCommercial 4.0 International License. If you’d like to help feed my coffee habit, you can leave me a tip via PayPal. Thanks!

Subscribe via TinyLetterYear IndexAll Years IndexWriting Archive