Computer cipher solving – word list scoring part 2

In my last post I discussed how to break up undivided text strings into words in order to be able to score trial decryptions. In that post I mentioned blanking out words that have been found in order not to double count letters. I’ll provide an example to clarify: suppose your trial decryption is “HBSTUMBLEDTXERE.” Using the length-based approach I recommended, your algorithm would first find the word STUMBLED when it gets to length 8. What you should do is then convert the test decryption to HB——–TXERE for the next loop. The final score would be 8, or,  if you have ERE in your word list, 11. If you leave the trial decryption in the original form, the algorithm would find TUMBLED, STUMBLE, TUMBLE, BLED, and LED as it tested shorter word lengths. The same letters would be counted multiple times and artificially increase the score. What you’re really looking for is the percentage of the decryption that forms words.

I suggested the score should be the number of letters that are found to be in words and that’s a simple way that works. But I believe a test decryption with longer words in it is more likely to be on the right track, and the score should reflect that. So you may wish to give extra points for longer words. Perhaps add L*(L-1) or L*(L-2) where L is the length of the word found would work better. You may want to deduct unmatched letters. But you have balance this against the situation where your bonus rewards inaccurate parsing too much. For example HULALIGHT would parse as HUL ALIGHT. HOLYLIGHT would split after the Y. The second form is more likely right. With simple letter count, the second one scores higher. But what if there’s a bonus for length? HUL ALIGHT might score higher depending on how big a bonus.

Now compare HULALIGHT to HALFLIGHT and to HOLYLIGHT. Without a length bonus these score the same. How do we fix that so the best one scores highest?  It’s possible to try alternate ways of parsing the word divisions and then scoring higher for the result that is most common, as I’ll explain below. I’ve found this to be much too time-consuming to be practical in hill-climbing. Another way I do use for cipher types with word divisions such as Aristocrats, Key Phrase, and Tridigital, is to score word pairs together based on the frequency of the pairing. I’ve downloaded 2-grams from the Google N-gram site and processed the files to delete irrelevant data, adjust the frequency numbers to more manageable size and spread, and alphabetize them. I use these files to score the word pairs. You might be tempted just to use the frequency of the individual words rather than the pairs, as it would be faster to look up. That might work with the above example since HALF is more common than HULA or Holy. So is HALF LIGHT the most common combo. But take TWENTY T??. The most frequent combo is TWENTY TWO but TWENTY THE would score higher based on individual word frequency. Tetragram scoring can take care of some of this and for simple substitution types cost in time is rarely worth two-word scoring. But for some very tough ones, like very short Headline puzzle headlines, it’s the only way to crack them, and in a Key Phrase I’ve found it essential.

I mentioned above that trying alternate means of parsing is not practical for hillclimbing. But another application of this technique is not used for solving at all. When I solve a cipher and the result is without word divisions, I like to submit the result in a more readable form for the Solutions Editor. That means I insert spaces at the word boundaries. My program to do this uses four steps. The first step consists of dividing up the text using the technique I described in my first post, but either method will work for step 1. The second step is to score the word pairs from the N-gram data as described in the last paragraph. These two steps are virtually instantaneous. Then the program goes back and checks for common parsing errors I’ve compiled in a list, such as changing “i snow” to “is now.” This is still instantaneous. The final step is to go back through and try moving one and then two letters to the left and the right at every space and testing the resultant word pairs. For example, “butt he” would be tested against “but the” and “bu tthe.” “But the” would outscore the others and be the output form. All this testing and then altering the output is very slow. For one already solved text the forty seconds or so it takes is acceptable but it can’t be used in hillclimbing.

Computer Cipher Solving – word scoring part 1

I’ve described various computer solving techniques in earlier blogs, but I only briefly mentioned  scoring using word lists. For most computer applications I use tetragram scoring because it’s fast and easy to implement. But it’s not always the most accurate way. If your solving program already “knows” the word break points then it’s relatively easy and fast to look up each trial string to see if it’s a word. I’ll get to that method in a minute. But what about the many cases where the trial output is one continuous string without breaks?

There are two approaches to that situation. The first is to begin at the first letter and keep appending letters until the string is no longer a word. For example, if the trial output begins “THEMAN” this program would go through “THEM,” which it recognizes as a word, and assume the break point comes after the M and begin looking for the next word at AN…. Or, if the word THEMA (Latin, but used in English) is in your reference word list, it will break there and start looking for the next word at the N. As you can see, this does not always find words as you would by eye. You naturally think it begins with the two words THE MAN or possibly THE MANY, etc. If it doesn’t find a word starting with the first letter, it moves on and does the same with letter 2 and so forth. The scoring algorithm won’t give an accurate number if it is breaking the text incorrectly. The final score is based on how many total letters are found to be in words.

The second approach is to start with longest words first. Start with the longest word length in your available lists and then shorten the search length incrementally. Let’s say you start with length 24, the maximum word length in my normal lists. You check to see if the first 24-letter string is a valid word. If it is, you blank that out and test the next string beginning at letter 25. If not, you do the same beginning at letter 2, and so on. You probably won’t find any words of that length, but the next cycle, you try 23-letter words, and so on. Whenever you find a word, be sure you eliminate that section of the output from future testing so that it’s not double counted using shorter words found within the longer ones. The final score in this version is also the total number of letters that are in words.

Neither method is perfect. Take a sentence beginning TWOSTRINGS. The first program will find TWOS T RINGS, dropping the T from the count. The second method would get it right. But with  BUTOUR, the second method gets BU TOUR, losing the BU, while the first method gets BUT OUR, the correct parse. I’ve written programs both ways and in my experience this second way is best.

Now for the question of how to determine if a string is a word. Of course it is very simple to write a program that reads from an alphabetical list and when it comes to the point where your test string should appear, determine whether or not it is there. This works reasonably fast on very short lists or if your candidate begins with an A or B. Otherwise, it is quite slow. Another approach is to use a hash function. I’m not going to discuss that since I don’t use one. If you already know what this is and how to use one, you don’t need me, and if you don’t, I can’t tell you. I believe Python and maybe other languages have this built in and it’s fast even for unordered lists but is complicated and has some computing overhead to build a hash table.

But there’s a fast method for Delphi, the language I use, which I believe is available in other languages, too. My FindWord function takes a string S as input and returns a true if it’s a word and false if it is not. It depends on using the AnsiCompareStr function. This function takes two strings as input, and compares them. If the first one is less than (i.e. alphabetically earlier than) the second, it returns a negative number, if it’s greater, it returns a positive number, and if they are the same, a zero. To use this, first you load your reference word list in alphabetical order and count the number of entries; call that X. This only needs to be done once when the program is loaded not each time the function is called. Your search function will begin its first comparison of S with the word in the middle, i.e. at position 1/2 x. If the test word is less than the list word, you next try S with the word at 1/4 x. If the first comparison shows S is greater than the list word then your second test is against the word 3/4 x. In other words, you keep splitting the search domain in half with every search. When you get a match, the function returns a True and stops looking. When you get down to the last word without a match, the function returns a false. It’s written recursively so that it automatically keeps calling itself until one of those two points is reached. For a list of 80,000 words, the maximum number of comparison you’d have to do is 17.

To make it even faster, don’t load all the words into a single list. Use a separate list for each word length. I sometimes use a two-dimensional array ranging from 2 to 24 for the word length, and 1 to 13000 for the word count. Since there are more 8-letter words than any other length and there are just under 13,000 words in that list. I treat one-letter words separately in my function, giving a False for anything besides A or I. This cuts the maximum number of searches to 14 for length 8 and for most strings, much fewer.

This can be refined even more. I’ll discuss that in my next post.

 

The Lincoln Highway by Amor Towles

The Lincoln HighwayThe Lincoln Highway by Amor Towles
My rating: 2 of 5 stars

This book was highly rated or strongly recommended to me by three different people whose taste and judgment I trust. So it was a big disappointment that I didn’t like the book. I got about 40% of the way through it and gave up because I still hadn’t become interested in the story or characters. It’s too long a book to spend the necessary time to finish something I don’t like. I found none of the characters credible or relatable and none of the events believable either. I could point out more specifics I didn’t like, but I don’t take any joy in throwing a wet blanket on the joys of others, so if you liked it, good for you. Towles’s earlier book A Gentleman in Moscow was somewhat better, but I was lukewarm on that one, too, for many of the same reasons. There’s just something about the artificiality of Towles’s style I don’t like.

View all my reviews

Project Hail Mary by Andy Weir

Project Hail MaryProject Hail Mary by Andy Weir
My rating: 4 of 5 stars

Weir has followed his first novel The Martian, with this very sciency thriller. The Earth is threatened by a microbe (astrophage) that is eating the sun. If it continues, in a few decades the Earth will be a frozen world and mankind will perish. Scientists obtain a sample through a probe and identify enough about it that they are able to determine that many other stars in the local cluster are infected, but one isn’t. Earth governments join together to build a mission to that solar system (Tau Ceti). It is up to the crew to determine how that other star has survived the astrophage infection and send back the solution.

{Mild spoiler, although you learn this very early in the book] Only one of the crew members survives to reach Tau Ceti. From this point on it resembles The Martian quite a bit as our hero uses his knowledge of science and engineering to overcome all sorts of problems, although he gets some help from an unexpected source. I’ll say no more on that. I did love the cleverness of much of the science workarounds and I learned quite a bit. It was also nice not to have the gore and violence of many other science fiction thrillers, the so-called space operas.

The book has its flaws, however. It is too long. It is much less plausible than The Martian. Weir gets lazy and just creates crises and then impossible and unexplained solutions. There are many inconsistencies. It’s also too silly. The lighthearted tone doesn’t fit well with the seriousness of the mission. The light tone reduces the suspense by a large factor. It’s as though Weir couldn’t make up his mind whether to write a sci-fi thriller or an travel adventure book. It becomes tedious after page 200 or so. Another crisis, another implausible solution. All in all, though, I enjoyed it and can recommend it.

View all my reviews

Ukraine’s neighbors

Everyone has heard plenty about what’s happening in Ukraine. Russia invaded it and Ukrainian refugees are fleeing. This has been going on for weeks. They’ve mostly been fleeing to neighboring countries. This chart shows Google searches in the U.S. for the four countries that have taken in the most Ukrainian refugees.


The bump for Poland and Hungary back in May 2021 is probably due to interest in their blockage of Gender Equality language at the EU Social Summit. Whatever you think about that, all four of these countries are showing tremendous generosity to the Ukrainian refugees. If you need a geography refresher, here’s a map.

Poland has taken in more than any other country, at least for now. The others listed are next in sheer numbers. Eventually the refugees may settle in other countries. I’ve skipped Russia, which would also be on this list, but many of the “refugees” there were forced there and did not go there to seek refuge. They are more like hostages or POWs.

Lemon by Kwon Yeo-sun

LemonLemon by Kwon Yeo-Sun
My rating: 1 of 5 stars

After reading the entire book I have no idea who did what. A beautiful girl died, years pass, and another crime occurs, but I don’t want to give a spoiler so I won’t say more on the plot. There were multiple suspects in both the crimes – pretty much the same people – but no one seems to have a motive and it’s never revealed who did either. I couldn’t even tell which character was narrating each chapter. Each was in the first person but there was no label or chapter heading to reveal who it was. In most of them it became obvious, but in several of the key ones, it wasn’t. The writing was also awkward and wandering into irrelevant anecdotes. I don’t know if it was bad writing or bad translating but this is definitely a book to skip. Its best (or least bad) feature is that it was very short.

View all my reviews

Cost of energy per mile – gas v. electric

With gas prices soaring, there’s a lot of outrage among the public. Everyone’s prone to blame someone, usually the “opposite” party’s policies. There’s no question that the Republican tax cuts and the Democrat spending plan have both contributed to the current inflation. But let’s just look at the cost of driving a car.

Stop blaming politicians and look in the mirror. If you’d purchased an electric vehicle (EV), you wouldn’t be having this problem. I drive a Volvo XC40 Recharge, an EV. My rough calculations put my energy cost per mile at around 7.5 cents. My wife’s car, an Acura gas car, costs over 20 cents a mile at today’s prices and that doesn’t include other costs the EV doesn’t have like oil changes and the $75 I just paid for a smog check. In California the electric grid uses very little fossil fuel so it’s not affected by the Russia oil ban. America’s policy is to eventually be almost all EV. Norway has done it. It’s time everyone got on board with it. The petroleum age is ending.

Worbot updated

I now have enough puzzle solutions to make some meaningful observations about my Worbot program that solves the daily Wordle puzzle. First, here are my Wordle stats (left) and Worbot’s (right).

Obviously, I started tracking Worbot stats a month or so after I started working the puzzle myself, hence the different totals. The stats on the right also don’t show the first few attempts where I tested the program, including the one where it failed to solve PROXY.

As you can see, Worbot has a better record than I do. It has three times as many solves in three attempts than in five. My ratio is about 2 to 1. It plays in hard mode, too; I don’t. In case you don’t know what hard mode is, it means that you must use the letters that have been identified in prior guess each time you guess. Worbot also takes it further and cannot guess a word that uses a letter than has previously been shown NOT to appear in the target word, i.e. the gray letters become off limits. I think the key to its success is the word lists I have programmed it to use. The list it uses for its initial guess is limited to 64 words that: 1) have all or almost all high-frequency letters; and 2) have been verified to appear in the actual Wordle program target word list (2315 words). The program chooses randomly from those 64. It at least has a chance of getting the word on the first try, although it hasn’t succeeded at that yet. Neither have I.

The main list that Worbot uses for all subsequent guesses is my normal master 5-letter word list, but ordered by frequency in English. That master list (over 4,000 words) does NOT use any knowledge of the official Wordle list. So later guesses may be of words that have no chance of being the correct one. Nevertheless, the fact that it searches the list in order of frequency makes it highly likely it will find the most common word that fits all the previous clues from the colored squares. I believe this increases the chance that it will guess the right word in fewer guesses than me, since I make guesses based on instinct and general vocabulary with no knowledge of whether other words may be more common. That’s because I have made the assumption from the relatively low number of words in the official Wordle list that all of the target words are quite common.

By the way, I had fun programming the statistics page to look much like the Wordle one. That was actually the hardest part of the programming.

The Spy and the Traitor by Ben MacIntyre

The Spy and the Traitor: The Greatest Espionage Story of the Cold WarThe Spy and the Traitor: The Greatest Espionage Story of the Cold War by Ben Macintyre
My rating: 5 of 5 stars

This is by far the best book I’ve read in many months, perhaps years. It is outlandish and unbelievable, yet it has the added distinction of being absolutely true. It is the story of a KGB agent who spied for England. When I joined the FBI this is the kind of case I hoped one day to be involved in. It never came to pass, because this is the sort of case that happens once in a lifetime to an intelligence agency and only a tiny handful of people ever know about it at the time due to its absolute secrecy.

The beginning is well-written, but unexciting, setting the stage by introducing the characters and refreshing for us the realpolitik history of the Reagan-Thatcher-Andropov-Gorbachev era. I remember it well, but younger readers will find it eye-opening. By the second half of the book, the tension ramps up. PIMLICO, the mole, rises in the KGB and becomes more valuable, while at the same time the intelligence he provides puts him at greater risk as it is used. He is eventually put in peril. As it happens, western intelligence has its own mole betraying its secrets to the KGB. I’ll leave it there to avoid spoilers, but rest assured the last third of the book is a page turner. Do yourself a favor and don’t read through the photographs until the very end, as they contain some spoilers for what comes later.

View all my reviews

Law & Order season 21 – a disappointment

One of my favorite television shows was the original Law & Order starring Jerry Orbach as detective Lennie Briscoe. The writing involved complex legal issues in addition to the clever detective work. The acting and writing were excellent. It ran for 20 years, from 1990 to 2010. So I was excited to see it coming back starting tonight in Season 21. The various spinoff series were too gory or sensationalized with an unappealing set of actors. I never watched any of them for more than one episode.

Unfortunately, the reboot is poorly done. I’ve already taken it off my watch list. The writing is bad, the casting is bad, the acting is bad, the main characters are all unlikable, and it’s succumbed to the same problems as the spinoffs – more gore, more swearing, more overall nastiness. My wife called it ham-handed. I can’t recommend it.

Tridigital cipher solving algorithm continued

In my last post, I mentioned key pruning. What I mean by that is halting the recursion (and allowing it to go back a level and continue with another word) based the nature of the keyblock. In particular, the block always has three rows. This means any given digit may have at most three letter equivalents. Thus I put a testing routine in the recursion routine to look for conflicts of this sort. If the word being tested passes the first conflict test, e.g. THEIRSOME in the last post, it then goes through a routine to count how many letters are represented by each digit. THEIRSOME is represented by 107735607. The 7 enciphers E and I while the 0 enciphers H and M. Since there are no cases where a digit represents four or more letters, this is a possible solution so far. This is not surprising since we’re only on level 2. If one of them represented four different letters, the recursion ends at that level, the test word SOME would be rejected, and the next word in the four-letter word list would be tried.

This example is so short that there are thousands of valid solutions (which is why Tridigital is a hobby cipher, not a real-life one). One my program found was “had some by their,” which even makes sense as a phrase. But with more words, especially longer ones, it will soon be the case for incorrect combinations that one or more digits represent more than three letters. This typically happens on the level three or four recursion.

The other technique I use is scoring. Since all solutions that pass through the conflict testing consist of valid words, the usual scoring techniques such as tetragram frequency or word list scoring don’t work. So I reorder each potential solution array back to its original order and test pairs of words for frequency.  I use Google N-gram data to determine this. The better the score, the higher in the display the solution is placed. Although this doesn’t speed up processing per se, it makes it much easier for me to spot a correct solution, or at least a likely correct segment in the solution early on. I don’t have to continuously scroll through dozens or even thousands of possible solutions as the program runs. The best ones are right up at the top.

As an example, the demo problem produces these possible solutions immediately:
had some by their
man some by their
arm some by their
had some up their
may some up their
man some up their

The most natural-sounding one is on top because the three two-word combinations (had some, some by, by their) score the highest in frequency. One of the other solutions may actually have been the first one found, but the display is in order of frequency score. Of course, we know none of these are the correct solution, but they are all valid.

This in turn allows another shortcut. If I spot a solution, or even a partial solution, I can abandon the program and use the digit-letter equivalencies revealed to run through my word lists in a separate program to identify any key words that can produce a keyblock with the same letters in the same columns, such as E and I in one column, H and M in another. Typically only about four or five words have to be solved before I have enough digits to find the original keyword and hat. Once I have those, I can solve any incorrectly solved or not yet solved parts by hand.

Tridigital cipher solving algorithm

If you are not familiar with the Tridigital cipher, go to the American Cryptogram Association cipher types page and be sure you understand how it works. I’ll use the same keyblock on that page as an example.

N O V E L C R A F T
6 7 0 3 5 2 8 1 4 9
D R A G O N F L Y -
B C E H I J K M P -
Q S T U V W X Z - -

pt: t h e   i d e s   o f   m a r c h
CT: 0 3 0 9 5 6 0 7 9 5 8 9 1 0 7 7 3.

Note that every plaintext letter has only one digit that represents it, i.e. plaintext D is always enciphered with 6 in this case. The opposite is not true. The 6 can also represent B or Q. The spaces in the plaintext are always represented by the digit on the far right, 9 in this case. In the example, 0 is the highest digit and represents 10. The columns are numbered in alphabetical order according to the “hat” NOVELCRAFT. The ciphertext is a string of digits.

Step 1 is to find the spaces in the ciphertext, that is, determine which digit is the one on the far right. Since the plaintext will never have two spaces in a row, most digits can be eliminated by the fact they appear doubled in the ciphertext. For others, it is usually easy to judge by using the lengths of the words that would be produced by the possibilities. One might result in a 27-letter word, another in five different one-letter words. Those you can eliminate. This is just a preliminary step, not the heart of the algorithm.

Step 2. Once you have the ciphertext divided into word lengths with spaces inserted you need to prepare your word lists. Create arrays for each word length. To speed up solution I order the words by frequency, i.e. how common they are in English, but this is not necessary.

Step 3. Create an array of the ciphertext words, ordering them from longest to shortest, but keep a key so you can restore them to the order they appear in the original text. In the example, the elements would be 10773, 5607, 030, 58. In real problems, there are going to be some longer words, which is essential to an efficient algorithm.

Step 4. Begin testing words of the right length for the first word. Check for conflicts. Since WHICH is the most common 5-letter word, that would be the first one tested. We see the H’s would be represented by two different digits, 0 and 3, so it cannot be the first word. Go to the next word, THEIR in my list. There are no conflicts. The E and I may both be in the same column in the keyblock and thus both represented by 7. Save the word in a temporary array or string of possible solutions. Feed this word into recursive routine that is the key to the algorithm along with the level, i.e. 1 ion this case since this is the first word.

Step 5. Recursion. The recursive routine must first check to see if it has already completed all the levels. If it has, it has found a possible solution. That should be printed, displayed or saved in some fashion unless its score makes it untenable (I’ll discuss scoring later). If it’s not yet complete, start testing words from the next word list, the one with words the same length as the next level. In our example, that’s words of length 4 for word two, ciphertext 5607. In my list, THAT would be the first word tested and it would conflict with its own ciphertext (T would be represented by 5 and 7) as well as with the first word.  In my list, the first 16 words would conflict, landing on SOME as a possibility. The E is represented by 7 in both words, THEIRSOME. This combination is fed back into the recursion routine with the new level (2, here) and the process is repeated until a full solution is found or all the words on some level are tried without finding a possibility to send on to the next level. The trial words are then backed out of the temporary array or string and the next word at each level is tried until all the levels are tried back to level one where the process is repeated.

The experienced programmer, or cryptographer, will realize that the process as described above will eventually find the solution, but would take impractically long, especially with longer ciphertexts. The key to making this work is to find an efficient way to prune the words tried. There are two basic ways I’ve found, although there may be others. The two I use are key testing and scoring. I’ll save those for my next post.

If I Disappear by Eliza Jane Brazier

If I DisappearIf I Disappear by Eliza Jane Brazier
My rating: 4 of 5 stars

Sera is obsessed with a true crime podcast about missing women, young unattached women who disappear in Northern California. She’s the (now trite) unreliable narrator of the story. She’s a mess, after a divorce and having lost a child, the obsession is her life. Rachel, the podcaster, inexplicably stops podcasting and Sera is determined to find out why. She is convinced Rachel has been killed. She heads to Rachel’s remote ranch off the Klamath River where Rachel’s parents own a summer riding ranch for tourists. Everyone up there is weird and something clearly is not right, but she’s the outsider stirring up trouble among the hostile locals.

I was slow to get into this story. It is told in the first person, which is not unusual, but written as though Sera is talking to the missing Rachel, e.g., “I can’t believe you never told me. All this time you were trying to save others.” I’ll give it style points for originality, but I found it off-putting at first. The author has a knack for ratcheting up the suspense as the various characters shift in and out of the role of chief suspect. Is there even a crime? No one there has reported one. Her parents tell Sera she was killed by a gang, but everyone else says she just took off to get away from her crazy family. Sera’s parents hate and distrust the local townspeople and the feeling is mutual. None of the characters are likeable and there’s not a lot of meat to this story, but the answer as to what happened to Rachel (and possibly those missing victims in the podcast) is well hidden until the very end. I’d give it three and half stars if I could, but I’ll squeeze out four.

View all my reviews

Gazpacho vs. Gestapo

In case you missed it, last Tuesday the far right wacko congresswoman from Georgia, Marjorie Taylor Greene, claimed that House Speaker Nancy Pelosi was sending gazpacho police to investigate the capitol riot. Apparently she doesn’t know the difference between cold soup and Nazis. This is surprising, since she is one of those. Apparently a lot of other people in this country also aren’t familiar with the meaning of gazpacho. Look at these two Google Trends charts. The top one is a comparison of how often and where the terms were searched on Google during the month of January. The searches were about the same frequency and randomly distributed. The bottom chart shows the searches this month. Nearly all of that blue searching has been in the last three days.


Greene is the same woman who claimed that Jewish space lasers were setting the forest fires in California last March.

Varsity Blues update – cost of trial

It’s been a while since I last wrote about Varsity Blues, the college admissions scandal. Two defendants, both parents who bribed school officials to get their children admitted to colleges of choice, went to trial rather than plead guilty. Both were convicted last October. Yesterday the first of them, Gamal Abdelaziz, was sentenced to one year and one day in prison along with two years supervised release after prison, a $250,000 fine and 400 hours of community service. The other defendant, John Wilson, will be sentenced next week. He was convicted of tax charges in addition to the college conspiracy charges, so he may get an even longer sentence.

These two men are the first two to choose trial rather than taking a plea deal. It cost them at time of sentencing. The longest sentence given out prior to this was for nine months. That defendant, Douglas Hodge, paid more money and was more directly and actively involved in the bribes on behalf of four children than most other parents. There have been several other defendants convicted in recent months, too. To see the whole list, here’s the authoritative link: Varsity Blues.

The most outrageous case is the one defendant who was pardoned by Donald Trump right before he left office. Robert Zangrillo, a Miami developer, was let off scot-free. The White House claimed that various businessmen and even a USC trustee (a major Trump supporter), advocated for the pardon for Zangrillo, but those businessmen all denied having any input on the pardon or contact with Zangrillo or the White House. The White House statement on the pardon also claimed that Zangrillo’s daughter Amber was earning a 3.9 GPA at USC, but the school confirmed that she was not enrolled there. The lies from that man never end.

The Last Flight by Julie Clark

The Last FlightThe Last Flight by Julie Clark
My rating: 4 of 5 stars

Claire Cook is married to the son of a powerful U.S. Senator from a power family (e.g. Kennedy, Bush). But her husband is controlling and abusive, so she decides to escape. She formulates a plan, but the plan is thwarted. Instead she ends up switching plane tickets with Eva, a young woman also in a desperate situation. The stories of the two women are told in interspersed chapters, Claire’s moving forward, Eva’s in flashbacks leading up to the day of the ticket switch.

I really like the premise. It’s a thriller, not a crime novel per se, although there are crimes involved. Tension was kept high. Will Claire’s husband find her? What happened to Eva? The writing was rather uninspired and won’t win any literary prizes, but it featured some locations I’m familiar with, which always adds to my interest. The ending wasn’t great, but it did explain one mystery and contained a surprise, so it wasn’t a disappointment.

View all my reviews

Worbot

This will be my last post on the subject of Wordle for a while (I hope). I wrote a program that tries to guess the input Wordle word. I’m calling it Worbot. I wrote it so that its attempts are shown in the same format as the actual Wordle. The program doesn’t have access to the Internet, so it can only solve the word that is input. It does a pretty good job of it. The only word Worbot hasn’t solved in six tries (the maximum allowed by actual Wordle) is PROXY, which is also the only word I didn’t get in six tries. And I had to run the word PROXY three times before the program failed. It rarely fails to solve within four guesses. Here are some sample runs. Spoiler warning: one of the words shown is today’s actual Wordle word, but you probably won’t read this today.

My purpose in writing this is to see if I can beat my program over time, i.e., develop a better record. I don’t yet have the routine written to track that for the program. My word list is slightly larger than the one used by Wordle, so some of my words may be invalid, but it could also be that Wordle uses some words not in my list. It may be possible to download the Wordle list, but I’m not concerned enough to go to that trouble.

Wordle spoiler bot

In case you missed it, someone reverse engineered the code for Wordle and figured out what word would come next. He posted the tool for that online and some other tool used it to create a bot that posts the next day’s word as a spoiler to anyone who Tweets about Wordle.  Fortunately, Twitter banned the bot as a violation of the terms of service.

As a side note: I finally got the word on my second guess. Yes, I was lucky.

Wordle

Okay, with a blog titled OnWords, you knew I’d have to get around to the latest online word craze, Wordle. It’s essentially MasterMind using five-letter words. It’s fun and I’m hooked. You should try it. Here are my stats:


I’ve missed getting the word only once, but that’s one more than I’d like. A week ago the word was PROXY. I had it narrowed down to PROOF and PROXY by the 6th level and I guessed wrong. My wife has gotten the word in two guesses twice. That’s just plain lucky.

The Baker’s Secret by Stephen P. Kiernan

The Baker's SecretThe Baker’s Secret by Stephen P. Kiernan
My rating: 4 of 5 stars

Emmanuelle (Emma) is the baker with the secret. She is baking bread for the the Nazis under orders from the Kommandant, but finding a way to sneak some food to her fellow French villagers. She’s the lead character, but a cynic, a religious skeptic, and a pessimist. The plot has the advantage of moving forward chronologically and is thus easy to follow. This is unfashionable these days, it seems. It took me a long time to get into the story, though, mainly because most of the characters aren’t very likeable. Perhaps that’s inevitable in a story of occupied France. Everyone must compromise themselves or their morals to survive or help their relatives survive. There was also a large dollop of implausibility. But the last 20% or so of the book moved rapidly and had me fully engaged.

There was one stylistic choice that left me bewildered, although it didn’t particularly hurt the story. The author never refers to Germany, Germans, or German the language. The same is true for France and French. It is always “the occupying army” or “our language.” There were plenty of French and German words and names, so it was no secret what these unnamed people and languages were. I don’t get the point. The writing was serviceable, if not elegant, and the plot worthwhile.

View all my reviews