सी, 2765 (इष्टतम)
संपादित करें
अब सभी एक सी फ़ाइल में। यह सिर्फ सभी इष्टतम समाधान पाता है। इन सभी में १५ अक्षरों के ६ शब्द और १ अक्षर वाले १ शब्द होने चाहिए, जिसमें मूल्य १ के value अक्षर होंगे और दो खाली होंगे। उसके लिए मुझे केवल डिक्शनरी का एक हिस्सा लोड करने की जरूरत है और मुझे 15 अक्षरों वाले शब्दों को ब्लैंक के साथ देखने की जरूरत नहीं है। कोड एक साधारण संपूर्ण गहराई-पहली खोज है।
#include <stdio.h>
#include <stdint.h>
#include <string.h>
struct w {
struct lc { uint64_t hi,lo; } lc;
char w[16];
} w15[6000], w10[40000];
int n15,n10;
struct lc pool = { 0x12122464612, 0x8624119232c4229 };
int pts[27] = {0,1,3,3,2,1,4,2,4,1,8,5,1,3,1,1,3,10,1,1,1,1,4,4,8,4,10};
int f[27],fs[26], w15c[27],w15l[27][6000];
int count(struct lc a, int l) { return (l < 16 ? a.lo << 4 : a.hi) >> 4*(l&15) & 15; }
int matches_val(uint64_t a, uint64_t b) {
uint64_t mask = 0x1111111111111111ll;
return !((a - b ^ a ^ b) & mask);
}
int matches(struct lc all, struct lc a) { return matches_val(all.hi,a.hi) && matches_val(all.lo,a.lo); }
int picks[10];
void try(struct lc cur, int used, int level) {
int c, i, must;
if (level == 6) {
for (i = 0; i<27; i++) if (count(cur, i) && pts[i]>1) return;
for (i = 0; i < n10; i++) if(!(used & (1 << (w10[i].w[0] & 31))) && matches(w10[i].lc, cur)) {
for (c = 0; c<level; c++) printf("%s ",w15[picks[c]].w);
printf("%s\n",w10[i].w);
}
return;
}
for (i = 0; i < 26;i++) if (count(cur,fs[i])) break;
must = fs[i];
for (c = 0; c < w15c[must]; c++) { i = w15l[must][c]; if(!(used & (1 << (w15[i].w[0] & 31))) && matches(cur, w15[i].lc)) {
struct lc b = { cur.hi - w15[i].lc.hi, cur.lo - w15[i].lc.lo };
picks[level] = i;
try(b, used + (1 << (w15[i].w[0] & 31)), level+1);
}}
}
int cmpfs(int *a, int *b){return f[*a]-f[*b];}
void ins(struct w*w, char *s, int c) {
int i;
strcpy(w->w,s);
for (;*s;s++)
if (*s&16) w->lc.hi += 1ll << 4*(*s&15); else w->lc.lo += 1ll << 4*(*s&15) - 4;
if (c) for (i = 0; i < 27;i++) if (count(w->lc,i)) f[i]++, w15l[i][w15c[i]++] = w-w15;
}
int main() {
int i;
char s[20];
while(scanf("%s ",s)>0) {
if (strlen(s) == 15) ins(w15 + n15++,s,1);
if (strlen(s) == 10) ins(w10 + n10++,s,0);
}
for (i = 0; i < 26;i++) fs[i] = i+1;
qsort(fs, 26, sizeof(int), cmpfs);
try(pool, 0, 0);
}
उपयोग:
$time ./scrab <sowpods.txt
cc -O3 scrab.c -o scrab
JUXTAPOSITIONAL DEMISEMIQUAVERS ACKNOWLEDGEABLY WEATHERPROOFING CONVEYORIZATION FEATHERBEDDINGS LAURUSTINE
JUXTAPOSITIONAL DEMISEMIQUAVERS ACKNOWLEDGEABLY WEATHERPROOFING CONVEYORIZATION FEATHERBEDDINGS LUXURIATED
JUXTAPOSITIONAL DEMISEMIQUAVERS ACKNOWLEDGEABLY WEATHERPROOFING CONVEYORIZATION FEATHERBEDDINGS LUXURIATES
JUXTAPOSITIONAL DEMISEMIQUAVERS ACKNOWLEDGEABLY WEATHERPROOFING CONVEYORIZATION FEATHERBEDDINGS ULTRAQUIET
JUXTAPOSITIONAL DEMISEMIQUAVERS ACKNOWLEDGEABLY WEATHERPROOFING CONVEYORIZATION FEATHERBEDDINGS UTRICULATE
JUXTAPOSITIONAL DEMISEMIQUAVERS WEATHERPROOFING ACKNOWLEDGEABLY CONVEYORIZATION FEATHERBEDDINGS LAURUSTINE
JUXTAPOSITIONAL DEMISEMIQUAVERS WEATHERPROOFING ACKNOWLEDGEABLY CONVEYORIZATION FEATHERBEDDINGS LUXURIATED
JUXTAPOSITIONAL DEMISEMIQUAVERS WEATHERPROOFING ACKNOWLEDGEABLY CONVEYORIZATION FEATHERBEDDINGS LUXURIATES
JUXTAPOSITIONAL DEMISEMIQUAVERS WEATHERPROOFING ACKNOWLEDGEABLY CONVEYORIZATION FEATHERBEDDINGS ULTRAQUIET
JUXTAPOSITIONAL DEMISEMIQUAVERS WEATHERPROOFING ACKNOWLEDGEABLY CONVEYORIZATION FEATHERBEDDINGS UTRICULATE
OVERADJUSTMENTS QUODLIBETARIANS ACKNOWLEDGEABLY WEATHERPROOFING EXEMPLIFICATIVE HYDROGENIZATION RUBIACEOUS
OVERADJUSTMENTS QUODLIBETARIANS WEATHERPROOFING ACKNOWLEDGEABLY EXEMPLIFICATIVE HYDROGENIZATION RUBIACEOUS
real 0m1.754s
user 0m1.753s
sys 0m0.000s
ध्यान दें कि हर समाधान दो बार मुद्रित किया जाता है क्योंकि 15-अक्षर 'डब्ल्यू' शब्द जोड़ने पर 2 ऑर्डर बनते हैं क्योंकि 2 'डब्ल्यू' टाइल होते हैं।
बिंदु टूटने के साथ पहला समाधान मिला:
JUXTAPOSITIONAL 465
DEMISEMIQUAVERS 480
ACKNOWLEDGEABLY 465
WEATHERPROOFING 405
CONVEYORIZATION 480
FEATHERBEDDINGS 390
LAURUSTINE (LAURU?TI?E) 80
no tiles left
संपादित करें: स्पष्टीकरण
क्या पूरे स्थान को खोजना संभव बनाता है? एक नया शब्द जोड़ते समय मैं केवल उन शब्दों को ध्यान में रखता हूं जिनमें सबसे कम शेष अक्षर होते हैं। इस पत्र को वैसे भी कुछ शब्दों में होना चाहिए (और एक 15 अक्षर का शब्द क्योंकि यह एक गैर-मूल्य वाला पत्र होगा, हालांकि मैं इसकी जांच नहीं करता हूं)। इसलिए मैं उन शब्दों से शुरू करता हूं, J, Q, W, W, X, Z
जिनके चारों ओर मायने रखता है 50, 100, 100, 100, 200, 500
। निचले स्तरों पर मुझे अधिक कटऑफ मिलती है क्योंकि कुछ शब्द अक्षरों की कमी से समाप्त हो जाते हैं। प्रत्येक स्तर पर खोज ट्री की चौड़ाई:
0: 1
1: 49
2: 3046
3: 102560
4: 724040
5: 803959
6: 3469
बेशक गैर-इष्टतम समाधानों की जांच नहीं करने से बहुत सारे कटऑफ प्राप्त होते हैं (15 अक्षरों के शब्दों या छोटे शब्दों में रिक्तता)। इसलिए यह भाग्यशाली है कि इस शब्दकोश के साथ 2765 समाधान प्राप्त किया जा सकता है (लेकिन यह करीब था, 15 अक्षर शब्दों के केवल 2 संयोजन एक उचित वामपंथी देते हैं)। दूसरी ओर, कम स्कोरिंग संयोजनों को खोजने के लिए कोड को संशोधित करना आसान है, जहां सभी बचे हुए 10 अक्षर 1-मूल्यवान नहीं हैं, हालांकि यह साबित करना कठिन होगा कि यह एक इष्टतम समाधान होगा।
साथ ही कोड समय से पहले अनुकूलन के क्लासिक मामले को दर्शाता है। matches
फ़ंक्शन का यह संस्करण कोड को केवल 30% धीमा बनाता है:
int matches(struct lc all, struct lc a) {
int i;
for (i = 1; i < 27; i++) if (count(a, i) > count(all, i)) return 0;
return 1;
}
मैंने यह भी पता लगा लिया कि बिट मैजिक समानांतर तुलना को अपने मूल कोड की तुलना में भी कम कैसे बनाया जा सकता है (इस मामले में उच्चतम निबल का उपयोग नहीं किया जा सकता है, लेकिन यह कोई समस्या नहीं है, क्योंकि मुझे केवल 32 निबल्स में से 26 की आवश्यकता है):
int matches_val(uint64_t a, uint64_t b) {
uint64_t mask = 0x1111111111111111ll;
return !((a - b ^ a ^ b) & mask);
}
लेकिन यह शून्य लाभ देता है।
संपादित करें
ऊपर दिए गए स्पष्टीकरण को लिखते हुए मैंने महसूस किया कि अधिकांश समय उन शब्दों की सूची को स्कैन करने में खर्च किया जाता है जिनमें matches
फ़ंक्शन में कोई विशिष्ट अक्षर नहीं होता है। ऊपर की सूची की गणना 10x स्पीडअप दिया।