Matching Game

Another week, another riddler. I really liked this one, if a bit clear cut. The problem:

I have a matching game app for my 4-year-old daughter. There are 10 different pairs of cards, each pair depicting the same animal. That makes 20 cards total, all arrayed face down. The goal is to match all the pairs. When you flip two cards up, if they match, they stay up, decreasing the number of unmatched cards and rewarding you with the corresponding animal sound. If they don’t match, they both flip back down. (Essentially like Concentration.) However, my 1-year-old son also likes to play the game, exclusively for its animal sounds. He has no ability to match cards intentionally — it’s all random.

If he flips a pair of cards every second and it takes another second for them to either flip back over or to make the “matching” sound, how long should my daughter expect to have to wait before he finishes the game and it’s her turn again?

To solve this we can look at each “level” independently, where a level is the number of pairs of cards remaining. We start at level 10 and our goal is to get to level 0. To figure out the estimated amount of time on, for example, level 10 we use the equation:

t_{10} = \frac{1}{19}(2) + \frac{18}{19}(2+t_{10})

This says the first card selection doesn’t matter – but after selecting it we have to select the second card and there is only one pair. This equation shows that there is a 1/19 chance we correctly select the card and proceed, while costing two seconds. There is also a 18/19 chance we fail, which costs us two seconds plus the time to successfully complete the level. Solving this gives us:

t_{10} = 38

Extending this we can see that solving for a generalized level is:

t_{n} = \frac{1}{2n-1}(2) + \frac{2n-2}{2n-1}(2+t_{n})

Summing levels 1-10 gives us 200 seconds. This was confirmed by brute forcing it in python.

import random, math

def run_trial(card_pairs): 
  time = 0
card_set = [math.floor(i/2) for i in range(card_pairs*2)]
while len(card_set):
    selection_index = [i for i in range(len(card_set))]
    random.shuffle(selection_index)
    if card_set[selection_index[0]] == card_set[selection_index[1]]:
      value = card_set[selection_index[0]]
      card_set.remove(value)
card_set.remove(value)
time += 2
return time

sum_time = 0
trials = 10000
for i in range(trials): sum_time += run_trial(10)
print("Average time: " + str(sum_time/trials))

 

Advertisements

A Classic Construction Problem

Another week, another Riddler. The question:

Consider four towns arranged to form the corners of a square, where each side is 10 miles long. You own a road-building company. The state has offered you $28 million to construct a road system linking all four towns in some way, and it costs you $1 million to build one mile of road. Can you turn a profit if you take the job?

Extra credit: How does your business calculus change if there were five towns arranged as a pentagon? Six as a hexagon? Etc.?

After a few napkin drawings I landed on this shape:

shape.png

Then I set up this series of equations:

Untitled2.png

Plugging that into Python we get answer of 27.3205 miles of bridges with an x_1 distance of 2.887.

Figure_1.png

Pretty simple but fun!

 

Camel Up Cup 2k18

Get ready for the premier bot creation board game tournament of the year!

Here’s the plan: A bunch of people make a bot to play the board game Camel Up. Then in a battle of wits we get together and pit our bots against one another. The winner will get a trophy. This is somewhat similar to Halite except way less competitive and no one will get a job as a result

CamelUp.PNG

The game

The game itself:

– The game is called CamelUp. I own a copy and can lend it out to try. There is also a copy at Cafe Mox in Ballard and maybe one at RayGun in Cap Hill
How to play: this video does a pretty good job of explaining how to play the game. Its five minutes
– We will playing the game with four players (bots) in each round. Player ordering and stuff will be figured out later. Only points will be awarded to the winning player

Cropped.png

Rendering of trophies

The bot details:

– We are using Python 3.x
– Your bot will be a function that I will pass the player number and gamestate to. Using that you should return your action
– I may be patching the game leading up to the event. It should just be for bugs / things I’ve missed. Hopefully nothing crazy though. Let me know if you something

Please invite anyone! Teams are cool! Reach out with questions.

The API can be found here

 

boardstate.PNG

Example of a player action

Kaleidoscope

This was a project designed to make a functional kaleidoscope and as a use case for learning how to use a lathe. It took a few revisions to get the scale and dimensions correct but the result is one that I am pretty proud of

 

kaleidoscope.jpg

An exterior and interior of a Rev C kaleidoscope

 

kaleidoscopeimage.jpg

Looking through one

Link to build pics

Cat in a Box

Another week, another puzzle. This one comes from MindYourDecisions on YouTube as suggested by a friend. Here’s the problem:

catproblem-e1520311636896.png

While I was able to logic out a solution that would find the cat in 7 steps the program I wrote was able to do it in 6. That solution is:

#Round 0 I select box 2
#Possible boxes the cat can be in: [1, 0, 1, 1, 1]
#Round 1 I select box 3
#Possible boxes the cat can be in: [0, 1, 0, 1, 1]
#Round 2 I select box 4
#Possible boxes the cat can be in: [1, 0, 1, 0, 1]
#Round 3 I select box 4
#Possible boxes the cat can be in: [0, 1, 0, 0, 0]
#Round 4 I select box 3
#Possible boxes the cat can be in: [1, 0, 0, 0, 0]
#Round 5 I select box 2
#Possible boxes the cat can be in: [0, 0, 0, 0, 0]

The benefit of this program is that it is easily able to find solutions for cases where there are more than five boxes, the cat can move one or two, etc.

Of course his explanation was cleaner but its a little nice to be able to say you exhaustively searched all the cases 🙂

import random
import copy
def select_box(sel_box,boxes):
#Input a box, it does the proceeding logic
old_boxes = copy.deepcopy(boxes)
for i in range(0,len(boxes)):
if old_boxes[i] > 0:
if (i>0) : boxes[i-1] += 1
if (i 0) for x in boxes] #reduces all non-zero box values to one
return boxes

def print_history(path,box_hist):
for i in range(0,len(path)):
print("Round " + str(i) + " I select box " + str(path[i]+1)) #plus one because the problem uses 1-indexing
print("Possible boxes the cat can be in: " + str(box_hist[i]))

def find_path(thresh):
#set base values
boxes = [1,1,1,1,1] #A 1 indicates the cat can be in the box
min_cat_spots = len(boxes)
path = []
box_hist = []

#Select a random box, check state after each selection. Repeat until finished or it won't work
while min_cat_spots !=0 and len(path) < thresh:
selection = random.randint(0,len(boxes)-1)
path.append(selection)
box_hist.append(boxes)
boxes = select_box(selection,boxes)
cat_spots = sum(boxes)
if cat_spots < min_cat_spots:
min_cat_spots = cat_spots
return [len(path),path,box_hist]

#Search for paths while the the search has a chance to be the new low-score
thresh = 14 #any large number
for i in range(0,10000):
results = find_path(thresh)
if results[0] < thresh:
thresh = results[0]
print_history(results[1],results[2])