1 Hour Coding Challenge

I had an hour to spare, and decided that I would try challenging myself. I wanted to make a clone of Minesweeper that my kids could play. I thought it would be fun to see if I could make a fully working version of Minesweeper in one hour without any reference.

I grew up with Macintoshes, and as such never actually had a Windows machine on which I could play Minesweeper, so I know it mostly by reputation, and not hours of playing it as an adolescent.

I had a starting point that I used; my implementation of Hopeless already had a canvas and some functions to draw beveled tiles.

Working from memory, I morphed hopeless into how I pictured Minesweeper in my head. In just about an hour, I had a playable game completed. Honestly, the most complicated part of the game is uncovering blank tiles when you click on them. I made a recursive function to do that, which at first was very inefficient and took too long!

With my playable game completed within the time limit, it was time to score myself on how it turned out.

While the basics of the game were correct, I got the look completely wrong! I made the tiles raised after being clicked. Thinking about it after the fact, it made sense that the buttons would be raised until clicked. I also got the colors wrong, as well as the size of the fields/number of mines. I didn’t mind these issues, so I showed it to my wife who spent a lot more time playing Minesweeper growing up. She was annoyed at the discrepancies.

So I spent another hour or two cleaning it up and making it more true to the original. This included more accurate colors, correcting the beveled blocks, making the same difficulty options, and also adding the ability to click on already-revealed numbers and having it automatically toggle it’s neighbors if the mine conditions had been met. This was actually a feature I didn’t know about!

So in the end, I think I ended up with a pretty good representation of Minesweeper.

Why would I bother doing this though? Aren’t there plenty of places to play this game already? Well, yes. One of the reasons I make the simple games I do is because I grow frustrated by free apps available on the iPhone and on websites that are laden with ads. Sometimes I want to show my kids a game, and not have the annoyance of ads.

It can also just be a fun challenge. I enjoyed doing this and am quite happy with the result. Please feel free to play it here!

Project Euler 174

We shall define a square lamina to be a square outline with a square “hole” so that the shape possesses vertical and horizontal symmetry.

Given eight tiles it is possible to form a lamina in only one way: 3 × 3 square with a 1 × 1 hole in the middle. However, using thirty-two tiles it is possible to form two distinct laminae. If t represents the number of tiles used, we shall say that t = 8 is type L(1) and t = 32 is type L(2).

Let N(n) be the number of t <= 1000000 such that t is type L(n); for example, N(15) = 832.

What is sum of N(n) for n=1 to 10?

This question turned out to be fairly straight forward, and is solvable using a brute force method.

Basically, we want to arrange tiles in laminae that are symmetrical, and don’t use more than 1,000,000 tiles. The largest lamina we can arrange would then be 250,000 tiles per side, with a wall thickness of 1.

The way I set this up was to iterate through all lamina side lengths (L) from 3 to our limit, 250,000. Then, for each, iterate for different hole sizes (H) in the middle from L–2 down to 1. (The evenness of L and H have to match.)

Calculating the number of tiles is an easy prospect; t = L² – H². A dictionary then keeps track of how many tiles are used for each combination. Once we’ve brute forced all the combinations, look through the dictionary to count up all the tile values that have 10 solutions or less!

let history = {};
let limit = 1000000;

for (let L=3; L<250000; L++){
    let L2 = L * L;
    // Hole (H) size must be at least 1, smaller than or equal to l-2
    for (let H=0; H<=L-2; H++){
        // Calculate number of tiles (t) in lamina
        let t = L2 - (H * H);

        // L and H evenness must match
        if (L%2 != H%2) continue;
        
        // Ignore answers over limit
        if (t > limit) continue;

        // Store result in history
        if (history[t] == undefined)
            history[t] = [];

        history[t].push(L);
    }
}

let count = 0
for (let i in history)
    if (history[i].length <= 10)
        count++;

console.log(count);

The first time I ran this, it was much slower than anticipated. I let it run overnight, and was happy to see the correct result when I checked on it the next day. I wondered what I needed to optimize to make it run better. It turns out that I had typed the upper limit, L, as 2,500,000! By decreasing that to the proper value, that reduced the compute time to 17 seconds.

I was able to find one more low-hanging optimization opportunity. By iterating through the H values from largest to smallest, the number of tiles, t, would increase. Once that value got over the 1,000,000 limit, I can break out of the loop, and go to the next value of L. This saves a lot of time computing out of bounds answers!

for (let L=3; L<250000; L++){
    let L2 = L * L;
    // Hole (H) size must be at least 1, smaller than or equal to l-2
    for (let H=L-2; H>1; H-=2){
        // Calculate number of tiles (t) in lamina
        let t = L2 - (H * H);

        // Break once we get over limit
        if (t > limit) break;

        // Store result in history
        if (history[t] == undefined)
            history[t] = [];

        history[t].push(L); 
    } 
}

This optimization pushed the compute time down to .278s! That’s a very reasonable time for Project Euler.

Project Euler 114

It’s been a while since I’ve taken the time to solve some Project Euler problems. I thought today would be a good day to pick it up and try solving one I had not been able to solve the last time I tried.

I’m going to speak generically about the problem because I don’t want to spoil it for anyone who may be trying to solve it. In brief, I had written a brute-force method for solving the problem, but as Project Euler so often does, they made the scale so huge that brute-force methods often fail. I turned to the internet to try to find a clue to point me in the right direction.

Sadly, one of the links I clicked didn’t have a clue, but just said “This is a Fibonacci sequence problem.”

I couldn’t unsee it, and it was clearly the way the problem was intended to be solved at scale. It felt like it was ruined, and I regretted trying to find assistance.

I decided to go do another problem without getting any aids or accidentally cheating. The problem I chose was another problem that scales quickly. The problem is stated as follows:

A row measuring seven units in length has red blocks with a minimum length of three units placed on it, such that any two red blocks (which are allowed to be different lengths) are separated by at least one grey square. There are exactly seventeen ways of doing this.

How many ways can a row measuring fifty units in length be filled?

I decided to start this problem with a brute force approach, even though I knew it wouldn’t scale. I wrote a recursive function to create rows filled with tiles. I started with the length of 7 they provided in the example, and I too got the correct 17.

function recurse(array){
    // Find the length of the array
    let s = tile_sum(array); 

    // If the array it too long, abort
    if (s > limit) 
        return;

    // If the array is correct size,
    // check for uniqueness and record, abort
    if (s == limit){ 
        record(array);
        return;
    }

    // Add tiles sized 1-limit and recurse
    for (let t=1; t<=limit; t++){
        if (t == 2) continue; // Tiles length 2 don't exist

        // Add a single tile spacer in if we are adding a red tile
        if (array[array.length-1] != 1 && t > 1)
            array.push(1);

        // Add tile to the array and recurse
        recurse(array.slice().concat([t]));
    }
}

 

I slowly increased the length by one to make sure nothing would break in my algorithm. I also noted the numbers as it computed them.

f(7) = 17
f(8) = 27
f(9) = 42
f(10) = 72

I thought that having learned my lesson from the previous problem I might have some luck by identifying this series of numbers. I went to the OEIS (Online Encyclopedia of Integer Sequences) and entered in these integers.

Spoilers below…

The OEIS search provided a result! It was A004695, the Fibonacci sequence… (but halved). Sure enough, computing the correct number in the Fibonacci sequence, and halving it yielded the correct answer for this problem.

I can’t believe two problems in a row ended up having the same shortcut. I wonder if the next one will as well…

 

© 2007-2015 Michael Caldwell