Sunday Puzzle May 22, 2022
Manipulate an Island Name to get Another Island
It’s an easyish one and comes from Blaine Deal, who conducts a weekly blog about Will’s NPR puzzles. Take the name of an island. Move its first letter two spaces later in the alphabet (so A would become C, B would become D, etc.). Reverse the result and you’ll have the name of another island. What islands are these?
Link to the challenge
Techniques Used
- String manipulation
- Simple file handling
- Linq methods ‘Aggregate’ and ‘Reverse’
Synopsis
Will was right, that was a pretty easy puzzle 😊. The hardest part about this one was building my island list. Eventually, I was able to use the list on Britannica.com, after manually editing their text for about half an hour.
After saving the result as a file, it was a simple matter of 1) reading that file into a list, 2) manipulating each list entry, and 3) checking whether the result was also an entry in that list.
Here’s the Code!
private void btnSolve_Click(object sender, RoutedEventArgs e) { Mouse.OverrideCursor = Cursors.Wait; var islandLst = new List<string>(); //Read the file and put each line into the list declared above: var fName = @"C:\Users\Randy\Documents\Puzzles\Data\Islands.txt"; using (var sr = File.OpenText(fName)) while (sr.Peek() != -1) islandLst.Add(sr.ReadLine() ?? ""); foreach(var island in islandLst) { //Manipulate the first letter and store the result in variable 'switched' var switched = (char)(char.ToLower(island[0]) + 2) + island[1..]; //Reverse the letters and convert to a string: var reversed = switched.Reverse().Aggregate("", (p,c) => p + c); //Convert the first letter to upper case var candidate = char.ToUpper(reversed[0]) + reversed[1..]; //Search the list for the result: var ndx = islandLst.BinarySearch(candidate); if (ndx >= 0) //Display the results: txtResult.Text += $"{island} - {islandLst[ndx]}\n"; } Mouse.OverrideCursor = null; }
Discussion
Here’s how I manipulate each entry in the islandLst to form a candidate to check. The lines highlighted above are discussed below:
var switched = (char)(char.ToLower(island[0]) + 2) + island[1..];
- Note that .NET allows you to treat a string variable as an
array
ofchar
, so you can use indexing on that array. To wit,island[0]
retrieves the first character from that array, at index 0
- .NET also allows you to perform arithmetic on
char
variables, so, ifc
is a char variable, thenc + 2
is a character moved up in the alphabet by two. So'g' + 2 = 'i'
, because i is two higher than g. However, the result is not achar
, so I need to cast it back tochar
before concatenating it with the remainder of the string. Casting is accomplished with the syntax(char)
, used as a prefix above.
- Note that .NET allows you to treat a string variable as an
var reversed = switched.Reverse().Aggregate("", (p,c) => p + c);
- ‘
Reverse
()’ is aLinq
method that builds anIEnumerable
‘list’ of char in the reverse order of the original. I can use it on a string because, as mentioned above, astring
is an array ofchar
, andLinq
can operate on an array (because an array is an IEnumerable) - ‘
Aggregate
‘ is anotherLinq
method that has two parameters:- The initial/seed value to aggregate with, namely, an empty string “”
- A Lambda expression
(p,c) => p + c
that tells .NET how to perform the aggregation. My variable ‘p
‘ represents the previous value (the results so far), and my variable ‘c
‘ represents the current list entry being processed. Effectively, my code says “for each list entry, add it to the running output”
- Why use
Aggregate
? Because, as mentioned above,Reverse
gives me a list (technically anIEnumerable
), and I need to convert it to a string.
- ‘
var candidate = char.ToUpper(reversed[0]) + reversed[1..];
- Take the first char (reversed[0]) and convert it to upper case (
char.ToUpper
) - Concatenate that with the remainder of the string (
reversed[1..]
). Note that the plus sign + serves as a concatenation operator, and .NET allows you to concatenate achar
to astring
.
- Take the first char (reversed[0]) and convert it to upper case (
Finally, having built a candidate, I search the list again to see if that list actually contains the candidate.
var ndx = islandLst.BinarySearch(candidate);
If the binary search operation returns a non-negative number, it means we have a solution!
Get the Code
Here’s the link to get my code. Note that you will need a (free) DropBox account to access that link. The compressed file contains my island list, which you can use to solve the puzzle yourself.