summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJason Katz-Brown <jason@airbnb.com>2013-08-25 02:17:13 -0700
committerJason Katz-Brown <jason@airbnb.com>2013-08-25 02:17:13 -0700
commit9306cb60c32082c5403931de0823a9fd5daa196c (patch)
treeca1b6eb695fdf3f0c2294e92416b272164bae642 /test
parent8fb2c681cecc01b46b0f4ba02d5cc177c4747b1c (diff)
Initial git commit.
Diffstat (limited to 'test')
-rw-r--r--test/.gitignore7
-rw-r--r--test/positions/boys1.gcg28
-rw-r--r--test/positions/boys2.gcg31
-rw-r--r--test/positions/boys3.gcg30
-rw-r--r--test/positions/boys4.gcg28
-rw-r--r--test/positions/boys5.gcg28
-rw-r--r--test/positions/consonant_heaviness_tendency.gcg20
-rw-r--r--test/positions/deadwoodendgame.gcg26
-rw-r--r--test/positions/fivepoint.gcg32
-rw-r--r--test/positions/logan.gcg28
-rw-r--r--test/positions/logan_we.gcg25
-rw-r--r--test/positions/multiplayer-crash.gcg22
-rw-r--r--test/positions/one_tile_play.gcg5
-rw-r--r--test/positions/preendgame.gcg23
-rw-r--r--test/positions/preendgame2.gcg24
-rw-r--r--test/positions/preendgame4.gcg23
-rw-r--r--test/positions/short_game_with_bad_moves.gcg9
-rw-r--r--test/test.pro32
-rw-r--r--test/testharness.cpp796
-rw-r--r--test/testharness.h117
-rw-r--r--test/testmain.cpp39
-rw-r--r--test/trademarkedboards.cpp148
-rw-r--r--test/trademarkedboards.h40
23 files changed, 1561 insertions, 0 deletions
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 0000000..f42b7af
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+test
+obj
+Makefile.Debug
+Makefile.Release
+debug
+release
diff --git a/test/positions/boys1.gcg b/test/positions/boys1.gcg
new file mode 100644
index 0000000..2a6f8db
--- /dev/null
+++ b/test/positions/boys1.gcg
@@ -0,0 +1,28 @@
+#player1 Quackle Quackle Computer
+#player2 David David Boys
+#description Quackle Computer plays David Boys in Round 1 at the 2006 Human vs. Computer Showdown
+#title 2006 Human vs. Computer Showdown Round 1
+#incomplete
+>Quackle: DEMJNOT 8d JETON +40 40
+>David: ?EDYEIG h2 rEDYEING +64 64
+>Quackle: BEDGMNP 7e BEDIM +26 66 BE, ET, DO
+>David: HEALERS j1 HEALERS +75 139 BEDIMS
+>Quackle: DFGINPS k3 DIF +29 95 AD, LI, EF
+>David: COOAORS l1 COOS +28 167 ADO, LIS
+>Quackle: EGNOPRS m3 SPONGER +92 187 ADOS, LISP
+>David: AORWAVA 6c AVOW +37 204 OBE, WET
+>Quackle: AEFMOVZ 8l MEZE +54 241
+>David: AARTUNY d8 JAUNTY +32 236
+>Quackle: ACFIOOV 1l COOF +27 268
+>David: WALTIER 4c WAILED +20 256
+>Quackle: AACEINV 3a VIA +22 290 AW
+>David: IRUTRUT a3 VIRTU +9 265
+>Quackle: AACEHLN 8a EH +42 332 VIRTUE
+>David: QUBITUR 2b BRUIT +32 297 BI, RAW
+>Quackle: AACILNR 9m RAN +16 348 ZA, EN
+>David: PQUIEN? 13a QUEY +32 329
+>Quackle: CALLIER c13 EL +2 350
+>David: PINIR?N 1e PIN +11 340 PI, IT
+>Quackle: ACEILOR 15a CALORIE +83 433 ELL
+>David: TRAING? 14f TRAdING +67 407 TI, RE
+>David: (DATSXK) +36 443
diff --git a/test/positions/boys2.gcg b/test/positions/boys2.gcg
new file mode 100644
index 0000000..bbaa6f4
--- /dev/null
+++ b/test/positions/boys2.gcg
@@ -0,0 +1,31 @@
+#player1 David David Boys
+#player2 Quackle Quackle Computer
+#description David Boys plays Quackle Computer in Round 2 at the 2006 Human vs. Computer Showdown
+#title 2006 Human vs. Computer Showdown Round 2
+#incomplete
+>David: DOLTTPI 8g TOLD +10 10
+>Quackle: EEIMNOU 7h MEOU +17 17 MO, EL, OD
+>David: HAPITE? 9b PITHEAd +70 80 TA, MOd
+>Quackle: ADEINST l1 DETAINS +77 94 MEOUS
+>David: NONJEV? 5j JOIN +22 102
+>Quackle: ABFLNOW d7 BATFOWL +32 126
+>David: ENAIVE? e1 NAIVEtE +72 174 BE
+>Quackle: DEGNNRW 3c WRINGED +32 158
+>David: GREATQE n1 ERGATE +30 204 JOINT
+>Quackle: HIMNNOP 10d FOHN +39 197 HO, EH, TAN
+>David: QUISROA 1a QUOIN +45 249
+>Quackle: EIMNPTY 11a TEPOY +38 235 HOY
+>David: RASBEEE 1h BARED +24 273
+>Quackle: ADIMNOY b9 PYEMIA +42 277
+>David: EESSUIR o6 REISSUE +76 349 ER
+>Quackle: DINOORT 13l DOOR +18 295 REISSUER
+>David: IUAICLK a14 KI +24 373 KA
+>Quackle: FINSTVZ 12k ZIN +32 327 ID, NO
+>David: LACUIXA n13 OI +4 377
+>Quackle: CFLRSTV l11 VIDS +8 335
+>David: GLACUXA 5b CAGE +7 384
+>Quackle: CFLRT 1n EF +15 350
+>David: LUXA n8 XU +20 404 XI, US
+>Quackle: CLRT 14a KAT +7 357
+>David: LA 15n LA +9 413 OIL
+>David: (CLR) +10 423
diff --git a/test/positions/boys3.gcg b/test/positions/boys3.gcg
new file mode 100644
index 0000000..161ec1a
--- /dev/null
+++ b/test/positions/boys3.gcg
@@ -0,0 +1,30 @@
+#player1 Quackle Quackle Computer
+#player2 David David Boys
+#description Quackle Computer plays David Boys in Round 3 at the 2006 Human vs. Computer Showdown
+#title 2006 Human vs. Computer Showdown Round 3
+#incomplete
+>Quackle: EIIJNTW 8g JEW +26 26
+>David: AACEENS j4 ENCASE +28 28 JEWS
+>Quackle: EEIINTT k2 TINE +14 40 EN, NE
+>David: AYDDRLE l4 DEARY +37 65 END, NEE
+>Quackle: EINOPTY h8 EYEPOINT +92 132
+>David: HAHOLDS m8 AHOLDS +33 98 YA
+>Quackle: ADIMNRS n8 MAD +30 162 YAM, HA, OD
+>David: HARTOAG o9 OATH +21 119 HAO, ODA
+>Quackle: BEIINRS 15a BRINIEST +83 245
+>David: AOFRGAT 14f FANG +31 150 FE, AS
+>Quackle: CEGMNOQ b10 CONGER +30 275
+>David: ORATUSZ 11b OUZO +26 176
+>Quackle: IKMQTU? 13g KI +23 298 KAS
+>David: TRASBRD 12d ARB +34 210 ZA, OR
+>Quackle: EIMQTU? k9 MEsQUIT +88 386 EM
+>David: DTRSVEP i1 PERV +18 228 VEND
+>Quackle: AFLLORU h1 ORA +25 411 OP, RE, AR
+>David: TDSGIWE g1 WIG +26 254 WOP, IRE, GAR
+>Quackle: FLLRTUX 10f FUEL +15 426
+>David: EIODLST 6l ADO +6 260
+>Quackle: AILNRTX f2 TAR +16 442 TIRE, AGAR
+>David: ESTILVU 12m DUH +7 267
+>Quackle: LOXINI? 2k TOXIN +24 466
+>David: EEILSTV 5b EVILEST +74 341 TARE
+>David: (LI?) +4 345
diff --git a/test/positions/boys4.gcg b/test/positions/boys4.gcg
new file mode 100644
index 0000000..762fcdb
--- /dev/null
+++ b/test/positions/boys4.gcg
@@ -0,0 +1,28 @@
+#player1 David David Boys
+#player2 Quackle Quackle Computer
+#description David Boys plays Quackle Computer in Round 4 at the 2006 Human vs. Computer Showdown
+#title 2006 Human vs. Computer Showdown Round 4
+#incomplete
+>David: NRERXCL 8g REX +20 20
+>Quackle: ABDIOUW 7h BAUD +22 22 BE, AX
+>David: ACILNRV k3 VALID +18 38
+>Quackle: EILOSWT 5h LOWLIEST +61 83
+>David: CDNRRST -CDNRT +0 38
+>Quackle: AEFIMSZ o2 MESTIZA +57 140
+>David: SRYISER 9l RYES +30 68 MESTIZAS
+>Quackle: AEFINTU n1 TUFAS +31 171 UM, FE, AS
+>David: RISGNH? n8 HEaRSING +77 145 HA
+>Quackle: EIINORW l8 WRIER +24 195
+>David: EEOOUAB k10 OBOE +24 169 OI, BE, OR
+>Quackle: ECINOOP 15h COOPING +39 234
+>David: AEEUGNT 4d TEGUA +17 186 AL
+>Quackle: EOQTUV? h1 EQUAL +42 276
+>David: ENDNIRL l4 LIN +12 198 AL, IN
+>Quackle: CETOTV? 1a COrVETTE +98 374
+>David: ADEILNR e3 RENAILED +68 266
+>Quackle: AAHIJRM d9 HIJRA +38 412 HE, ID
+>David: DPFKNTY 13c FAD +14 280
+>Quackle: ADEEMNO 11k BEER +6 418
+>David: KYNAPOT 6b TOKAY +22 302
+>Quackle: ADEGMNO b3 MONTAGED +66 484
+>Quackle: (PAIN) +12 496
diff --git a/test/positions/boys5.gcg b/test/positions/boys5.gcg
new file mode 100644
index 0000000..3c56f99
--- /dev/null
+++ b/test/positions/boys5.gcg
@@ -0,0 +1,28 @@
+#player1 Quackle Quackle Computer
+#player2 David David Boys
+#description Quackle Computer plays David Boys in Round 5 at the 2006 Human vs. Computer Showdown
+#title 2006 Human vs. Computer Showdown Round 5
+#incomplete
+>Quackle: HERMINE 8d HEMIN +28 28
+>David: EIPORTU h1 ERUPTION +89 89
+>Quackle: EIKRTT? i8 sKITTER +76 104 HEMINs
+>David: ADEFIUX 11e FIXATED +72 161
+>Quackle: EEDGHS? 15c HEDGErS +97 201 sKITTERS
+>David: AELRRUY 4h PURELY +22 183
+>Quackle: AFLMNNV 10g ALIF +39 240 AX, LA, FE
+>David: ABIPRWW 3k WAB +37 220 WE, AL, BY
+>Quackle: AJMNNOV 2f JORAM +36 276
+>David: ILNPRSW e5 WIPER +20 240
+>Quackle: CDGNNOV f10 CION +28 304 CALIF
+>David: BELNOSY 14b YOB +25 265 OH, BE
+>Quackle: ADEGNTV 6b DEVIATING +74 378
+>David: AEILNRS b1 ISLANDER +68 333
+>Quackle: AADINRU 1j ANURIA +25 403 AM
+>David: GNOSUVZ 1a GINZO +75 408
+>Quackle: DEIIOST 3b LOTI +8 411
+>David: LOOSTUV 13a LOO +23 431 OY, OOH
+>Quackle: CDEEIQS 4a QADI +55 466 OD, TI
+>David: AESTUV a8 AVE +24 455 AR
+>Quackle: CEES 5l SEC +16 482 ALS, BYE
+>David: STU n5 CUTS +8 463
+>David: (E) +2 465
diff --git a/test/positions/consonant_heaviness_tendency.gcg b/test/positions/consonant_heaviness_tendency.gcg
new file mode 100644
index 0000000..cb2156a
--- /dev/null
+++ b/test/positions/consonant_heaviness_tendency.gcg
@@ -0,0 +1,20 @@
+#player1 NoName New Player 2
+#player2 NoName jasonkb
+>NoName: ABELNUW 8D BLAWN +26 26
+>NoName: ADRSTYZ F8 ADZ +33 33
+>NoName: EEFGRTU 11E REFUGE +34 60
+>NoName: AEERSTY K10 YE +32 65
+>NoName: AEELQTT 9I QAT +28 88
+>NoName: AEERSTW 10J WYE +31 96
+>NoName: EEIILOT 9D EIDE +18 106
+>NoName: AEEGRST M8 RESTAGE +78 174
+>NoName: ILNNOST 14H INSOLENT +70 176
+>NoName: ?CDEIMS 15C MISCoDE +97 271
+>NoName: EHILRUX 12L EAUX +38 214
+>NoName: AGKNOPU 8L GROK +33 304
+>NoName: CEHILRV 13B CHERVIL +86 300
+>NoName: AHJNPSU 10B JUN +31 335
+>NoName: ADFIINO 15K FIDO +29 329
+>NoName: AHMNPST 12C AM +21 356
+>NoName: AINORRY L2 ROARING +16 345
+#rack2 BHNPRST
diff --git a/test/positions/deadwoodendgame.gcg b/test/positions/deadwoodendgame.gcg
new file mode 100644
index 0000000..fb87f03
--- /dev/null
+++ b/test/positions/deadwoodendgame.gcg
@@ -0,0 +1,26 @@
+#player1 jasonkb jasonkb
+#player2 MartyGabriel Marty Gabriel
+>jasonkb: DHNNSTW -HWND +0 0
+>MartyGabriel: DFINU 8D FUNDI +26 26
+>jasonkb: HKNNSTW E6 TH.NKS +26 26
+>MartyGabriel: EX 7G EX +23 49
+>jasonkb: AAGNOUW 10B WAU. +19 45
+>MartyGabriel: BENORT 6B BET.OR +20 69
+>jasonkb: AGINOPW A5 WAGON +36 81
+>MartyGabriel: DHNY C9 H.NDY +32 101
+>jasonkb: ABEIIPQ 12A QA.I +48 129
+>MartyGabriel: CIORZ C2 COZI.R +36 137
+>jasonkb: BEEILPU A11 E.UIP +48 177
+>MartyGabriel: ?AEEMRR 15A .AMpERER +83 220
+>jasonkb: BDDEELV 5G BEVEL +27 204
+>MartyGabriel: AAEERTU K5 .AUREATE +66 286
+>jasonkb: DDIILRS L10 DID +21 225
+>MartyGabriel: FO J9 OF +30 316
+>jasonkb: AILORST M5 RIALTOS +70 295
+>MartyGabriel: AEIISTV 2C .AVITIES +67 383
+>jasonkb: EEGGINS 8M .EG +12 307
+>MartyGabriel: MOO 1H MOO +31 414
+>jasonkb: ?EGINPS 14H ESPyING +82 389
+>MartyGabriel: ACLNOTY 4C .ANY +32 446
+>jasonkb: JL 9I J.. +18 407
+#rack2 CLOT
diff --git a/test/positions/fivepoint.gcg b/test/positions/fivepoint.gcg
new file mode 100644
index 0000000..c9a0261
--- /dev/null
+++ b/test/positions/fivepoint.gcg
@@ -0,0 +1,32 @@
+#player1 Ganesh Ganesh Asirvatham
+#player2 Paul Paul Cleary
+#description Ganesh Asirvatham plays Paul Cleary in Round 11 at the 2005 WSC
+#title 2005 WSC Round 11
+#incomplete
+>Ganesh: AOXJGWS 8g JAW +26 26
+>Paul: IEEKBNL h6 BEANLIKE +69 69
+>Paul: ARTEQ?G (challenge) +5 74
+>Ganesh: OXGSHYD i12 OXY +44 70 KO, EX
+>Paul: ARTEQ?G 11g QI +11 85
+>Ganesh: GSHDINV 13g VEXINGS +44 114
+>Paul: ARTE?GN j2 GARNETs +76 161 JAWs
+>Ganesh: DRRHYME 4h MYRRH +32 146
+>Paul: AZEARIH 10h LAZIER +35 196
+>Ganesh: DERESIU m2 RESIDUE +82 228 MYRRHS
+>Paul: HAIUUTE 8l HEAT +33 229
+>Ganesh: ADOEASI 11j ODA +27 255 ZO, ID, EA
+>Paul: UUIECEL 3f ECU +12 241 UM
+>Ganesh: EASIDTR o1 TARDIEST +83 338
+>Paul: LIEUIWP 2c PLEW +30 271 WE
+>Ganesh: BNCOAAE 1e BEANO +31 369 BE, EWE
+>Paul: IIUPLFT c1 UPLIFT +22 293
+>Ganesh: ACEGOOR 9e COON +17 386 JO
+>Paul: USIEOPI 1a PIU +15 308
+>Ganesh: AADEGIR 5b AFRAID +20 406
+>Paul: IEOUSNV l13 GUV +11 319
+>Ganesh: EFGMOTT e9 COFT +18 424
+>Paul: IEOSNNL d10 NOEL +19 338 NO, OF, ET
+>Ganesh: ?EGMOT c11 OMEGa +29 453 OOF, MET, EL
+>Paul: ISN 15l VINS +21 359
+>Paul: (T) +1 360
+>Ganesh: T (T) -1 452
diff --git a/test/positions/logan.gcg b/test/positions/logan.gcg
new file mode 100644
index 0000000..b60f96f
--- /dev/null
+++ b/test/positions/logan.gcg
@@ -0,0 +1,28 @@
+#player1 Maven Maven
+#player2 AdamLogan Adam Logan
+#title 1998 Exhibition Game
+#description Maven plays Adam Logan in an exhibition game in 1998. This game was featured as the Annotated Game in the Scrabble News issue 144.
+>Maven: ACNTVYZ 8F CAVY +24 24
+>AdamLogan: EGLNORY G6 YEARLONG +66 66
+>Maven: ADNNOTZ 6D DOZY +37 61
+>AdamLogan: ADEFOTV H13 OFT +21 87
+>Maven: AENNNOT 5B NEON +15 76
+>AdamLogan: ACDEEIV 12B DEVIANCE +96 183
+>Maven: AHINRTU 4A HURT +34 110
+>AdamLogan: DDEEMMN C7 EMENDED +26 209
+>Maven: ABEINNP 8A IAMB +33 143
+>AdamLogan: AILMTTU A1 MATH +27 236
+>Maven: EFGNNPS E10 FEIGN +18 161
+>AdamLogan: AILORTU 15H TUTORIAL +77 313
+>Maven: ABNOPS? J10 BOS +26 187
+>AdamLogan: IILPRSU 15A PILIS +34 347
+>Maven: AKNPRS? K5 SPANKeR +105 292
+>AdamLogan: EEEORSU B1 OE +12 359
+>Maven: HJTTWW? 7J JAW +13 305
+>AdamLogan: AEEGRSU M3 GREASE +31 390
+>Maven: HRTTWX? 6M AX +25 330
+>AdamLogan: EIIILQU O5 LEI +13 403
+>Maven: AHRTTW? 9B WE +10 340
+>AdamLogan: AIIIOQU J2 QUAI +35 438
+>Maven: AHRTTU? 1A MOUTHpART +92 432
+>Maven: (EIIO) +8 440
diff --git a/test/positions/logan_we.gcg b/test/positions/logan_we.gcg
new file mode 100644
index 0000000..bb704dd
--- /dev/null
+++ b/test/positions/logan_we.gcg
@@ -0,0 +1,25 @@
+#player1 Maven Maven
+#player2 AdamLogan Adam Logan
+#title 1998 Exhibition Game
+#description Maven plays Adam Logan in an exhibition game in 1998. This game was featured as the Annotated Game in the Scrabble News issue 144.
+>Maven: ACNTVYZ 8F CAVY +24 24
+>AdamLogan: EGLNORY G6 YE.RLONG +66 66
+>Maven: ADNNOTZ 6D DOZ. +37 61
+>AdamLogan: ADEFOTV H13 OFT +21 87
+>Maven: AENNNOT 5B NEON +15 76
+>AdamLogan: ACDEEIV 12B DEVIA.CE +96 183
+>Maven: AHINRTU 4A HURT +34 110
+>AdamLogan: DDEEMMN C7 EMEND.D +26 209
+>Maven: ABEINNP 8A IA.B +33 143
+>AdamLogan: AILMTTU A1 MAT. +27 236
+>Maven: EFGNNPS E10 FE.GN +18 161
+>AdamLogan: AILORTU 15H .UTORIAL +77 313
+>Maven: ?ABNOPS J10 BOS +26 187
+>AdamLogan: IILPRSU 15A PILIS +34 347
+>Maven: ?AKNPRS K5 SPANKeR +105 292
+>AdamLogan: EEEORSU B1 OE +12 359
+>Maven: ?HJTTWW 7J J.W +13 305
+>AdamLogan: AEEGRSU M3 GREASE +31 390
+>Maven: ?HRTTWX 6M .X +25 330
+>AdamLogan: EIIILQU O5 LEI +13 403
+#rack1 ?AHRTTW
diff --git a/test/positions/multiplayer-crash.gcg b/test/positions/multiplayer-crash.gcg
new file mode 100644
index 0000000..a3bdb45
--- /dev/null
+++ b/test/positions/multiplayer-crash.gcg
@@ -0,0 +1,22 @@
+#player1 Mark_Ogden Mark Ogden
+#player2 Chappy Chappy
+#player3 Nicole_Gorham Nicole Gorham
+#player4 Daniel_Southam Daniel Southam
+>Mark_Ogden: BCEIP 8F BICEP +22 22
+>Chappy: JLOORSU F6 JO. +28 28
+>Nicole_Gorham: BCDEITZ G7 F.Z +38 38
+>Daniel_Southam: EIORRTV J6 RA.INE +12 12
+>Mark_Ogden: EIMNRSU K2 GAWKER +32 54
+>Chappy: LNORSUY 12J SOURLY +35 63
+>Nicole_Gorham: ?DIMMOV 11D MIsMOV.D +116 154
+>Daniel_Southam: ADEILR O6 READIL. +33 45
+>Mark_Ogden: DIINQSU 9I X. +34 88
+>Chappy: CENOPRU N1 POUNCER +82 145
+>Nicole_Gorham: AFIOTTY O1 ANTE +34 188
+>Daniel_Southam: AEEEIOV 12C QAT +34 79
+>Mark_Ogden: EHOT N10 HE.OT +47 135
+>Chappy: AABEENT L4 EAVE +39 184
+>Nicole_Gorham: AFIOTWY 13B NIT +33 221
+>Daniel_Southam: AEEEILO 14D SEISING +70 149
+>Mark_Ogden: DFI 15F FID +37 172
+#rack2 AABLLNS
diff --git a/test/positions/one_tile_play.gcg b/test/positions/one_tile_play.gcg
new file mode 100644
index 0000000..a4b19c6
--- /dev/null
+++ b/test/positions/one_tile_play.gcg
@@ -0,0 +1,5 @@
+#player1 jasonkb jasonkb
+#player2 bricap bricap
+>jasonkb: EHY 8F HEY +18 18
+>bricap: AEZ F8 HAZE +36 36
+#rack1 GNX
diff --git a/test/positions/preendgame.gcg b/test/positions/preendgame.gcg
new file mode 100644
index 0000000..209feae
--- /dev/null
+++ b/test/positions/preendgame.gcg
@@ -0,0 +1,23 @@
+#player1 jasonkb jasonkb
+#player2 MartyGabriel Marty Gabriel
+>jasonkb: DHNNSTW -HWND +0 0
+>MartyGabriel: DFINU 8D FUNDI +26 26
+>jasonkb: HKNNSTW E6 THUNKS +26 26
+>MartyGabriel: EX 7G EX +23 49
+>jasonkb: AAGNOUW 10B WAUK +19 45
+>MartyGabriel: BENORT 6B BETTOR +20 69
+>jasonkb: AGINOPW A5 WAGON +36 81
+>MartyGabriel: DHNY C9 HANDY +32 101
+>jasonkb: ABEIIPQ 12A QADI +48 129
+>MartyGabriel: CIORZ C2 COZIER +36 137
+>jasonkb: BEEILPU A11 EQUIP +48 177
+>MartyGabriel: ?AEEMRR 15A PAMpERER +83 220
+>jasonkb: BDDEELV 5G BEVEL +27 204
+>MartyGabriel: AAEERTU K5 LAUREATE +66 286
+>jasonkb: DDIILRS L10 DID +21 225
+>MartyGabriel: FO J9 OF +30 316
+>jasonkb: AILORST M5 RIALTOS +70 295
+>MartyGabriel: AEIISTV 2C CAVITIES +67 383
+>jasonkb: EEGGINS 8M LEG +12 307
+>MartyGabriel: MOO 1H MOO +31 414
+#rack1 ?EGINPS
diff --git a/test/positions/preendgame2.gcg b/test/positions/preendgame2.gcg
new file mode 100644
index 0000000..66ca1fe
--- /dev/null
+++ b/test/positions/preendgame2.gcg
@@ -0,0 +1,24 @@
+#player1 jasonkb jasonkb
+#player2 MartyGabriel Marty Gabriel
+>jasonkb: DHNNSTW -HWND +0 0
+>MartyGabriel: DFINU 8D FUNDI +26 26
+>jasonkb: HKNNSTW E6 THUNKS +26 26
+>MartyGabriel: EX 7G EX +23 49
+>jasonkb: AAGNOUW 10B WAUK +19 45
+>MartyGabriel: BENORT 6B BETTOR +20 69
+>jasonkb: AGINOPW A5 WAGON +36 81
+>MartyGabriel: DHNY C9 HANDY +32 101
+>jasonkb: ABEIIPQ 12A QADI +48 129
+>MartyGabriel: CIORZ C2 COZIER +36 137
+>jasonkb: BEEILPU A11 EQUIP +48 177
+>MartyGabriel: ?AEEMRR 15A PAMpERER +83 220
+>jasonkb: BDDEELV 5G BEVEL +27 204
+>MartyGabriel: AAEERTU K5 LAUREATE +66 286
+>jasonkb: DDIILRS L10 DID +21 225
+>MartyGabriel: FO J9 OF +30 316
+>jasonkb: AILORST M5 RIALTOS +70 295
+>MartyGabriel: AEIISTV 2C CAVITIES +67 383
+>jasonkb: EEGGINS 8M LEG +12 307
+>MartyGabriel: MOO 1H MOO +31 414
+>jasonkb: ?EGINPS 5G BEVELER +12 319
+#rack2 ACLLNOT
diff --git a/test/positions/preendgame4.gcg b/test/positions/preendgame4.gcg
new file mode 100644
index 0000000..02914b2
--- /dev/null
+++ b/test/positions/preendgame4.gcg
@@ -0,0 +1,23 @@
+#player1 JasonKatz-Brown Jason Katz-Brown
+#player2 compy compy
+>JasonKatz-Brown: DEILRTY 8F TIREDLY +80 80
+>compy: AGHKTTU L4 GUTTY +18 18
+>JasonKatz-Brown: DFLNOOR 5G ODORFUL +22 102
+>compy: AHKSSUW 7G HAW +37 55
+>JasonKatz-Brown: ?BEHINR 4C BIRcHEN +85 187
+>compy: EIKSSUZ H1 SIZED +45 100
+>JasonKatz-Brown: ABEESTV E3 BRAVE +20 207
+>compy: ADEKMSU 9G MED +34 134
+>JasonKatz-Brown: EFJOPST C3 OBJET +30 237
+>compy: ADKOOSU 8A DUSK +57 191
+>JasonKatz-Brown: AFGPQRS 2F FRIG +16 253
+>compy: AAELMOO M2 MOOLA +19 210
+>JasonKatz-Brown: AINOPQS N1 QI +30 283
+>compy: AAEILRX O1 ILEX +95 305
+>JasonKatz-Brown: ALNOPRS N6 PROLANS +78 361
+>compy: AAEPRUV O8 PARA +36 341
+>JasonKatz-Brown: CEEINNO 1A CONINE +32 393
+>compy: EOSTTUV 12J VOTES +16 357
+>JasonKatz-Brown: AAEINUW D8 KNAWE +24 417
+>compy: CGNSTUY J12 VUG +11 368
+#rack1 ?AAEIIU
diff --git a/test/positions/short_game_with_bad_moves.gcg b/test/positions/short_game_with_bad_moves.gcg
new file mode 100644
index 0000000..f7ea011
--- /dev/null
+++ b/test/positions/short_game_with_bad_moves.gcg
@@ -0,0 +1,9 @@
+#player1 jasonkb jasonkb
+#player2 bricap bricap
+>jasonkb: IIJOOPS 8G SI +4 4
+>bricap: AACIMOQ 7H QI +23 23
+>jasonkb: IJOOOPT G8 .IP +6 10
+>bricap: ?AACCMO 11A MACACOs +79 102
+>jasonkb: ?DJOOOT B10 J.TO +27 37
+>bricap: AAOOSUU 14B SOU +30 132
+#rack1 ?DELOOW
diff --git a/test/test.pro b/test/test.pro
new file mode 100644
index 0000000..e0a0b77
--- /dev/null
+++ b/test/test.pro
@@ -0,0 +1,32 @@
+TEMPLATE = app
+DEPENDPATH += .. ../quackleio
+INCLUDEPATH += . ..
+
+# enable/disable debug symbols
+# CONFIG += debug
+
+CONFIG += console
+CONFIG -= x11
+CONFIG += release
+
+build_pass:CONFIG(debug, debug|release) {
+ LIBS += -L../debug -L../quackleio/debug
+}
+
+build_pass:CONFIG(release, debug|release) {
+ LIBS += -L../release -L../quackleio/release
+}
+
+LIBS += -L.. -L../quackleio -lquackle -lquackleio
+
+# Input
+HEADERS += testharness.h trademarkedboards.h
+SOURCES += testharness.cpp testmain.cpp trademarkedboards.cpp
+
+
+win32:!win32-g++ {
+ QMAKE_CFLAGS_DEBUG ~= s/-MDd/-MTd/
+ QMAKE_CXXFLAGS_DEBUG ~= s/-MDd/-MTd/
+ QMAKE_CFLAGS_RELEASE ~= s/-MD/-MT/
+ QMAKE_CXXFLAGS_RELEASE ~= s/-MD/-MT/
+}
diff --git a/test/testharness.cpp b/test/testharness.cpp
new file mode 100644
index 0000000..6febbb9
--- /dev/null
+++ b/test/testharness.cpp
@@ -0,0 +1,796 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <QtCore>
+
+#include <iostream>
+#include <limits>
+#include <algorithm>
+
+#include <bogowinplayer.h>
+#include <computerplayercollection.h>
+#include <resolvent.h>
+#include <datamanager.h>
+#include <endgameplayer.h>
+#include <game.h>
+#include <gameparameters.h>
+#include <lexiconparameters.h>
+#include <strategyparameters.h>
+#include <enumerator.h>
+#include <reporter.h>
+
+#include <quackleio/dictimplementation.h>
+#include <quackleio/flexiblealphabet.h>
+#include <quackleio/froggetopt.h>
+#include <quackleio/gcgio.h>
+#include <quackleio/util.h>
+
+#include "trademarkedboards.h"
+#include "testharness.h"
+
+using namespace Quackle;
+
+TestHarness::TestHarness()
+ : m_computerPlayerToTest(0), m_quiet(false)
+{
+ m_gamesDir = "games";
+ m_dataManager.setComputerPlayers(Quackle::ComputerPlayerCollection::fullCollection());
+}
+
+TestHarness::~TestHarness()
+{
+}
+
+const char *usage =
+"Optional arguments:\n"
+"--computer=; sets the computer player (default 'Speedy Player').\n"
+"--mode=\n"
+" 'positions' (default) runs computer player all positions.\n"
+" 'report' asks computer player for report on all positions.\n"
+" 'htmlreport' asks for html report on all positions.\n"
+" 'selfplay' runs 1000 selfplay games.\n"
+" 'playability' output info for computing playability values.\n"
+" 'enumerate' lists all racks.\n"
+" 'staticleaves' output static leave values of racks in 'racks' file.\n"
+" 'randomracks' spit out random racks (forever?).\n"
+" 'leavecalc' spit out roughish values of leaves in 'leaves' file.\n"
+" 'anagram' anagrams letters supplied in --letters.\n"
+"--position=game.gcg; this option can be repeated to specify positions\n"
+" to test.\n"
+"--lexicon=; sets the lexicon (default 'twl06').\n"
+"--alphabet=; sets the alphabet (default 'english').\n"
+"--seed=integer; set the random seed for reproducability.\n"
+"--report; generate reports for selfplay games (default false).\n"
+"--letters; letters to anagram.\n"
+"--build; when mode is anagram, do not require that all letters be used.\n"
+"--quiet; print nothing during selfplay games (default false).\n"
+"--repetitions=integer; the number of games for selfplay (default 1000).\n";
+
+void TestHarness::executeFromArguments()
+{
+ GetOpt opts;
+
+ QString mode;
+ QString computer;
+ QString seedString;
+ QString repString;
+ bool build;
+ QString letters;
+ bool help;
+ bool report;
+ unsigned int seed = numeric_limits<unsigned int>::max();
+ unsigned int reps = 1000;
+
+ opts.addOption('c', "computer", &computer);
+ opts.addOption('a', "alphabet", &m_alphabet);
+ opts.addOption('l', "lexicon", &m_lexicon);
+ opts.addOption('m', "mode", &mode);
+ opts.addOption('s', "seed", &seedString);
+ opts.addOption('r', "repetitions", &repString);
+ opts.addOption('t', "letters", &letters);
+ opts.addRepeatableOption("position", &m_positions);
+
+ opts.addSwitch("report", &report);
+ opts.addSwitch("build", &build);
+ opts.addSwitch("quiet", &m_quiet);
+ opts.addSwitch("help", &help);
+
+ if (!opts.parse())
+ return;
+
+ if (help)
+ {
+ UVcout << usage << endl;
+ return;
+ }
+
+ if (mode.isNull())
+ mode = "positions";
+ if (computer.isNull())
+ computer = "Speedy Player";
+ if (m_lexicon.isNull())
+ m_lexicon = "twl06";
+ if (m_alphabet.isNull())
+ m_alphabet = "english";
+ if (!seedString.isNull())
+ seed = seedString.toUInt();
+ if (!repString.isNull())
+ reps = repString.toUInt();
+
+
+ bool playerFound = false;
+ const Quackle::Player &player = QUACKLE_COMPUTER_PLAYERS.playerForName(QuackleIO::Util::qstringToString(computer), playerFound);
+ if (playerFound)
+ {
+ m_computerPlayerToTest = player.computerPlayer();
+ }
+ else
+ {
+ UVcout << "Computer " << QuackleIO::Util::qstringToString(computer) << " not found!" << endl;
+ return;
+ }
+
+ startUp();
+
+ if (mode == "positions")
+ testPositions();
+ else if (mode == "report")
+ testReport(false);
+ else if (mode == "htmlreport")
+ testReport(true);
+ else if (mode == "enumerate")
+ enumerateAll();
+ else if (mode == "staticleaves")
+ staticLeaves(QString("racks"));
+ else if (mode == "randomracks")
+ randomRacks();
+ else if (mode == "leavecalc")
+ leaveCalc(QString("leaves"));
+ else if (mode == "anagram")
+ anagram(letters, build);
+ else if (mode == "selfplay")
+ selfPlayGames(seed, reps, report, false);
+ else if (mode == "playability")
+ selfPlayGames(seed, reps, report, true);
+ else if (mode == "worddump")
+ wordDump();
+ else if (mode == "bingos")
+ bingos();
+}
+
+void TestHarness::startUp()
+{
+ UVcout << "Starting up.";
+
+ m_dataManager.setBackupLexicon("twl06");
+ m_dataManager.setDataDirectory("../data");
+
+ QString alphabetFile = QuackleIO::Util::stdStringToQString(Quackle::AlphabetParameters::findAlphabetFile(QuackleIO::Util::qstringToStdString(m_alphabet) + ".quackle_alphabet"));
+ QuackleIO::FlexibleAlphabetParameters *flexure = new QuackleIO::FlexibleAlphabetParameters;
+ if (flexure->load(alphabetFile))
+ {
+ m_dataManager.setAlphabetParameters(flexure);
+ }
+ else
+ {
+ UVcerr << "Couldn't load alphabet " << QuackleIO::Util::qstringToString(m_alphabet) << endl;
+ delete flexure;
+ }
+
+ m_dataManager.setBoardParameters(new ScrabbleBoard());
+
+ m_dataManager.lexiconParameters()->loadGaddag(Quackle::LexiconParameters::findDictionaryFile(QuackleIO::Util::qstringToStdString(m_lexicon + ".gaddag")));
+ UVcout << ".";
+
+ m_dataManager.lexiconParameters()->loadDawg(Quackle::LexiconParameters::findDictionaryFile(QuackleIO::Util::qstringToStdString(m_lexicon + ".dawg")));
+
+ m_dataManager.strategyParameters()->initialize(QuackleIO::Util::qstringToStdString(m_lexicon));
+ UVcout << ".";
+
+ UVcout << endl;
+
+ m_gamesDir = QString("games_PLAYERNAME_%1").arg(QDateTime::currentDateTime().toString("dd.MM_hh.mm.ss"));
+}
+
+void TestHarness::testFromFile(const QString &file)
+{
+ UVcout << "Testing game from " << QuackleIO::Util::qstringToString(file) << endl;
+ Quackle::Game *game = createNewGame(file);
+ if (game)
+ {
+ testPosition(game->currentPosition(), computerPlayerToTest());
+ }
+
+ delete game;
+}
+
+double TestHarness::leaveSim(const Rack &R, int iterations)
+{
+ double sum = 0.0;
+
+ UVcout << R << endl;
+ Bag B;
+ B.removeLetters(R.tiles());
+
+ int tilesToLeave = 14 + rand() % (93 - 14);
+
+ for (int i = 0; i < iterations; i++)
+ {
+ Quackle::Game game;
+
+ Quackle::PlayerList players;
+
+ Quackle::Player compyA(m_computerPlayerToTest->name() + MARK_UV(" A"), Quackle::Player::ComputerPlayerType, 0);
+ compyA.setAbbreviatedName(MARK_UV("A"));
+ compyA.setComputerPlayer(new Quackle::StaticPlayer());
+ players.push_back(compyA);
+
+ Quackle::Player compyB(m_computerPlayerToTest->name() + MARK_UV(" B"), Quackle::Player::ComputerPlayerType, 1);
+ compyB.setAbbreviatedName(MARK_UV("B"));
+ compyB.setComputerPlayer(new Quackle::StaticPlayer());
+ players.push_back(compyB);
+
+ game.setPlayers(players);
+ game.associateKnownComputerPlayers();
+
+ game.addPosition();
+
+ game.currentPosition().setCurrentPlayerRack(Rack(""), true);
+ game.currentPosition().setOppRack(Rack(""), true);
+
+ Bag startBag = B;
+ game.currentPosition().setBag(startBag);
+
+ game.addPosition();
+
+ UVcout << "NEW GAME" << endl;
+
+ while (game.currentPosition().bag().size() > tilesToLeave)
+ {
+ if (game.currentPosition().gameOver())
+ {
+ UVcout << "GAME OVER" << endl;
+ break;
+ }
+
+ const Quackle::Player player(game.currentPosition().currentPlayer());
+ Quackle::Move compMove(game.haveComputerPlay());
+ UVcout << "with " << player.rack() << ", " << player.name() << " commits to " << compMove << endl;
+ }
+
+ game.currentPosition().setCurrentPlayerRack(R, true);
+ Quackle::Move compMove(game.haveComputerPlay());
+ sum += compMove.equity;
+ }
+
+ return sum / iterations;
+}
+
+void TestHarness::leaveCalc(const QString &filename)
+{
+ QuackleIO::GCGIO io;
+ QFile file(filename);
+
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ {
+ UVcout << "Could not open file " << QuackleIO::Util::qstringToString(filename) << endl;
+ return;
+ }
+
+ QTextStream in(&file);
+
+ const int iterations = 10;
+
+ while (!in.atEnd())
+ {
+ QString line = in.readLine();
+ Rack rack(QuackleIO::Util::encode(line));
+ double value = leaveSim(rack, iterations);
+ UVcout << "leavecalc: " << rack << " " << value << endl;
+ }
+
+ file.close();
+
+}
+
+void TestHarness::randomRacks()
+{
+ for (;;)
+ {
+ Game game;
+
+ Quackle::PlayerList players;
+
+ Player compyA(m_computerPlayerToTest->name() + MARK_UV(" A"), Quackle::Player::ComputerPlayerType, 0);
+ compyA.setAbbreviatedName(MARK_UV("A"));
+ compyA.setComputerPlayer(m_computerPlayerToTest);
+ players.push_back(compyA);
+
+ game.setPlayers(players);
+
+ game.addPosition();
+
+ UVcout << game.currentPosition().currentPlayer().rack() << endl;
+ }
+}
+
+void TestHarness::staticLeaves(const QString &filename)
+{
+ QuackleIO::GCGIO io;
+ QFile file(filename);
+
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ {
+ UVcout << "Could not open file " << QuackleIO::Util::qstringToString(filename) << endl;
+ return;
+ }
+
+ QTextStream in(&file);
+
+ Quackle::Game game;
+
+ Quackle::PlayerList players;
+
+ Quackle::Player compyA(m_computerPlayerToTest->name() + MARK_UV(" A"), Quackle::Player::ComputerPlayerType, 0);
+ compyA.setAbbreviatedName(MARK_UV("A"));
+ compyA.setComputerPlayer(m_computerPlayerToTest);
+ players.push_back(compyA);
+
+ Quackle::Player compyB(m_computerPlayerToTest->name() + MARK_UV(" B"), Quackle::Player::ComputerPlayerType, 1);
+ compyB.setAbbreviatedName(MARK_UV("B"));
+ compyB.setComputerPlayer(m_computerPlayerToTest);
+ players.push_back(compyB);
+
+ game.setPlayers(players);
+ game.associateKnownComputerPlayers();
+
+ game.addPosition();
+
+ while (!in.atEnd())
+ {
+ QString line = in.readLine();
+ Rack rack(QuackleIO::Util::encode(line));
+ game.currentPosition().setCurrentPlayerRack(rack);
+ Move move = game.currentPosition().staticBestMove();
+ //Move scoredExch = game.currentPosition().scoreMove(exchZero);
+ //UVcout << rack << " " << scoredExch << endl;
+ UVcout << rack << " " << move << endl;
+ }
+
+ file.close();
+}
+
+void TestHarness::enumerateAll()
+{
+ Quackle::Bag B;
+ Enumerator E(B);
+ ProbableRackList racks;
+ E.enumerate(&racks);
+ for (ProbableRackList::iterator it = racks.begin(); it != racks.end(); ++it)
+ UVcout << (*it).rack << " " << (*it).probability << endl;
+}
+
+struct PowerRack
+{
+ PowerRack(ProbableRack &r) : rack(r.rack),
+ stemProbability(r.probability),
+ usableTiles(0),
+ power(0) {}
+
+ Rack rack;
+ double stemProbability; /* MSP */
+ int usableTiles; /* UT */
+ double power; /* MMPR */
+};
+
+typedef vector<PowerRack> PowerRackList;
+
+static bool powerSort(const PowerRack& r1,
+ const PowerRack& r2)
+{
+ return r1.power > r2.power;
+}
+
+// Looks for a single letter that acts to pluralize words based on the assumption
+// that it will make a very common last letter in the lexicon.
+static Letter findPluarlizer()
+{
+ // generate all the words in the lexicon
+ Generator gen;
+ int flags = Generator::AnagramRearrange | Generator::AddAnyLetters
+ | Generator::ClearBlanknesses;
+ WordList all = gen.anagramLetters("", flags);
+
+ // count the frequency of occurrence of the final letter
+ const int allLetters = QUACKLE_FIRST_LETTER + QUACKLE_MAXIMUM_ALPHABET_SIZE;
+ int endCounts[allLetters];
+ for (int j = 0; j < allLetters; j++) {
+ endCounts[j] = 0;
+ }
+ for (WordList::iterator it = all.begin(); it != all.end(); ++it) {
+ LetterString word = *it;
+ Letter last = word[word.length() - 1];
+ endCounts[last]++;
+ }
+
+ // find the most common and 2nd most common final letters
+ int maxEndCnt = 0;
+ int maxEndLetter = QUACKLE_NULL_MARK;
+ int max2EndCnt = 0;
+ int max2EndLetter = QUACKLE_NULL_MARK;
+ for (int j = 0; j < allLetters; j++) {
+ if (endCounts[j] > maxEndCnt) {
+ max2EndCnt = maxEndCnt;
+ max2EndLetter = maxEndLetter;
+ maxEndCnt = endCounts[j];
+ maxEndLetter = j;
+ } else if (endCounts[j] > max2EndCnt) {
+ max2EndCnt = endCounts[j];
+ max2EndLetter = j;
+ }
+ }
+
+// UVcout << QUACKLE_ALPHABET_PARAMETERS->userVisible(maxEndLetter)
+// << " " << endCounts[maxEndLetter] << endl;
+// UVcout << QUACKLE_ALPHABET_PARAMETERS->userVisible(max2EndLetter)
+// << " " << endCounts[max2EndLetter] << endl;
+
+ // We found a pluralizer if it is much more common, otherwise this
+ // language doesn't seem to have one.
+ if (endCounts[maxEndLetter] > 2 * endCounts[max2EndLetter]) {
+ UVcout << QUACKLE_ALPHABET_PARAMETERS->userVisible(maxEndLetter)
+ << " is the pluralizer" << endl;
+ return maxEndLetter;
+ }
+ return QUACKLE_NULL_MARK;
+}
+
+void TestHarness::bingos()
+{
+ Letter pluralizer = findPluarlizer();
+
+ // enumerate all racks not considering blanks
+ Quackle::Bag B;
+ int blankCnt = 0;
+ while (B.removeLetter(QUACKLE_BLANK_MARK)) {
+ ++blankCnt;
+ }
+ Enumerator E(B);
+ ProbableRackList enumRacks;
+ E.enumerate(&enumRacks, 6);
+
+ // convert probable racks to power racks for extra fields
+ PowerRackList racks;
+ for (ProbableRackList::iterator it = enumRacks.begin();
+ it != enumRacks.end(); ++it) {
+ racks.push_back(PowerRack(*it));
+ }
+
+ // get counts of all non-blank letters
+ Letter start = QUACKLE_ALPHABET_PARAMETERS->firstLetter();
+ Letter end = QUACKLE_ALPHABET_PARAMETERS->lastLetter();
+ char bagCounts[QUACKLE_FIRST_LETTER + QUACKLE_MAXIMUM_ALPHABET_SIZE];
+ B.letterCounts(bagCounts);
+
+ Generator gen;
+ int cnt = 0;
+ for (PowerRackList::iterator it = racks.begin(); it != racks.end(); ++it) {
+ LetterString letters(it->rack.tiles());
+
+ char rackCounts[QUACKLE_FIRST_LETTER + QUACKLE_MAXIMUM_ALPHABET_SIZE];
+ String::counts(letters, rackCounts);
+
+ if (++cnt % 1000 == 0) {
+ UVcout << "stem: " << QUACKLE_ALPHABET_PARAMETERS->userVisible(letters)
+ << " (" << cnt << " / " << racks.size() << ")" << endl;
+ }
+
+ // Count how many tiles combine with rack to make a bingo
+ int usableTiles = 0;
+ for (Letter c = start; c <= end; ++c) {
+ if (bagCounts[c] <= rackCounts[c]) {
+ continue; // none left in bag to draw
+ }
+ int flags = Generator::AnagramRearrange | Generator::SingleMatch;
+ WordList anagrams = gen.anagramLetters(letters + c, flags);
+ if (anagrams.size() > 0) {
+ usableTiles += bagCounts[c] - rackCounts[c]; // count all in the bag
+ }
+ }
+
+ // if we can make anything we can also do so with blanks
+ if (usableTiles > 0) {
+ usableTiles += blankCnt;
+ }
+ it->usableTiles = usableTiles;
+ if (rackCounts[pluralizer]) {
+ // Baron: "However, due to the frequent retention of the S in
+ // actual play, its attributed frequency was subsequently increased
+ // artificially 50%". I generalized 'S' to a pluralizer for
+ // multi-language support.
+ it->stemProbability *= 1.5;
+ }
+ it->power = it->stemProbability * usableTiles;
+ }
+
+ sort(racks.begin(), racks.end(), powerSort);
+
+ // Normalize max MSP to 1 (or 1.5 if it contains pluralizer) and MMPR
+ double scale = 1 / racks.begin()->stemProbability;
+ if (racks.begin()->rack.contains(LetterString(1, pluralizer))) {
+ scale *= 1.5;
+ }
+ for (PowerRackList::iterator it = racks.begin(); it != racks.end(); ++it) {
+ it->stemProbability *= scale;
+ it->power *= scale;
+ }
+
+ // dump results
+ for (PowerRackList::iterator it = racks.begin(); it != racks.end(); ++it) {
+ UVcout << it->rack << " " << it->stemProbability << " "
+ << it->usableTiles << " " << it->power << endl;
+ }
+}
+
+void TestHarness::testPosition(const Quackle::GamePosition &position, Quackle::ComputerPlayer *player)
+{
+ player->setPosition(position);
+
+ ProbableRackList racks;
+ Quackle::Bag unseenBag = position.unseenBag();
+
+ if (unseenBag.size() <= QUACKLE_PARAMETERS->rackSize() + 3)
+ {
+ Enumerator enumerator(unseenBag);
+ enumerator.enumerate(&racks);
+ UVcout << racks.size() << " enumerations: " << endl;
+ for (ProbableRackList::iterator it = racks.begin(); it != racks.end(); ++it)
+ UVcout << (*it).rack << " " << (*it).probability << endl;
+ }
+
+ const int movesToShow = 10;
+ UVcout << "Testing " << computerPlayerToTest()->name() << " on:" << endl;
+ UVcout << position << endl;
+ UVcout << "Generating moves..." << endl;
+
+ MoveList moves = computerPlayerToTest()->moves(movesToShow);
+
+ for (Quackle::MoveList::const_iterator it = moves.begin(); it != moves.end(); ++it)
+ {
+ UVcout << *it << endl;
+ }
+}
+
+void TestHarness::anagram(const QString &letters, bool build)
+{
+ QuackleIO::DictImplementation dict;
+ Dict::WordList list = dict.query(letters, build? Dict::Querier::NoRequireAllLetters : Dict::Querier::None);
+
+ for (Dict::WordList::Iterator it = list.begin(); it != list.end(); ++it)
+ {
+ UVcout << QuackleIO::Util::qstringToString((*it).word);
+ if ((*it).british)
+ UVcout << "#";
+ UVcout << endl;
+ }
+}
+
+Quackle::Game *TestHarness::createNewGame(const QString &filename)
+{
+ QuackleIO::GCGIO io;
+ QFile file(filename);
+
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ {
+ UVcout << "Could not open gcg " << QuackleIO::Util::qstringToString(filename) << endl;
+ return 0;
+ }
+
+ QTextStream in(&file);
+ Quackle::Game *game = io.read(in, QuackleIO::Logania::MaintainBoardPreparation);
+ file.close();
+
+ return game;
+}
+
+void TestHarness::testPositions()
+{
+ UVcout << "Testing " << m_positions.size() << " positions with " << m_computerPlayerToTest->name() << "." << endl;
+ for (QStringList::iterator it = m_positions.begin(); it != m_positions.end(); ++it)
+ testFromFile(*it);
+}
+
+void TestHarness::testReport(bool html)
+{
+ UVcout << "Reporting on " << m_positions.size() << " positions with " << m_computerPlayerToTest->name() << "." << endl;
+ for (QStringList::iterator it = m_positions.begin(); it != m_positions.end(); ++it)
+ {
+ Quackle::Game *game = createNewGame(*it);
+ if (game)
+ {
+ if (html)
+ {
+ UVcout << game->currentPosition().board().htmlBoard(45) << endl;
+ }
+ else
+ {
+ UVString report;
+ Quackle::Reporter::reportGame(*game, m_computerPlayerToTest, &report);
+ UVcout << report << endl;
+ }
+ }
+
+ delete game;
+ }
+}
+
+void TestHarness::selfPlayGames(unsigned int seed, unsigned int reps, bool reports, bool playability)
+{
+ if (seed != numeric_limits<unsigned int>::max()) {
+ UVcout << "using seed " << seed << endl;
+ m_dataManager.seedRandomNumbers(seed);
+ }
+
+ for (unsigned int i = 0; i < reps; i++)
+ selfPlayGame(i, reports, playability);
+}
+
+void TestHarness::selfPlayGame(unsigned int gameNumber, bool reports, bool playability)
+{
+ Quackle::Game game;
+
+ Quackle::PlayerList players;
+
+ Quackle::Player compyA(m_computerPlayerToTest->name() + MARK_UV(" A"), Quackle::Player::ComputerPlayerType, 0);
+ compyA.setAbbreviatedName(MARK_UV("A"));
+ compyA.setComputerPlayer(m_computerPlayerToTest);
+ players.push_back(compyA);
+
+ Quackle::Player compyB(m_computerPlayerToTest->name() + MARK_UV(" B"), Quackle::Player::ComputerPlayerType, 1);
+ compyB.setAbbreviatedName(MARK_UV("B"));
+ compyB.setComputerPlayer(m_computerPlayerToTest);
+ players.push_back(compyB);
+
+ game.setPlayers(players);
+ game.associateKnownComputerPlayers();
+
+ game.addPosition();
+
+ UVcout << "NEW GAME (#" << gameNumber << ")" << endl;
+
+ QTime time;
+ time.start();
+
+ const int playahead = 50;
+ int i;
+ for (i = 0; i < playahead; ++i)
+ {
+ if (game.currentPosition().gameOver())
+ {
+ if (!m_quiet) { UVcout << "GAME OVER" << endl; }
+ break;
+ }
+
+ const Quackle::Player player(game.currentPosition().currentPlayer());
+
+ if (!m_quiet) {
+ if (playability) {
+ game.currentPosition().kibitz(100);
+ Quackle::MoveList moves = game.currentPosition().moves();
+ float bestEquity = moves.front().equity - 0.0001f;
+ Quackle::MoveList tops;
+ for (MoveList::iterator it = moves.begin(); it != moves.end(); ++it) {
+ if ((*it).equity >= bestEquity) {
+ tops.push_back(*it);
+ }
+ }
+ int numTops = tops.size();
+ for (MoveList::iterator it = tops.begin(); it != tops.end(); ++it) {
+ MoveList words = game.currentPosition().allWordsFormedBy(*it);
+ for (MoveList::iterator it2 = words.begin(); it2 != words.end(); ++it2) {
+ Rack word = (*it2).prettyTiles();
+ UVcout << word << " " << numTops << endl;
+ }
+ }
+ int toPlay = rand() % numTops;
+ //UVcout << "playing move #" << toPlay << endl;
+ game.commitMove(tops[toPlay]);
+ } else {
+ Quackle::Move compMove(game.haveComputerPlay());
+ UVcout << "with " << player.rack() << ", " << player.name()
+ << " commits to " << compMove << endl;
+ }
+ }
+ }
+
+ int secondsElapsed = static_cast<int>(time.elapsed() / 1000);
+ if (!m_quiet) {
+ UVcout << "Game " << gameNumber << " played in " << secondsElapsed
+ << " seconds with " << i << " moves" << endl;
+ }
+
+ if (!reports) {
+ return;
+ }
+
+ Quackle::StaticPlayer playah;
+ UVString report;
+ Quackle::Reporter::reportGame(game, &playah, &report);
+ if (!m_quiet) { UVcout << report << endl; }
+
+ QString gamesDir = m_gamesDir;
+ gamesDir.replace("PLAYERNAME", QuackleIO::Util::uvStringToQString(m_computerPlayerToTest->name()));
+ gamesDir.replace(" ", "_");
+ QDir::current().mkdir(gamesDir);
+
+ QString joinedCompyName = QuackleIO::Util::uvStringToQString(m_computerPlayerToTest->name());
+ joinedCompyName.replace(" ", "_");
+ QFile outFile(QString("%1/%2-game-%3.gcg").arg(gamesDir).arg(joinedCompyName).arg(gameNumber));
+
+ if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text))
+ {
+ UVcout << "Could not open gcg output file" << endl;
+ return;
+ }
+
+ QuackleIO::GCGIO io;
+ QTextStream out(&outFile);
+ io.write(game, out);
+
+ QFile outFileReport(QString("%1/%2-game-%3.report").arg(gamesDir).arg(joinedCompyName).arg(gameNumber));
+
+ if (!outFileReport.open(QIODevice::WriteOnly | QIODevice::Text))
+ {
+ UVcout << "Could not open report output file" << endl;
+ return;
+ }
+ QTextStream outReport(&outFileReport);
+ outReport << QuackleIO::Util::uvStringToQString(report);
+ outReport << "Game played in " << secondsElapsed << " seconds." << endl;
+
+ outFile.close();
+ outFileReport.close();
+}
+
+static void dumpGaddag(const GaddagNode *node, const LetterString &prefix)
+{
+ for (const GaddagNode* child = node->firstChild(); child; child = child->nextSibling()) {
+ Letter childLetter = child->letter();
+ LetterString newPrefix(prefix);
+ newPrefix += childLetter;
+
+ if (child->isTerminal()) {
+ UVcout << "wordDump: " << QUACKLE_ALPHABET_PARAMETERS->userVisible(newPrefix) << endl;
+ }
+ if (child->firstChild()) {
+ dumpGaddag(child, newPrefix);
+ }
+ }
+}
+
+void TestHarness::wordDump()
+{
+ if (QUACKLE_LEXICON_PARAMETERS->hasGaddag()) {
+ dumpGaddag(QUACKLE_LEXICON_PARAMETERS->gaddagRoot(),
+ LetterString());
+ } else {
+ UVcout << "wordDump: no gaddag" << endl;
+ }
+}
diff --git a/test/testharness.h b/test/testharness.h
new file mode 100644
index 0000000..aa3e139
--- /dev/null
+++ b/test/testharness.h
@@ -0,0 +1,117 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef QUACKLE_TESTHARNESS_H
+#define QUACKLE_TESTHARNESS_H
+
+#include <QStringList>
+
+#include <datamanager.h>
+#include <alphabetparameters.h>
+namespace Quackle
+{
+ class ComputerPlayer;
+ class Game;
+ class GamePosition;
+ class Rack;
+ class GaddagNode;
+}
+
+class TestHarness
+{
+public:
+ TestHarness();
+ ~TestHarness();
+
+ // parse and execute commands specified on command line
+ void executeFromArguments();
+
+ void startUp();
+
+ // Loads all positions and runs the computer player on them.
+ void testPositions();
+
+ // Loads all positions and spits out a report on them.
+ void testReport(bool html);
+
+ // Enumerates all racks using a full bag
+ void enumerateAll();
+
+ // Compute bingo stems ala Baron's MMPR
+ void bingos();
+
+ // Loads game from the file, and tests the final position,
+ // and cleans up the game.
+ void testFromFile(const QString &file);
+
+ // Load racks from a file racks and spit out their static leave values
+ void staticLeaves(const QString &file);
+
+ // Spit out random racks.
+ void randomRacks();
+
+ // Spit out roughish leave values. Leaves come from file leaves.
+ void leaveCalc(const QString &file);
+
+ // Sim a leave.
+ double leaveSim(const Quackle::Rack &R, int iterations);
+
+ // Tests what the computer player does on this position.
+ void testPosition(const Quackle::GamePosition &position, Quackle::ComputerPlayer *player);
+
+ // Anagrams given letters.
+ void anagram(const QString &letters, bool build);
+
+ void wordDump();
+
+ // Allocates and loads a game from the file.
+ Quackle::Game *createNewGame(const QString &filename);
+
+ void selfPlayGames(unsigned int seed, unsigned int reps, bool reports, bool playability);
+ void selfPlayGame(unsigned int gameNumber, bool reports, bool playability);
+
+ // Sets the positions that will be tested.
+ void setPositions(const QStringList &positions)
+ {
+ m_positions = positions;
+ }
+
+ Quackle::ComputerPlayer *computerPlayerToTest() const
+ {
+ return m_computerPlayerToTest;
+ }
+
+ void setComputerPlayerToTest(Quackle::ComputerPlayer *computerPlayer)
+ {
+ m_computerPlayerToTest = computerPlayer;
+ }
+
+protected:
+ // void dumpGaddag(const GaddagNode *node, const LetterString &prefix);
+ QStringList m_positions;
+ Quackle::DataManager m_dataManager;
+ Quackle::ComputerPlayer *m_computerPlayerToTest;
+ bool m_quiet;
+ QString m_gamesDir;
+ QString m_lexicon;
+ QString m_alphabet;
+};
+
+#endif
diff --git a/test/testmain.cpp b/test/testmain.cpp
new file mode 100644
index 0000000..f304c2a
--- /dev/null
+++ b/test/testmain.cpp
@@ -0,0 +1,39 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <QCoreApplication>
+#include <QStringList>
+
+#include <game.h>
+#include <quackleio/util.h>
+
+#include "testharness.h"
+#include "trademarkedboards.h"
+
+int main(int argc, char **argv)
+{
+ QCoreApplication a(argc, argv);
+
+ TestHarness harness;
+ harness.executeFromArguments();
+
+ return 0;
+}
+
diff --git a/test/trademarkedboards.cpp b/test/trademarkedboards.cpp
new file mode 100644
index 0000000..b9eb37c
--- /dev/null
+++ b/test/trademarkedboards.cpp
@@ -0,0 +1,148 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include "trademarkedboards.h"
+
+ScrabbleBoard::ScrabbleBoard()
+{
+ m_name = MARK_UV("Scrabble Board");
+
+ const int letterm[15][15] =
+ {
+ // A B C D E F G H I J K L M N O
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1},
+ {1, 1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1},
+ {2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1},
+ {1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1},
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1},
+ {1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1},
+ {1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2},
+ {1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1, 1},
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1}
+ };
+
+ const int wordm[15][15] =
+ {
+ // A B C D E F G H I J K L M N O
+ {3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3},
+ {1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1},
+ {1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1},
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1},
+ {1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1},
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1},
+ {1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1},
+ {1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1},
+ {3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3}
+ };
+
+ for (int i = 0; i < 15; ++i)
+ {
+ for (int j = 0; j < 15; ++j)
+ {
+ m_letterMultipliers[i][j] = letterm[i][j];
+ m_wordMultipliers[i][j] = wordm[i][j];
+ }
+ }
+}
+
+//////
+
+SuperScrabbleBoard::SuperScrabbleBoard()
+{
+ m_height = 21;
+ m_width = 21;
+
+ m_startRow = 10;
+ m_startColumn = 10;
+
+ m_name = MARK_UV("Super Scrabble Board");
+
+ const int letterm[21][21] =
+ {
+ // A B C D E F G H I J K L M N O P Q R S T U
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1},
+ {1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1},
+ {2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2},
+ {1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1},
+ {1, 1, 4, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 4, 1, 1},
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1},
+ {2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2},
+ {1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1},
+ {1, 1, 4, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 4, 1, 1},
+ {1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1},
+ {2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2},
+ {1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1},
+ {1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1}
+ };
+ const int wordm[21][21] =
+ {
+ // A B C D E F G H I J K L M N O P Q R S T U
+ {4, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 4},
+ {1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1},
+ {1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1},
+ {1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1},
+ {1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1},
+ {3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3},
+ {1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1},
+ {1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1},
+ {1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1},
+ {1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1},
+ {1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1},
+ {3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3},
+ {1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1},
+ {1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1},
+ {1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1},
+ {1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1},
+ {4, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 4},
+ };
+
+ for (int i = 0; i < 21; ++i)
+ {
+ for (int j = 0; j < 21; ++j)
+ {
+ m_letterMultipliers[i][j] = letterm[i][j];
+ m_wordMultipliers[i][j] = wordm[i][j];
+ }
+ }
+}
diff --git a/test/trademarkedboards.h b/test/trademarkedboards.h
new file mode 100644
index 0000000..f596c8f
--- /dev/null
+++ b/test/trademarkedboards.h
@@ -0,0 +1,40 @@
+/*
+ * Quackle -- Crossword game artificial intelligence and analysis tool
+ * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef QUACKLE_TRADEMARKEDBOARDS_H
+#define QUACKLE_TRADEMARKEDBOARDS_H
+
+#include "boardparameters.h"
+
+// Name: Scrabble Board
+class ScrabbleBoard : public Quackle::BoardParameters
+{
+public:
+ ScrabbleBoard();
+};
+
+// Name: Super Scrabble Board
+class SuperScrabbleBoard : public Quackle::BoardParameters
+{
+public:
+ SuperScrabbleBoard();
+};
+
+#endif