DIY Hangboard

Being a renter I really wanted a way to work on bouldering while at home. In order to work on both pull-up and finger strength the internet suggested getting a hangboard — however they didn’t look like they would fit the geometry of my odd door or required big bolts. As a result I had to go with the DIY option


The final product


I didn’t document it well but a rough parts list:

Here is an image from the other side


Radar Charts

Recently on FiveThirtyEight they have used “radar charts” quite a bit. Frequently used in video games to show multidimensional data while being visually striking.



While these are cool what I found myself doing was trying to compare the relative areas. While this isn’t incorrect it can be deceiving — the order and therefore shape they make can skew the amount of area they take up. To prove this I recreated them in Python:



It is interesting that the area can grow by ~20% just by reordering the attributes.

Maybe not revolutionary but something to consider when making or viewing these graphs

Continue reading

Creating Crossword Grids

Another week, another riddler. This week’s puzzle:


Crossword puzzle grids typically obey a few rules and conventions.

  1. They are 15-by-15.
  2. They are rotationally symmetric — that is, if you turn the grid upside down it appears exactly the same.
  3. All the words — that is, all the horizontal and vertical sequences of white squares — must be at least three letters long. All the letters must appear in an “across” word and a “down” word.
  4. The grid must be entirely connected — that is, there can be no “islands” of white squares separated from the rest by black squares.

First question: How many such crossword grids are there?

Second question: Crossword constructors do well to avoid using “cheater squares,” black squares whose addition makes some words shorter but does not change the puzzle’s total word count. How many grids are there without cheater squares?

Extra credit: The Sunday “New York Times” puzzle is 21-by-21. How many of those are there, with and without cheater squares?


So in short we didn’t make all of the grids — this turned out to be very difficult and I am very interested to see the approach that others used to tackle this problem. However we did make something that generated around a thousand of them



Code can be found here

Elf Playlist

Another week, another riddler. Here is this week’s problem:

In Santa’s workshop, elves make toys during a shift each day. On the overhead radio, Christmas music plays, with a program randomly selecting songs from a large playlist.

During any given shift, the elves hear 100 songs. A cranky elf named Cranky has taken to throwing snowballs at everyone if he hears the same song twice. This has happened during about half of the shifts. One day, a mathematically inclined elf named Mathy tires of Cranky’s sodden outbursts. So Mathy decides to use what he knows to figure out how large Santa’s playlist actually is.

Help Mathy out: How large is Santa’s playlist?

So to do this we used minimized N for the following


P_{N} = \prod_{i=1}^{100}(1-\frac{i}{N})\approx0.5


Each term represents the chance that the song is not a repeat — so the first song has a 0/N chance, so the chance that it is not that song is 1. This gets multiplied by the (1-1/N) for the second song, etc. etc.

This results in 7176 when our shift length is 100. Next, we vary the shift length and find the resulting playlist length:


This, interestingly, follows the following equation for a playlist length of l and playlist length of N:

N = 0.7214l^2 - 1.8316l+2.6343


Now we know why the shift length is 100, its likely the total number of Christmas songs 🙂

import matplotlib.pyplot as plt

def num_songs_in_playlist(goal_prob,shift_len_in_songs):
	prob = 0
	songs_in_playlist = 200
	while prob < goal_prob:
		prob = 1
		for i in range(shift_len_in_songs): prob = (1-(i/songs_in_playlist)) * prob
		songs_in_playlist += 1
	return songs_in_playlist

x = [i for i in range(50,200)]
y = [num_songs_in_playlist(0.5,i) for i in range(50,200)]

plt.xlabel("Shift Length (songs)")
plt.ylabel("Playlist Length")
plt.title("Santa's playlist length to ensure repeating\n probability 0.5 over various shift lengths")


imagine a hockey game


Okay okay this is a fun problem. To do this we have to look at team B’s expected goals.

The chance that team B gets 0 points is


P_{0} = (1-0.055)^{20} = 0.3226


The chance team B gets 1 point is:


P_{1} = 20*(0.055)*(1-0.055)^{19} = 0.3795


and the chance team B gets 2+ points is:


P_{2+} = 1 - P_{0} - P_{1} = 0.3019


While the difference isn’t large, it holds that team A is expected to win. Counterintuitive!

Hue Lights 3.0

This is the third iteration of my Hue lights integration. An increase in technical knowledge and the fact that I am now living alone means that I could really go all out with this.

Hue lights are an RGB lightbulb that can change colors from various triggers. This project was designed to setup some unique or custom triggers.




Part I: Dash Buttons

These are small, wireless buttons that Amazon makes to make it easy for you to buy things. However I redirect these buttons so they turn all the lights on and off.



This uses Scapy to sniff the network and anytime something makes a request with the MAC address of a button I turn the lights on if most are off or vis versa.


Part II: Weather Forecast

Every morning, when my alarm goes off, my lights will turn on and this will look up the weather in my area using WeatherUnderground and set the lights to represent the weather.


It looks up the weather code against this excel spreadsheet that shows what color the lights will be

Part III: Scene Controller

This is a button pad that selects from eight scenes that have been preprogrammed for whatever activity seems “right” — so there is one for movies, yoga, reading, etc. Also its just fun to show off the system


This gets imported as a MIDI device using Pygame and then it polls for button presses. After each button press it looks up the code in the same spreadsheet as the weather codes




Thats it! Thanks for reading. The code can be found here

7/L Segment Display

Today I was troubleshooting a sensor that was giving an error code — but Error 52 “Over Voltage” was not what I expected… regardless I checked the voltage and it looked fine. About ten minutes later I realized that the display was mounted upside down and it was Error 25, “Programming Error” — duh.



Which one? Choose wisely


While this is totally my fault it is also avoidable. So if you are a company that makes things with important codes using a seven segment display AND your display can logically be upside down then don’t use any numbers that are also valid in either orientation.




Here are the amount of numbers that satisfy that criteria:


To find this I used the criteria of a number having to be not a number upside down (because of a 7, 4 or 3) or be itself when upside down (96 -> 96).

1 Digit Numbers
2 Digit Numbers
3 Digit Numbers
4 Digit Numbers
5 Digit Numbers


Here is the code:

import matplotlib.pyplot as plt

def flip(num):
    flips = [

    new_num = ""
    for i in range(len(num)):
        new_num += flips[int(num[len(num)-1-i])][1]
    if new_num == num or len(new_num) &amp;gt; len(num): return num
    else: return

def find_all_digits(digits):
    valid_options = []
    for i in range(0,10**digits):
        val = str(i)
        val = "0"*(digits-len(val))+val
        if flip(val) is not None:
    return len(valid_options)

x,y = [],[]
for i in range(1,9):

fig = plt.figure()
ax = fig.add_subplot(111)
for i,j in zip(x,y):
plt.title("Number of valid numbers that aren't confusing when upside down")
plt.xlabel("N\n Number of Digits Used")
plt.ylabel('Valid Entries / Total Possible Entries')