Month: October 2017
Sunday Puzzle for Oct 1st, 2017
I sure hope I found the solution Will was looking for! I’ve never heard of ‘flan’ until now. I know Will creates crossword puzzles for a living, so maybe flan is a common word to him. Or, maybe, as a New Yorker, he eats fancy desserts all the time.
According to Google, the dish pictured here is a ‘flan’. Sorry, it looks like cheese cake to me! I guess I’m not a gourmand.
Struggle Notes
If you look at the buttons on my screen shot, you might guess I tried pretty hard to get alternative word lists. (I wasn’t too happy with ‘flan’.)
- The button ‘Try All Words” uses a huge dictionary of English words (forget mere food words, try anything!), so if the solution used common words, like ‘corn’, that would have solved it
- The button “Get Name Brand Foods” downloads foods that might not be in my dictionary of English words.
- Since neither of those two methods found a different solution, I’m sticking with flan/gumbo.
Downloading Food Names
Note my other button, ”Get Food Names”.
- This button goes to Wikipedia’s page https://en.wikipedia.org/wiki/Lists_of_foods, which is a list of links…
- Follows each link, and grabs the food names from that page
- The result is 347 files of various food names, such as ‘List_of_pies,_tarts_and_flans’.
- If you’re a web guru, you might guess that takes a while to run. And you’d be correct; it took about 15 minutes to download them all.
Techniques Used
- String manipulation
- BinarySearch for lists
- Linq Aggregate
- Linq Select
- Removing diacritics (accents) from Unicode text
How To Shift Letters Using Linq
string shifted = aWord.Select(c => c == 'z' ? 'a' : (char)(c + 1))
.Aggregate("", (p, c) => p + c);
This code shifts each letter by one, as Will describes it in the challenge. For example, ‘flan’ becomes ‘gmbo’.
Notes:
- My variable ‘aWord’ might contain, for example, the word ‘flan’
- Linq Select treats aWord as a list of letters (i.e. list of char data type)
- The code examines each letter, c
- I use the ternary operator on each letter. ‘Ternary Operator” is a short-hand if-statement
- It takes the form condition ? first_expression : second_expression;
- If the letter c is ‘z’ (my condition)
- Return an ‘a’ (my first expression)
- Otherwise, add one to it and convert it back to char (2nd expression)
- The aggregate operator converts the list of char back into a string
- If ‘aWord’ contained “flan”, shifted would be assigned “gmbo”
How to Solve the Puzzle
The method below uses the code from above to shift a 4-letter word. My method needs a list of 4-letter foods and of 5-letter foods, passed as parameters
private void SearchListsForSolution(List<string> fiveLetterFoodList,
List<string> fourLetterFoodList) {
List<string> solutionList = new List<string>();
foreach (string aWord in fourLetterFoodList) {
if (!solutionList.Contains(aWord)) {
string shifted = aWord.Select(c => c == 'z' ? 'a' : (char)(c + 1))
.Aggregate("", (p, c) => p + c);
//Loop injects 'u' at 3 different positions to build candidate
//So we try 'gumbo', 'gmubo' and 'gmbuo'
for (int i = 1; i <= 3; i++) {
string candidate = shifted.Substring(0, i)
+ "u" + shifted.Substring(i);
//fiveLetterFoodList is a sorted list of foods
int p = fiveLetterFoodList.BinarySearch(candidate);
//if p is greater than zero, we found candidate in the list
if (p >= 0) {
//Add the 4-letter word, shifted version
//and 5-letter word to textbox
tbSolution.Text +=
$"{aWord } → {shifted} + u → {fiveLetterFoodList[p]}\n";
solutionList.Add(aWord);
}
}
}
}
}
Notes
- There are only 3 places to inject a u into a 4-letter word
- My code tries all 3 places and checks to see if the result is a word
- By using Binary Search against the 5-letter word list
- The BinarySearch method returns an index > 0 if it finds the candidate
- So when that happens, I update my TextBox ‘tbSolution’ to include what I just found
- The list ‘SolutionList’ helps me avoid entering the same solution twice; I need it because ‘flan’ was present in multiple files
Removing Diacritics
Just in case, I tried fixing words like ‘Ragú‘, converting it to ‘Ragu‘ by removing the accent over the letter u. (It didn’t help.) It was pretty easy; I just copied the code from here: “Stripping is an Interesting Job…”
That code looked like this:
static string RemoveDiacritics(string text)
{
var normalizedString = text.Normalize(NormalizationForm.FormD);
var stringBuilder = new StringBuilder();
foreach (var c in normalizedString)
{
var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
if (unicodeCategory != UnicodeCategory.NonSpacingMark)
{
stringBuilder.Append(c);
}
}
return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
}
Get the Code!
As usual, you can download my code from my DropBox account here. As usual, they will only let you download if you create a free account with them. Note: my zip file contains all the food lists, located in my bin folder.