Project Euler – Problem 145

May 5, 2011

The problem: Problem 145

Analysis

Suprisingly enough the brute-force solution works. It takes a couple of minutes but it gets the job done. Suppose we have a function called is_reversible then the following algorithm can be used to count all the reversible numbers below one-billion.

count = 0
for i = 1 upto 1000000000 do
  if (is_reversible(i)) then count++
endfor
output count

Implementation

Uses the OCaml programming language.

(* a left fold over the digits of a positive integer *)
let rec nfoldl f v = function
    0 -> v
  | n -> nfoldl f (f v (n mod 10)) (n / 10)

let reverse = nfoldl (fun n d -> (n * 10) + d) 0

let odd n = n mod 2 = 1
let allodd = nfoldl (fun b d -> b && odd d) true

let is_reversible n =
  n mod 10 <> 0 && allodd (n + reverse n)

let naive_count n =
  let cnt = ref 0 in
    for i = 1 to n-1 do
      if is_reversible i then incr cnt;
    done;
    !cnt

The above code is elegant and it solves the problem but I’m not satisfied with its speed. In that regard I decided to improve on the algorithm a bit.

More Analysis

Notice that since the sum of a number, n, and its reverse, reverse(n) must yield a number with all digits odd, it must be the case that n cannot begin and end with digits of the same parity (i.e. both even or both odd). Hence, a likely candidate must lie in one of these sets A = \{n : n \,\text{begins with}\, 2, 4, 6, 8 \,\text{and}\, n \,\text{ends with}\, 1, 3, 5, 7, 9\} or B = \{n : n \,\text{begins with}\, 1, 3, 5, 7, 9 \,\text{and}\, n \,\text{ends with}\, 2, 4, 6, 8\}. Now, |A| = |B| = (4*5)*10^7 = 200000000, i.e. 200 million. Furthermore, if a number in A is reversible then its reverse is in B and is obviously reversible as well. This means we only need to generate the elements and count those in A that are reversible. Our final answer must then be multiplied by 2 to account for those in B.

A Better Implementation

Uses the Haskell programming language. I switched languages when I realised that the list code I needed for this to work was not implemented using tail-recursion in the OCaml standard library. I did rewrite those pieces using tail recursion but in the end I still decided to switch languages just for the fun of it. Actually, the Haskell version below isn’t much better. Its still slow. But very elegant :D. At least I can use it for testing correctness on small cases since the solution is so simple and easy to read.

nfoldl _ v 0 = v
nfoldl f v n = nfoldl f (f v (n `mod` 10)) (n `div` 10)

nreverse = nfoldl (\n d -> (n * 10) + d) 0
allodd = nfoldl (\b d -> b && odd d) True
isReversible n = n `mod` 10 /= 0 && allodd (n + nreverse n)

countDigits = (+1) . floor . logBase 10 . fromIntegral

genCandidates n =
  let gen m i len = if i > len then
                      if m >= n then [] else [m]
                    else
                      if i == 1 then
                        concatMap (\d -> gen (m*10+d) (i+1) len) [1,3,5,7,9]
                      else if i == len then
                        concatMap (\d -> gen (m*10+d) (i+1) len) [2,4,6,8]
                      else
                        concatMap (\d -> gen (m*10+d) (i+1) len) [0..9]
  in concatMap (gen 0 1) [1..countDigits n]

betterCount = (*2) . length . (filter isReversible) . genCandidates

Finally, I bit my tongue and decided to code up a solution in everyone’s favorite system programming language, C.

#include <stdio.h>
#include <math.h>

#define FALSE 0
#define TRUE  1

#define even(n) ((n)%2==0)

int reverse(int n) {
  int m = 0;
  while (n > 0) { m = m*10 + (n%10); n /= 10; }
  return m;
}

int allodd(int n) {
  while (n > 0) {
    if (even(n%10)) return FALSE;
    n /= 10;
  }
  return TRUE;
}

#define is_reversible(n) ((n)%10>0 && allodd((n) + reverse(n)))
#define count_digits(n) ((int)(floor(log10(n) + 1)))

int __count;

void __better_count(int m, int i, int len, int n) {
  int j;
  if (i > len) {
    if (m < n && is_reversible(m)) __count += 2;
  } else {
    if (i == 1) {
      for (j = 1; j <= 9; j+=2) __better_count(m*10+j, i+1, len, n);
    } else if (i == len) {
      for (j = 2; j <= 8; j+=2) __better_count(m*10+j, i+1, len, n);
    } else {
      for (j = 0; j <= 9; j++) __better_count(m*10+j, i+1, len, n);
    }
  }
}

int better_count(int n) {
  int len;
  
  __count = 0;
  for (len = 2; len <= count_digits(n); len++) __better_count(0, 1, len, n);
  return __count;
}

int main(void) {
  printf("%d\n", better_count(1000000000));
  return 0;
}

In the end, the problem was easy and I had a lot of fun playing around with the various languages. I learned quite a lot, so it certainly wasn’t a waste of time.

Getting Previous Play Whe Results using Python

April 13, 2011

Quick Update (17th January, 2012):

  • I have created an extension for Google Chrome that allows you to view the latest Play Whe results. Check it out here: Play Whe Results Viewer
  • You can view even more results and statistics if you follow this link: Play Whe Smarter
  • And finally, you can like the Play Whe Smarter page on facebook to keep up to date with the latest tricks and strategies for winning at Play Whe. Like us here: Play Whe Smarter

Play Whe is a numbers game brought to Trinidad by Chinese immigrants. Its usually played by persons who are influenced by intuition, superstition, dreams and caprice. The rules to the game are pretty simple. You have 36 numbers, 1 through 36. When a number is drawn the person(s) who selected that number wins a sum of money; $24 to every $1 that was played. Everyday (except Sundays and public holidays) there are two drawings, one at 1:00pm and the other at 6:30pm.

The NLCB provides a Play Whe Statistics form that can be used to query the numbers that were drawn on any given day way back to the first draw on July 4th, 1994.

The Play Whe Statistics Form

That is great.

However, the results are not returned and can’t be returned in a program friendly format. json or XML would have been nice. Even if the HTML it returned was properly marked-up I would have been thankful, but that is not the case either. I am still lucky though, because there seems to be some consistency to the data and so it can be extracted using regular expressions.

Let’s assume we want to get a “Monthly Summary” for April, 2011. Well, we will need to figure out how the Play Whe Statistics form is querying the server. If we fire up Live HTTP Headers in Firefox, we will be able to determine the POST request that’s being sent to the server when a query is made for the “Monthly Summary”. [By the way, I know its a POST request due to the fact that a GET request would have passed the arguments in the URL.]

The three highlighted regions in the dialog below gives us all the information we need.

Play Whe Query for April 2011 Monthly Summary

With this information we can now write some Python code to make the query.

import urllib
sel = '/search/pwq/countdateCash.php'
host = 'nlcb.co.tt'
params = urllib.urlencode({
  'month': 'Apr',
  'year': 11
})
data = urllib.urlopen('http://' + host + sel, params).read()
print data

It returns some messed up HTML but with a little regular expression magic we can extract some useful information:

import re
pattern = r"(\d{2})-Apr-11: Draw # (\d+) : (AM|PM)'s draw  was (\d+)"
results = re.findall(pattern, data)
# sorts by draw number and then prints the results
for res in sorted(results, key=lambda r: r[1]):
  print res

Here’s a snippet of the data that’s returned:

('01', '10293', 'AM', '19') # the draw at 1:00pm
('01', '10294', 'PM', '23') # the draw at 6:30pm
('02', '10295', 'AM', '3')
('02', '10296', 'PM', '35')
('04', '10297', 'AM', '1')
('04', '10298', 'PM', '33')
('05', '10299', 'AM', '4')
('05', '10300', 'PM', '32')
('06', '10301', 'AM', '28')
('06', '10302', 'PM', '20')
('07', '10303', 'AM', '29')
('07', '10304', 'PM', '17')
('08', '10305', 'AM', '15')
('08', '10306', 'PM', '13')
('09', '10307', 'AM', '5')
('09', '10308', 'PM', '32')
...

That’s it. You now have a programmatic way for getting your current and past Play Whe results. Enjoy!

Project Euler – Trinidad and Tobago Standings

November 21, 2010

Below is an image of the current standings in projecteuler.net as of 21/11/2010 for Trinidad and Tobago.

Project Euler standings as of 21/11/2010

As you can see I’m 2nd in the standings. Damn you wallygold. Lol. I need to solve 10 more problems to reach Level 3. Hopefully, I will have time to do it before the year ends.

A note about the languages I use. Currently I’m using racket (a scheme based language) to solve the problems. However, in the past I’ve solved some of the problems using C, Java, Python, Haskell, Scala, LISP and of course the trusty old pencil and paper. I guess I tend to utilize whatever language I am currently into.


Follow

Get every new post delivered to your Inbox.

Join 206 other followers