The Case

Case Four. El Puente has decided to test us. First, some maths, then some GIS, and finally some Bowie. I’ve no idea who El Puente will turn out to be, but anyone that includes the Thin White Duke in a nerdy code hunt must be kinda cool.


Part One - Primes

First up a number puzzle. Find the largest special prime under 100M. We’re given a table of primes to chew through.

But First We Optimise

Premature Optimisation. Is it really the root of all evil? IDK, but given we have 5,761,455 primes to test, some optimisation seems logical.

We know a special prime is one that can be expressed as the sum of two consecutive primes plus 1. We need use our tables of primes to satisfy:

$$ \begin{align} a+b+1&<x \end{align} $$ Where a and b are consecutive primes and x is 100M. We can rearrange: $$ \begin{align} a&<x-b-1 \end{align} $$ We also know $$ \begin{align} a&<b \end{align} $$ If we add (2) and (3) $$ \begin{align} 2a&<x-1 \\ \Rightarrow a&< \frac{(x-1)}{ 2 } \end{align} $$

So we can limit the search to consecutive primes less than 50M. (Yes, pretty obvious, but it’s my blog and I wanted to play with KaTex).

I’m sure there’s some more fancy maths to work out the most optimal b, but we’re devs, let’s just make a random guess and calculate 20 candidate special primes:

let SpecialPrimes = Primes
| where Prime < 50000000
| top 20 by Prime desc
| extend NextPrime = next(Prime)
| extend SpecialPrime = (Prime + NextPrime + 1);

But these may or may not be actual primes. If we join them back to the Primes table, then take the max, we should get an answer:

let SpecialPrimes = Primes
| where Prime < 50000000
| top 20 by Prime desc
| extend NextPrime = next(Prime)
| extend SpecialPrime = (Prime + NextPrime + 1);
| join kind=inner Primes on $left.SpecialPrime == $right.Prime
| summarize MaxSpecialPrime = max(SpecialPrime)
| project TheAnswer=strcat("", MaxSpecialPrime)


We can also see our “optimised” query took about 520ms to run.

Click the link.

Part Two - Trees and Major Tom

So next, we have to find our friend in NYC, near an American Linden tree that’s close to four Schubert Chokecherries and a Turkish Hazelnut. Close meaning within 66m radius. Shouldn’t that be 216 Freedom Units since we’re in New York?

First, we run the given code to load a table of tree locations, types and sizes.

To group by a location we can use geo_point_to_h3cell and coincidentally, the 66m radius corresponds to a resolution of 10.

We can then aggregate etc by the H3 cell token to find the correct cell where our guy is hiding. I’m just going to pivot the tree names by cell and filter for 4 Schubert Chokecherries and at least 1 Turkish Hazelnut and American Linden.

From there it’s just a matter of joining back to our trees list, finding the location of the smallest American Linden.

let trees = nyc_trees
| extend  cell=geo_point_to_h3cell(longitude, latitude, 10);
let cells = trees
| where spc_common like "Turkish Hazelnut" or spc_common like "Schubert" or spc_common like "American Linden"
| project-keep cell, spc_common
| evaluate pivot(spc_common)
| where ["'Schubert' chokecherry"] == 4 and ["Turkish hazelnut"] > 0 and ["American linden"] > 0;
| join kind=inner  cells on cell
| where spc_common == "American linden"
| summarize arg_min(tree_dbh, *)

Plugging the lat/long into the VirtualTour function gives us a Street View. Looking around for a while, we can find the key and decode the encrypted string (using a verbatim literal) with the provided Decrypt func.

Impressive, you got it right! Something BIG is going to happen… Keep the next hint close to you, it will help you. We will be in touch soon. El Puente

I’m happy, hope you’re happy too.