Allegro.cc - Online Community

Allegro.cc Forums » The Depot » boggle solver

This thread is locked; no one can reply to it. rss feed Print
 1   2 
boggle solver
Matthew Leverton
Supreme Loser
January 1999
avatar

Attached is a Boggle solver (Windows binary) that I wrote with an official Scrabble wordlist. From a command prompt, just run:

boggle 100000

To solve 100000 random boards. The best boards are displayed with their scores. Then the elapsed time is reported. I'm curious to see how fast it is on different CPUs, particularly multi-cores. Report your results! (along with your highest board if you wish)

If you are sufficiently bored, I challenge you to write a faster solver than mine.

I'm looking at it from a statistical perspective to find most common words, partial words, etc. I know other people have already done it, but it's no fun reading other people's results.

Some of the 4x4 boards have over 1,000 words! The Scrabble dictionary is a bit generous and I doubt casual players would allow most of the obscure ones, but it still would be funny to win a "first to 50 points" game in the first round. ;D

Vanneto
Member #8,643
May 2007

I have an Intel Core 2 Duo E4500 @ 2.2GHz. Some results:

Solving 100,000 puzzles:

Score: 2342 Solved 100000 boards in 8.313000 seconds. <12029.352015/s>

Solving 500,000 puzzles:
Score: 2622 Solved 500000 boards in 42.140999 seconds. <11864.929967/s>

Solving 1,000,000 puzzles:
Score: 2943 Solved 1000000 boards in 83.390999 seconds <11991.701909/s>

Quite fun and interesting.

EDIT:
Fixed typos from "word count" to "score" as Matthew said below. Sorry about that. :P

In capitalist America bank robs you.

Matthew Leverton
Supreme Loser
January 1999
avatar

The number displayed is the score, not the word count. That is, [1, 1, 2, 3, 5, 11] points for [3, 4, 5, 6, 7, and 8+] letter words.

OnlineCop
Member #7,919
October 2006
avatar

1C:\allegro\596514>boggle.exe 100000
2Loading dictionary...OK
3258
4D B N E
5G E S C
6E Z S S
7T D R U
8 
9311
10K E T A
11A D O Y
12L A S N
13U T H H
14 
15599
16W O I E
17Y E S O
18N E R O
19H I N R
20 
21676
22T I B E
23I O R T
24U R E E
25S F S G
26 
27717
28S O N A
29M T N I
30A V E S
31M T Z D
32 
33778
34A E R O
35O D R Y
36I T A E
37E U T S
38 
39796
40D S O T
41N O I P
42T N E S
43E O A G
44 
451076
46I A T R
47L U A E
48E T S T
49C S H B
50 
511340
52S R C N
53S A E E
54A R P H
55E T E R
56 
571541
58S L R P
59E E A S
60B N T L
61D G O D
62 
632103
64O T N E
65T S E T
66A N E R
67P T I D
68 
69Solved 100000 boards in 14.797000 seconds (6758.126679/s)
70 
71C:\allegro\596514>

Looks like it takes advantage of multiple cores; is it multi-threaded, then?

And I guess I'm asking this too late, but it doesn't contain a virus, right? :o

My computer: Dual 2400 processors @ 1.83 GHz, 2 GB RAM

Thomas Fjellstrom
Member #476
June 2000
avatar

I don't really feel like rebooting into windows.. But I could test on my Q6600 if you get source ;) using pthreads....

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Vanneto
Member #8,643
May 2007

OK, here is the latest, with 10,000,000.

1C:\Documents and Settings\Miha\Desktop>boggle 10000000
2Loading dictionary...OK
3622
4L T D E
5M O E I
6B R L S
7A S R W
8 
9985
10O G S N
11N R R L
12E I T E
13O S E O
14 
15986
16C Q E T
17T E L D
18H S A E
19F A R T
20 
211032
22C R M N
23R O S O
24S R T K
25S E N I
26 
271266
28G R U T
29S E P E
30T S O R
31E D O N
32 
331305
34H E O Y
35T A E H
36B S R S
37I E E E
38 
391765
40S J E W
41T R N D
42E E E S
43P R O O
44 
452221
46U H R E
47D E S E
48L T E T
49B A S L
50 
512250
52G T A A
53E S E L
54T R N S
55E S U I
56 
573168
58S I A O
59F L E R
60A T E R
61O T S R
62 
633225
64U S E N
65E L S S
66T R E R
67O S E P
68 
693253
70S T E S
71T E E N
72T R E E
73M S R B
74 
753266
76S O A M
77S L E R
78I T E R
79D E S T
80 
813524
82E L M S
83S T A R
84B T E R
85X S E S
86 
87Solved 10000000 boards in 815.437012 seconds (12263.362904/s)

In capitalist America bank robs you.

Erikster
Member #9,510
February 2008
avatar

AMD Turion 64 x2 Mobile Technology TL-60 2.00 GHz

100,000 boards in 11.919 seconds <8389.965832/s>

It went nutz at 500,000, what have you done?:o

Cat! I'm a kitty cat. And I dance dance dance, and I dance dance dance.

Todd Cope
Member #998
November 2000
avatar

Processor: 2.8ghz Pentium 4 w/HT

Test 1:

1C:\Games\boggle>boggle 100000
2Loading dictionary...OK
3457
4L U N T
5L A I H
6Y L A V
7T A S N
8 
9504
10L O P L
11N I I A
12J N T E
13Y I D W
14 
15737
16V A Z S
17O T T I
18E S E H
19P E E T
20 
211012
22S T T T
23L E R A
24O S G M
25T W I I
26 
271217
28I M W H
29E A E B
30E R T T
31E N A S
32 
331255
34E S M S
35N R I L
36E O T I
37T T O R
38 
391289
40H A T B
41I R I T
42G N E T
43T A R N
44 
452140
46N S N T
47S E E E
48I D R P
49T C E J
50 
512151
52E T E T
53L E T E
54S A R H
55H A E D
56 
57Solved 100000 boards in 14.579000 seconds (6859.180791/s)

Test 2:

1C:\Games\boggle>boggle 500000
2Loading dictionary...OK
31281
4O N E W
5A E S D
6M R I T
7B P E D
8 
91385
10N R S O
11E A E H
12T D S T
13S S Q J
14 
151451
16U T E U
17S T R S
18L E E K
19A T O N
20 
211766
22L A M L
23E R E I
24B R T S
25O U E F
26 
271817
28E S E R
29Q L T S
30A A T C
31P R E L
32 
332016
34O S S N
35S E R G
36R E S O
37O T R M
38 
393411
40H A T E
41P T S R
42S E E C
43O R R R
44 
45Solved 500000 boards in 71.344002 seconds (7008.297651/s)

Matthew Leverton
Supreme Loser
January 1999
avatar

I think my C64 could solve faster than some of these computers... I'd have to rewrite the program first though to not use 100MB of RAM on the dictionary. 8-)

Quote:

I don't really feel like rebooting into windows.. But I could test on my Q6600 if you get source ;) using pthreads....

I'll release the source later after I clean it up a bit and add proper support for 'Q' since it's actually 'Qu'. Also right now the scores are erroneously high since I'm not checking for duplicates. The highest known computed score for a 4x4 using the Scrabble word list is around 2,500.

And yes, I am using pthreads to concurrently solve boards since they are all independent of each other.

Thomas Fjellstrom
Member #476
June 2000
avatar

I figured you'd have used Win32 threads since its a windows program.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

wiseguy
Member #44
April 2000
avatar

wow, 100 percent cpu usage and 70+ Mb of RAM used if you go with too many boards :)

but it's kinda cool

1Loading dictionary...OK
2145
3R D A W
4A Y H T
5U O F I
6O H N R
7 
8288
9O S R O
10L S E U
11T Z S A
12E Y S O
13 
141358
15R S L H
16N I E E
17S A T M
18A B S E
19 
201621
21M I S R
22V E R E
23S E F O
24S N R T
25 
261668
27T S V C
28E A N D
29S T E M
30E L A D
31 
32Solved 10000 boards in 2.469000 seconds (4050.222596/s)

1Loading dictionary...OK
2147
3S R H E
4F T X T
5P E B E
6W M A N
7 
8242
9T H T O
10U L R F
11S R I R
12G Y A H
13 
14323
15R T U A
16S O X T
17H G I V
18S T E N
19 
20380
21I E R D
22W T E N
23T F R J
24S S E W
25 
26429
27A B T R
28M E A L
29O N I H
30N O E Y
31 
32454
33H A N E
34O W A I
35D H E L
36U D S O
37 
38892
39H P L I
40T I E T
41T A R O
42N S U O
43 
441441
45O S E E
46A S R N
47T I O E
48L D T M
49 
501471
51N N E H
52G A E T
53T L T S
54D T E E
55 
562143
57G S S I
58N T R E
59I A O R
60P T O B
61 
622297
63I S T S
64S E E D
65B T S T
66U S A N
67 
682457
69E A O Q
70Y T R R
71S E A E
72S S D E
73 
742621
75N S O T
76T R E O
77E A R S
78T E T I
79 
80Solved 400000 boards in 103.921997 seconds (3849.040735/s)

I didn't try for 1,000,000... I have a 2.66 GHz celeron

OnlineCop
Member #7,919
October 2006
avatar

My question is, why is the time exponential O(n2) instead of linear O(n) or even O(n log n) ?

Are you re-checking things within a tight loop (like variable.size() inside of a for..loop)?

Thomas Fjellstrom
Member #476
June 2000
avatar

Quote:

My question is, why is the time exponential O(n2) instead of linear O(n) or even O(n log n) ?

Maybe the number of threads has something to do with it? Windows performs fairly badly when you start loading up on threads.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Matthew Leverton
Supreme Loser
January 1999
avatar

Quote:

My question is, why is the time exponential O(n2) instead of linear O(n) or even O(n log n) ?

Do you mean a single solution? Because the time per board has the same distribution whether you do 1000 or 1000000.

Solving a single solution takes roughly the same time, but it depends on the letters. A board of all Q's will be solved faster than one with good letters.

Quote:

wow, 100 percent cpu usage and 70+ Mb of RAM used if you go with too many boards :)

If I'm not using 100% then I'm not using enough!

It uses more threads depending on the number of boards to solve. If you do fewer than 1000, then it will run in a single thread. So if you only have on CPU/core that may give you best results.

I have a dual core system (AMD), but I get best results by running up to 8 threads at once. Obviously the most significant jump for me was from 1 to 2 threads. From 2 to 8 boosted me up to about 11K/s from 8K/s on 2 threads.

Same went for my Core 2 Duo laptop. But from some of the numbers here, it doesn't appear to be consistent across all computers. I assume none of the people were taxing their CPUs hard at the same time as running the solver...

GullRaDriel
Member #3,861
September 2003
avatar

1D:\Documents and Settings\Gull_Code\Bureau\boggle>boggle.exe 1000000
2Loading dictionary...OK
3741
4L I S E
5Q N A T
6H N L R
7T A S A
8 
91073
10D B H Y
11S E T C
12D O R A
13N P N R
14 
151539
16O S T E
17N T I R
18N O S E
19L O T E
20 
211546
22U Y S N
23I E E A
24R T S T
25O U E T
26 
271738
28T S S R
29E N E E
30E S C F
31A S N E
32 
331762
34S I S E
35R E H T
36P E E L
37O M A L
38 
392203
40N E R F
41D I S A
42T E T E
43B S E O
44 
452457
46R R T A
47S E E O
48S E N T
49N R A S
50 
512701
52S S E T
53R E T R
54T I E E
55S O L S
56 
57Solved 1000000 boards in 87.531998 seconds (11424.393667/s)

Edited: I was using some poor power management on my laptop.

BTW I have a Core 2 Duo @ 2 GHz with 2 GB of ram.

EDIT:

Quote:

Windows performs fairly badly when you start loading up on threads.

Do you have any proof of that ?

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

nonnus29
Member #2,606
August 2002
avatar

Solved 100000 boards in 7.234000 seconds (13823.610333/s)

Solved 500000 boards in 36.609001 seconds (13657.843267/s)

Core 2 Duo E6600. I want to see Thomas Q6600 result.

Edit:

Solved 1000000 boards in 71.359001 seconds (14013.649067/s)

Oooh, do I have the high score?!?!

I think this is the hardest workout this machine has had in the year I've had it... That's a shame...

Matthew Leverton
Supreme Loser
January 1999
avatar

For what it's worth, it works like this:

I load the dictionary as a tree. Each node is a letter with 26 children nodes. CAT, CARE, and CAREER would look like:

     Root
      |
      C
      | 
      A   
     / \
    T   R
    *   |
   CAT  E----E----R
        *         *
       CARE     CAREER

The dictionary is read only and shared among all the threads. Say we have a board like:

C E
A R

I set a node pointer to the dictionary root and check if n->c['c'] exists. It does, so I walk down to it. I check to see if the terminate node (*) exists. It doesn't, so C is not a word. I move to the right on the board, see an e, and therefore check for n->c['e']. It doesn't exist, so no words begin that that combo, and I go back up to the previous node and check the next available letter in the board.

I just use an iteration (no recursion) with a static stack of length rows * cols. If a word node is reached, then its pointer added to the static list of word pointers. This is to minimize any unnecessary string copies from the dictionary to the word list.

That is, once the dictionary is loaded and the board is created, memory is not created or destroyed or moved around.

So if your CPU can handle all of that, then you'll get a nice fast time.

The biggest optimization to my current approach would be to try to get stuff in memory stored in as optimal way as possible, but if anyone has any better algorithms than mine please share.

Timorg
Member #2,028
March 2002

Thats the kind of dictionary structure I used for an anagram finder.
I have attached my code if anyone is interested.

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

nonnus29
Member #2,606
August 2002
avatar

Quote:

but if anyone has any better algorithms than mine please share.

That sounds pretty optimal to me. I was thinking that your tree dictionary will probably give you good 'locality of reference' since the most common words in the english language use similar letters (ie will the most used parts of the dictionary stay in cache?). You're not allocating/freeing memory. Are there function calls? A lot of function calls?

I'm going to be pissed OFF if this is NOT written in D. >:(

ks
Member #1,086
March 2001

Perhaps the following link is of some value,

http://www.jsoftware.com/jwiki/Trash/Doc/Articles/Play181

Matthew Leverton
Supreme Loser
January 1999
avatar

I wrote it in D and then translated it to C. In a real world application, I would use D because I wouldn't need to solve billions of puzzles. But given I want to optimize it for speed, C is a better choice. This is the type of thing I'd write in C as a library and interface it with D or PHP, etc. [Or use D but write the code by managing my own memory.]

All memory allocation is done at initialization. The only function calls are like board_reset() and board_solve() which could really be optimized out. The algorithm itself is just a single for loop.

The D version was significantly slower because I made it more friendly to use. For instance, I had a pathfinder() function that could walk every possible path, taking a boolean delegate as a parameter that would determine whether or not to continue following each node.

So I could so stuff like:

1bool findWord(char[] word)
2{
3 bool found = false;
4 pathfinder(delegate(char[] path) {
5 // set found if path == word ;
6 // return false if the path is wrong or true if it could be right
7 });
8 
9 return found;
10}
11 
12char[][] solve()
13{
14 char[][] words;
15 
16 pathfinder(delegate(char[] path) {
17 if (dict.beginsWith(path))
18 {
19 if (dict.isWord(path)) words ~= path; // so slow!
20 return true;
21 }
22 else return false;
23 });
24 
25 return words;
26}

So it looks nice because you can easily share code, but really you're just wasting a lot of function calls. Obviously a similar thing could be done in C with function pointers, but I wanted to maximized speed.

Once I finish it in C, I'll translate it back D in the same form. But it won't really look like a D application. I mostly just want to test out how well the D compiler optimizes.

Oscar Giner
Member #2,207
April 2002
avatar

Solved 100000 boards in 5.328000 seconds (18768.768527/s)

Core 2 Duo E6750 at 3.2GHz

GullRaDriel
Member #3,861
September 2003
avatar

Quote:

Obviously a similar thing could be done in C with function pointers, but I wanted to maximized speed.

And how a call to a function pointer is different from a call to that function itself ?

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

Thomas Fjellstrom
Member #476
June 2000
avatar

Quote:

And how a call to a function pointer is different from a call to that function itself ?

The extra pointer indirection adds up if its done a lot.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

ImLeftFooted
Member #3,935
October 2003
avatar

Matthew said:

I mostly just want to test out how well the D compiler optimizes.

Any details (ie. numbers) on performance differences?

 1   2 


Go to: