The Samovar


Countdown numbers game in Python

One of the things about being ill is that you have to spend a lot of time in bed with nothing much to do. Having watched the whole first series of the Sopranos, I had to find something else. So here’s the result. I revisited an old program I wrote many years ago to solve the Countdown numbers game.

In this game, you’re given six numbers between 1 and 100 and a target number between 100 and 999. You’re given 30 seconds to try to make the target using the six numbers and the operations plus, minus, times and divide.

I originally wrote a program to solve this many years ago (when I was about 14 I think), but the algorithm I used was pretty horrible. I worked out by hand all the possible arrangements of brackets you could have for six numbers, and then tried each operator and number in each appropriate slot. It worked, but it was ugly programming.

Recently I’ve been learning Python for an academic project, and so I thought I may as well try rewriting it in Python. I think the solution I’ve come up with is nicer than any of the solutions I’ve found on the internet (mostly written in Java or C), although having written it I found this paper which uses a very similar solution to mine (but in Haskell rather than Python).

Python programmers might get something from the minimal code below (all comments and docs stripped out), or you can take a look at the full source code here, including detailed comments and docs explaining the code and algorithm.

My ideal (as always with Python) was to write a program you could just look at and understand the source code without comments, but I don’t think I achieved that. I’d be interested if a more experienced Python programmer could do so. Let me know.

This version is incomplete, from the slower version, and is supposed to be understandable without explanations (takes about 40 seconds to find all solutions, too slow for Countdown):

def ValidExpressions(sources,operators=standard_operators,minimal_remaining_sources=0):
    for value, i in zip(sources,range(len(sources))):
        yield TerminalExpression(value=value, remaining_sources=sources[:i]+sources[i+1:])
    if len(sources)>=2+minimal_remaining_sources:
        for lhs in ValidExpressions(sources,operators,minimal_remaining_sources+1):
            for rhs in ValidExpressions(lhs.remaining_sources, operators, minimal_remaining_sources):
                for f in operators:
                    try: yield BranchedExpression(operator=f, lhs=lhs, rhs=rhs, remaining_sources=rhs.remaining_sources)
                    except InvalidExpressionError: pass

def TargetExpressions(target,sources,operators=standard_operators):
    for expression in ValidExpressions(sources,operators):
        if expression.value==target:
            yield expression

This version is actually complete, from the faster version which needs the comments to explain (takes about 15 seconds to run, good enough to win Countdown):

sub = lambda x,y: x-y
def add(x,y):
    if x<=y: return x+y
    raise ValueError
def mul(x,y):
    if x=2+minremsources:
        for e1, rs1, v1 in expressions(sources,ops,minremsources+1):
            for e2, rs2, v2 in expressions(rs1,ops,minremsources):
                for o in ops:
                    try: yield ([o,e1,e2],rs2,o(v1,v2))
                    except ValueError: pass

def findfirsttarget(target,sources,ops=standard_ops):
    for e,s,v in expressions(sources,ops):
        if v==target:
            return e
    return []
Advertisements


Countdown letters game
July 10, 2007, 1:33 am
Filed under: Frivolity, Games, Java, Programming | Tags: ,

I’ve been quite impressed by the abilities of my shiny new phone, especially the sort of games and programs you can run on it. I downloaded software to calculate poker odds, translate words between 15 different languages, connect to Google maps, and tell me all sorts of political statistics from the CIA World Factbook (which surprisingly I’ve already used in one argument I got into with someone!).

So I wondered if I too could write some fantastic software for my phone. What I really wanted to do was to write a program to crack the Enigma code on my phone, thus proving the claim that is sometimes made that modern phones have as much computing power as the whole computing effort of WW2. That seemed too much like hard work though. So instead, I set myself the more modest task of beating Dictionary Corner in Countdown.

For those who don’t know, Countdown is a gameshow in the UK. One of the games is to find the best word you can make with 9 randomly chosen letters in 30 seconds. After the contestants have said what their best words are, Dictionary Corner tell them what they could have got. Obviously they use a computer to do it, but until now we the viewers have been at a disadvantage unless we were willing to have our laptops out while we watched the show. No longer!

I present the mobile phone Countdown letters game solver (click to go to the download page, for Java enabled phones). It will find the five best words you can make in only 10 seconds (or less on a newer phone than mine).  Here it is in action on a Countdown conundrum:

clg-in-action.jpg

Sadly, even the awesome power of the mobile phone is not enough to beat Countdown legend Conor Travers (14) who managed to get this one in under two seconds.

Do please download it and have a go with it. It works on my phone but I’d like to have feedback to find out if it works for other people’s phones. For the technically minded, it requires J2ME, including MIDP2.0 and CLDC1.0,  or better.