En İyi Skorlu Boggle Kurulu


16

Bu (şimdi geçersiz) sorunun cevaplarını görmek ilgimi çekiyordu , ancak hiçbir zaman düzeltilmedi / geliştirilmedi.

6 taraflı Boggle zarlarından oluşan bir set ( bu sorudan çalınan yapılandırma) verildiğinde , hangi kart yapılandırmasının mümkün olan en yüksek puan için izin vereceğini iki dakika içinde belirleyin. (yani hangi zar hangi yerde yukarı en büyük puanlama kelime havuzu için izin verir?)


AMAÇ

  • Kodunuz en fazla 2 dakika (120 saniye) çalışmalıdır. O zaman, otomatik olarak çalışmayı durdurmalı ve sonuçları yazdırmalıdır.

  • Final meydan puanı, programın 5 çalışmasının ortalama Boggle puanı olacaktır.

    • Beraberlik durumunda kazanan, hangi algoritma daha fazla kelime bulursa o olur .
    • Hala bir kravat olması durumunda, kazanan hangi algoritma daha uzun (8+) kelime bulursa olacaktır .

KURALLARI / CONSTRAINTS

  • Bu bir kod zorluğudur; kod uzunluğu önemsizdir.

  • Bir kelime listesi için lütfen bu bağlantıya bakın ( ISPELL "english.0"listeyi kullanın - SCOWL listesinde bazı yaygın kelimeler eksik).

    • Bu giriş, istediğiniz şekilde kodunuzda / içe aktarılmış / okunabilir.
    • Yalnızca normal ifade ile eşleşen kelimeler ^([a-pr-z]|qu){3,16}$sayılır. (Birim olarak yalnızca küçük harfler, 3-16 karakter, qu kullanılmalıdır.)
  • Kelimeler, tek bir sözcükte birden fazla kez tek bir kalıp kullanmadan sözcükleri doğru sırada hecelemek için bitişik harfleri (yatay, dikey ve çapraz) birleştirerek oluşturulur.

    • Kelimeler 3 harf veya daha uzun olmalıdır; daha kısa kelimeler puan kazanmaz.
    • Çoğaltılan harfler kabul edilebilir, sadece zar değil.
    • Kenarları tahtadan bir taraftan diğer tarafa geçen / kesen kelimelere izin verilmez.
  • Son Boggle ( meydan okuma değil ) puanı, bulunan tüm kelimelerin puan değerlerinin toplamıdır.

    • Her kelime için atanan puan değeri, kelimenin uzunluğuna bağlıdır. (aşağıya bakınız)
    • Normal Boggle kuralları, başka bir oyuncu tarafından bulunan kelimeleri düşecek / indirecektir. Burada başka hiçbir oyuncunun yer almadığını ve bulunan tüm kelimelerin toplam puana sayıldığını varsayın.
    • Ancak, aynı ızgarada bir kereden fazla bulunan kelimeler yalnızca bir kez sayılmalıdır.
  • İşleviniz / programınız en uygun düzenlemeyi BULMALIDIR ; önceden belirlenmiş bir listenin sabit kodlaması yapmaz.

  • Çıktınız ideal oyun tahtanızın 4x4 ızgarası, o tahta için bulunan tüm kelimelerin listesi ve bu kelimelerle eşleşen Boggle puanı olmalıdır.


DIE YAPILANDIRMA

A  A  E  E  G  N
E  L  R  T  T  Y
A  O  O  T  T  W
A  B  B  J  O  O
E  H  R  T  V  W
C  I  M  O  T  U
D  I  S  T  T  Y
E  I  O  S  S  T
D  E  L  R  V  Y
A  C  H  O  P  S
H  I  M  N  Qu U
E  E  I  N  S  U
E  E  G  H  N  W
A  F  F  K  P  S
H  L  N  N  R  Z
D  E  I  L  R  X

STANDART BOGGLE PUANLAMA TABLOSU

Word length => Points
<= 2 - 0 pts
   3 - 1  
   4 - 1  
   5 - 2  
   6 - 3  
   7 - 5
>= 8 - 11 pts
*Words using the "Qu" die will count the full 2 letters for their word, not just the 1 die.

ÖRNEK ÇIKTI

A  L  O  J  
V  U  T  S  
L  C  H  E  
G  K  R  X

CUT
THE
LUCK
HEX
....

140 points

Daha fazla açıklama gerekiyorsa, lütfen sorun!


2
Hedefi standartlaştırmak için bir sözlüğe sahip olmayı tercih ederim. Basit bir google aramasının da göstereceği gibi bunun yeni bir fikir olmadığını da unutmayın :) Gördüğüm en yüksek puan 4527( 1414toplam kelime), burada bulundu: ai.stanford.edu/~chuongdo/boggle/index.html
mellamokb

4
Program bu yüzyılı sona erdirmek için gerekli mi?
Peter Taylor

1
@GlitchMr İngilizcede, Q genellikle U. Boggle hesaplarında bu amaçla kullanılır.
Gaffi

1
Kelime listesi belirtimi net değil. Sadece ingilizce olarak listelenen kelimeleri sayıyor musunuz? Küçük harf? (Standart kelime oyunu kuralları kısaltmaları / başlatıcıları ve özel isimleri içermez).
Peter Taylor

1
Ben regex düşünüyordum ^([a-pr-z]|qu){3,16}$(bu yanlış qu ile 3 harfli kelimeler hariç tutacak, ama hiç yok).
Peter Taylor

Yanıtlar:


9

C, ortalama 500+ 1500 1750 puan

Bu, sürüm 2'ye göre nispeten küçük bir gelişmedir (önceki sürümlerle ilgili notlar için aşağıya bakın). İki bölüm var. Birincisi: Havuzdan tahtaları rastgele seçmek yerine, havuzdaki her tahta üzerinde tekrarlar, havuzun tepesine dönmeden ve tekrar etmeden önce her birini sırayla kullanır. (Bu yineleme gerçekleşirken havuz değiştirildiği için, üst üste iki kez veya daha kötüsü seçilen tahtalar olacaktır, ancak bu ciddi bir endişe değildir.) İkinci değişiklik, havuzun değiştiğinde programın şimdi izlemesidir. ve program havuz içeriğini iyileştirmeden çok uzun bir süre devam ederse, aramanın "durduğunu", havuzu boşalttığını ve yeni bir arama ile başladığını belirler. İki dakika dolana kadar bunu yapmaya devam eder.

Başlangıçta 1500 nokta aralığının ötesine geçmek için bir çeşit sezgisel arama yapacağımı düşünmüştüm. @ mellamokb'un 4527 puanlık bir tahta hakkındaki yorumu beni geliştirmek için bolca yer olduğunu varsaymamı sağladı. Ancak, nispeten küçük bir kelime listesi kullanıyoruz. 4527 puanlık tahta, en kapsayıcı kelime listesi olan YAWL kullanarak puan aldı - resmi ABD Scrabble kelime listesinden bile daha büyük. Bunu göz önünde bulundurarak, programımın bulduğu panoları yeniden inceledim ve 1700'ün üzerinde sınırlı sayıda pano olduğunu gördüm. Örneğin, 1726 puan alan bir tahtayı keşfetmiş olan birden fazla koşum vardı, ancak her zaman bulunan aynı tahtaydı (dönüşleri ve yansımaları görmezden gelmek).

Başka bir test olarak, programımı sözlük olarak YAWL kullanarak çalıştırdım ve yaklaşık bir düzine çalışmadan sonra 4527 puanlık kurulu buldu. Bu göz önüne alındığında, programımın zaten arama alanının üst sınırında olduğunu varsayıyorum ve bu nedenle planladığım yeniden yazma çok az kazanç için ekstra karmaşıklık getirecektir.

Programımın english.0kelime listesini kullanarak bulduğu en yüksek puan alan beş tahtanın listesi:

1735 :  D C L P  E I A E  R N T R  S E G S
1738 :  B E L S  R A D G  T I N E  S E R S
1747 :  D C L P  E I A E  N T R D  G S E R
1766 :  M P L S  S A I E  N T R N  D E S G
1772:   G R E P  T N A L  E S I T  D R E S

İnancım, 531 kelimeyle 1772 "grep board" (onu aramaya başladığım gibi), bu kelime listesiyle mümkün olan en yüksek puanlama kurulu olduğu. Programımın iki dakikalık çalışmasının% 50'den fazlası bu anakartla bitiyor. Ayrıca daha iyi bir şey bulamadan programımı bir gecede bıraktım. Bu nedenle, daha yüksek puan alan bir tahta varsa, muhtemelen programın arama tekniğini yenen bir yönünün olması gerekir. Örneğin, mizanpajda olası her küçük değişikliğin toplam puanda büyük bir düşüşe neden olduğu bir tahta, programım tarafından asla bulunamayabilir. Benim önsezim, böyle bir tahtanın var olma ihtimalinin düşük olması.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#define WORDLISTFILE "./english.0"

#define XSIZE 4
#define YSIZE 4
#define BOARDSIZE (XSIZE * YSIZE)
#define DIEFACES 6
#define WORDBUFSIZE 256
#define MAXPOOLSIZE 32
#define STALLPOINT 64
#define RUNTIME 120

/* Generate a random int from 0 to N-1.
 */
#define random(N)  ((int)(((double)(N) * rand()) / (RAND_MAX + 1.0)))

static char const dice[BOARDSIZE][DIEFACES] = {
    "aaeegn", "elrtty", "aoottw", "abbjoo",
    "ehrtvw", "cimotu", "distty", "eiosst",
    "delrvy", "achops", "himnqu", "eeinsu",
    "eeghnw", "affkps", "hlnnrz", "deilrx"
};

/* The dictionary is represented in memory as a tree. The tree is
 * represented by its arcs; the nodes are implicit. All of the arcs
 * emanating from a single node are stored as a linked list in
 * alphabetical order.
 */
typedef struct {
    int letter:8;   /* the letter this arc is labelled with */
    int arc:24;     /* the node this arc points to (i.e. its first arc) */
    int next:24;    /* the next sibling arc emanating from this node */
    int final:1;    /* true if this arc is the end of a valid word */
} treearc;

/* Each of the slots that make up the playing board is represented
 * by the die it contains.
 */
typedef struct {
    unsigned char die;      /* which die is in this slot */
    unsigned char face;     /* which face of the die is showing */
} slot;

/* The following information defines a game.
 */
typedef struct {
    slot board[BOARDSIZE];  /* the contents of the board */
    int score;              /* how many points the board is worth */
} game;

/* The wordlist is stored as a binary search tree.
 */
typedef struct {
    int item: 24;   /* the identifier of a word in the list */
    int left: 16;   /* the branch with smaller identifiers */
    int right: 16;  /* the branch with larger identifiers */
} listnode;

/* The dictionary.
 */
static treearc *dictionary;
static int heapalloc;
static int heapsize;

/* Every slot's immediate neighbors.
 */
static int neighbors[BOARDSIZE][9];

/* The wordlist, used while scoring a board.
 */
static listnode *wordlist;
static int listalloc;
static int listsize;
static int xcursor;

/* The game that is currently being examined.
 */
static game G;

/* The highest-scoring game seen so far.
 */
static game bestgame;

/* Variables to time the program and display stats.
 */
static time_t start;
static int boardcount;
static int allscores;

/* The pool contains the N highest-scoring games seen so far.
 */
static game pool[MAXPOOLSIZE];
static int poolsize;
static int cutoffscore;
static int stallcounter;

/* Some buffers shared by recursive functions.
 */
static char wordbuf[WORDBUFSIZE];
static char gridbuf[BOARDSIZE];

/*
 * The dictionary is stored as a tree. It is created during
 * initialization and remains unmodified afterwards. When moving
 * through the tree, the program tracks the arc that points to the
 * current node. (The first arc in the heap is a dummy that points to
 * the root node, which otherwise would have no arc.)
 */

static void initdictionary(void)
{
    heapalloc = 256;
    dictionary = malloc(256 * sizeof *dictionary);
    heapsize = 1;
    dictionary->arc = 0;
    dictionary->letter = 0;
    dictionary->next = 0;
    dictionary->final = 0;
}

static int addarc(int arc, char ch)
{
    int prev, a;

    prev = arc;
    a = dictionary[arc].arc;
    for (;;) {
        if (dictionary[a].letter == ch)
            return a;
        if (!dictionary[a].letter || dictionary[a].letter > ch)
            break;
        prev = a;
        a = dictionary[a].next;
    }
    if (heapsize >= heapalloc) {
        heapalloc *= 2;
        dictionary = realloc(dictionary, heapalloc * sizeof *dictionary);
    }
    a = heapsize++;
    dictionary[a].letter = ch;
    dictionary[a].final = 0;
    dictionary[a].arc = 0;
    if (prev == arc) {
        dictionary[a].next = dictionary[prev].arc;
        dictionary[prev].arc = a;
    } else {
        dictionary[a].next = dictionary[prev].next;
        dictionary[prev].next = a;
    }
    return a;
}

static int validateword(char *word)
{
    int i;

    for (i = 0 ; word[i] != '\0' && word[i] != '\n' ; ++i)
        if (word[i] < 'a' || word[i] > 'z')
            return 0;
    if (word[i] == '\n')
        word[i] = '\0';
    if (i < 3)
        return 0;
    for ( ; *word ; ++word, --i) {
        if (*word == 'q') {
            if (word[1] != 'u')
                return 0;
            memmove(word + 1, word + 2, --i);
        }
    }
    return 1;
}

static void createdictionary(char const *filename)
{
    FILE *fp;
    int arc, i;

    initdictionary();
    fp = fopen(filename, "r");
    while (fgets(wordbuf, sizeof wordbuf, fp)) {
        if (!validateword(wordbuf))
            continue;
        arc = 0;
        for (i = 0 ; wordbuf[i] ; ++i)
            arc = addarc(arc, wordbuf[i]);
        dictionary[arc].final = 1;
    }
    fclose(fp);
}

/*
 * The wordlist is stored as a binary search tree. It is only added
 * to, searched, and erased. Instead of storing the actual word, it
 * only retains the word's final arc in the dictionary. Thus, the
 * dictionary needs to be walked in order to print out the wordlist.
 */

static void initwordlist(void)
{
    listalloc = 16;
    wordlist = malloc(listalloc * sizeof *wordlist);
    listsize = 0;
}

static int iswordinlist(int word)
{
    int node, n;

    n = 0;
    for (;;) {
        node = n;
        if (wordlist[node].item == word)
            return 1;
        if (wordlist[node].item > word)
            n = wordlist[node].left;
        else
            n = wordlist[node].right;
        if (!n)
            return 0;
    }
}

static int insertword(int word)
{
    int node, n;

    if (!listsize) {
        wordlist->item = word;
        wordlist->left = 0;
        wordlist->right = 0;
        ++listsize;
        return 1;
    }

    n = 0;
    for (;;) {
        node = n;
        if (wordlist[node].item == word)
            return 0;
        if (wordlist[node].item > word)
            n = wordlist[node].left;
        else
            n = wordlist[node].right;
        if (!n)
            break;
    }

    if (listsize >= listalloc) {
        listalloc *= 2;
        wordlist = realloc(wordlist, listalloc * sizeof *wordlist);
    }
    n = listsize++;
    wordlist[n].item = word;
    wordlist[n].left = 0;
    wordlist[n].right = 0;
    if (wordlist[node].item > word)
        wordlist[node].left = n;
    else
        wordlist[node].right = n;
    return 1;
}

static void clearwordlist(void)
{
    listsize = 0;
    G.score = 0;
}


static void scoreword(char const *word)
{
    int const scoring[] = { 0, 0, 0, 1, 1, 2, 3, 5 };
    int n, u;

    for (n = u = 0 ; word[n] ; ++n)
        if (word[n] == 'q')
            ++u;
    n += u;
    G.score += n > 7 ? 11 : scoring[n];
}

static void addwordtolist(char const *word, int id)
{
    if (insertword(id))
        scoreword(word);
}

static void _printwords(int arc, int len)
{
    int a;

    while (arc) {
        a = len + 1;
        wordbuf[len] = dictionary[arc].letter;
        if (wordbuf[len] == 'q')
            wordbuf[a++] = 'u';
        if (dictionary[arc].final) {
            if (iswordinlist(arc)) {
                wordbuf[a] = '\0';
                if (xcursor == 4) {
                    printf("%s\n", wordbuf);
                    xcursor = 0;
                } else {
                    printf("%-16s", wordbuf);
                    ++xcursor;
                }
            }
        }
        _printwords(dictionary[arc].arc, a);
        arc = dictionary[arc].next;
    }
}

static void printwordlist(void)
{
    xcursor = 0;
    _printwords(1, 0);
    if (xcursor)
        putchar('\n');
}

/*
 * The board is stored as an array of oriented dice. To score a game,
 * the program looks at each slot on the board in turn, and tries to
 * find a path along the dictionary tree that matches the letters on
 * adjacent dice.
 */

static void initneighbors(void)
{
    int i, j, n;

    for (i = 0 ; i < BOARDSIZE ; ++i) {
        n = 0;
        for (j = 0 ; j < BOARDSIZE ; ++j)
            if (i != j && abs(i / XSIZE - j / XSIZE) <= 1
                       && abs(i % XSIZE - j % XSIZE) <= 1)
                neighbors[i][n++] = j;
        neighbors[i][n] = -1;
    }
}

static void printboard(void)
{
    int i;

    for (i = 0 ; i < BOARDSIZE ; ++i) {
        printf(" %c", toupper(dice[G.board[i].die][G.board[i].face]));
        if (i % XSIZE == XSIZE - 1)
            putchar('\n');
    }
}

static void _findwords(int pos, int arc, int len)
{
    int ch, i, p;

    for (;;) {
        ch = dictionary[arc].letter;
        if (ch == gridbuf[pos])
            break;
        if (ch > gridbuf[pos] || !dictionary[arc].next)
            return;
        arc = dictionary[arc].next;
    }
    wordbuf[len++] = ch;
    if (dictionary[arc].final) {
        wordbuf[len] = '\0';
        addwordtolist(wordbuf, arc);
    }
    gridbuf[pos] = '.';
    for (i = 0 ; (p = neighbors[pos][i]) >= 0 ; ++i)
        if (gridbuf[p] != '.')
            _findwords(p, dictionary[arc].arc, len);
    gridbuf[pos] = ch;
}

static void findwordsingrid(void)
{
    int i;

    clearwordlist();
    for (i = 0 ; i < BOARDSIZE ; ++i)
        gridbuf[i] = dice[G.board[i].die][G.board[i].face];
    for (i = 0 ; i < BOARDSIZE ; ++i)
        _findwords(i, 1, 0);
}

static void shuffleboard(void)
{
    int die[BOARDSIZE];
    int i, n;

    for (i = 0 ; i < BOARDSIZE ; ++i)
        die[i] = i;
    for (i = BOARDSIZE ; i-- ; ) {
        n = random(i);
        G.board[i].die = die[n];
        G.board[i].face = random(DIEFACES);
        die[n] = die[i];
    }
}

/*
 * The pool contains the N highest-scoring games found so far. (This
 * would typically be done using a priority queue, but it represents
 * far too little of the runtime. Brute force is just as good and
 * simpler.) Note that the pool will only ever contain one board with
 * a particular score: This is a cheap way to discourage the pool from
 * filling up with almost-identical high-scoring boards.
 */

static void addgametopool(void)
{
    int i;

    if (G.score < cutoffscore)
        return;
    for (i = 0 ; i < poolsize ; ++i) {
        if (G.score == pool[i].score) {
            pool[i] = G;
            return;
        }
        if (G.score > pool[i].score)
            break;
    }
    if (poolsize < MAXPOOLSIZE)
        ++poolsize;
    if (i < poolsize) {
        memmove(pool + i + 1, pool + i, (poolsize - i - 1) * sizeof *pool);
        pool[i] = G;
    }
    cutoffscore = pool[poolsize - 1].score;
    stallcounter = 0;
}

static void selectpoolmember(int n)
{
    G = pool[n];
}

static void emptypool(void)
{
    poolsize = 0;
    cutoffscore = 0;
    stallcounter = 0;
}

/*
 * The program examines as many boards as it can in the given time,
 * and retains the one with the highest score. If the program is out
 * of time, then it reports the best-seen game and immediately exits.
 */

static void report(void)
{
    findwordsingrid();
    printboard();
    printwordlist();
    printf("score = %d\n", G.score);
    fprintf(stderr, "// score: %d points (%d words)\n", G.score, listsize);
    fprintf(stderr, "// %d boards examined\n", boardcount);
    fprintf(stderr, "// avg score: %.1f\n", (double)allscores / boardcount);
    fprintf(stderr, "// runtime: %ld s\n", time(0) - start);
}

static void scoreboard(void)
{
    findwordsingrid();
    ++boardcount;
    allscores += G.score;
    addgametopool();
    if (bestgame.score < G.score) {
        bestgame = G;
        fprintf(stderr, "// %ld s: board %d scoring %d\n",
                time(0) - start, boardcount, G.score);
    }

    if (time(0) - start >= RUNTIME) {
        G = bestgame;
        report();
        exit(0);
    }
}

static void restartpool(void)
{
    emptypool();
    while (poolsize < MAXPOOLSIZE) {
        shuffleboard();
        scoreboard();
    }
}

/*
 * Making small modifications to a board.
 */

static void turndie(void)
{
    int i, j;

    i = random(BOARDSIZE);
    j = random(DIEFACES - 1) + 1;
    G.board[i].face = (G.board[i].face + j) % DIEFACES;
}

static void swapdice(void)
{
    slot t;
    int p, q;

    p = random(BOARDSIZE);
    q = random(BOARDSIZE - 1);
    if (q >= p)
        ++q;
    t = G.board[p];
    G.board[p] = G.board[q];
    G.board[q] = t;
}

/*
 *
 */

int main(void)
{
    int i;

    start = time(0);
    srand((unsigned int)start);

    createdictionary(WORDLISTFILE);
    initwordlist();
    initneighbors();

    restartpool();
    for (;;) {
        for (i = 0 ; i < poolsize ; ++i) {
            selectpoolmember(i);
            turndie();
            scoreboard();
            selectpoolmember(i);
            swapdice();
            scoreboard();
        }
        ++stallcounter;
        if (stallcounter >= STALLPOINT) {
            fprintf(stderr, "// stalled; restarting search\n");
            restartpool();
        }
    }

    return 0;
}

Sürüm 2 için notlar (9 Haziran)

İşte kodumun ilk sürümünü bir atlama noktası olarak kullanmanın bir yolu. Bu versiyondaki değişiklikler 100 satırdan az, ancak ortalama oyun skorunu üçe katladı.

Bu versiyonda program, programın bugüne kadar oluşturduğu en yüksek puan alan N kuruldan oluşan adaylardan oluşan bir “havuz” tutuyor. Her yeni tahta üretildiğinde, havuza eklenir ve havuzdaki en düşük puanlı tahta kaldırılır (eğer puanı zaten mevcut olandan daha düşükse, yeni eklenen tahta çok iyi olabilir). Havuz başlangıçta rastgele oluşturulan panolarla doldurulur, daha sonra programın çalışması boyunca sabit bir boyut tutar.

Programın ana döngüsü havuzdan rastgele bir tahta seçmek ve değiştirmek, bu yeni kurulun puanını belirlemek ve daha sonra havuza koymaktır (yeterince iyi ise). Bu şekilde, program yüksek puan tablolarını sürekli olarak geliştirmektedir. Ana faaliyet adım adım, artımlı iyileştirmeler yapmaktır, ancak havuzun boyutu da programın daha iyi hale getirmeden önce bir tahtanın puanını geçici olarak daha da kötüleştiren çok adımlı iyileştirmeler bulmasına izin verir.

Tipik olarak bu program oldukça hızlı bir şekilde iyi bir yerel maksimum bulur, bundan sonra daha iyi maksimumlar bulunamayacak kadar uzaktır. Ve bir kez daha programı 10 saniyeden daha uzun süre çalıştırmanın pek bir anlamı yok. Bu, örneğin programın bu durumu algılaması ve yeni bir aday havuzuyla yeni bir arama başlatmasıyla geliştirilebilir. Ancak, bu sadece marjinal bir artış sağlayacaktır. Uygun bir sezgisel arama tekniği muhtemelen daha iyi bir keşif yolu olacaktır.

(Yan not: Bu sürümün yaklaşık 5k pano / sn ürettiğini gördüm. İlk sürüm tipik olarak 20k pano / sn yaptı, başlangıçta endişelendim. Profilleme üzerine, kelime listesini yönetmek için fazladan zaman harcadığını keşfettim. Başka bir deyişle, bu tamamen program başına çok daha fazla kelime bulmaktan kaynaklanıyordu.Bunun ışığında, kelime listesini yönetmek için kodu değiştirmeyi düşündüm, ancak bu program sadece tahsis edilen 120 saniyenin 10'unu kullanıyor, bir optimizasyon çok erken olacaktır.)

Sürüm 1 için notlar (2 Haziran)

Bu çok ama çok basit bir çözüm. Tüm yaptığı rastgele tahtalar oluşturur ve daha sonra 10 saniye sonra en yüksek puanı alan olanı verir. (Varsayılan olarak 10 saniyeye ayarladım çünkü problem spesifikasyonunun izin verdiği ekstra 110 saniye genellikle beklemeye değecek kadar bulunan nihai çözümü geliştirmiyor.) Bu yüzden son derece aptal. Bununla birlikte, daha akıllı bir arama için iyi bir başlangıç ​​noktası yapmak için tüm altyapıya sahiptir ve eğer herhangi biri son tarihten önce kullanmak isterse, bunu yapmaya teşvik ederim.

Program sözlüğü bir ağaç yapısına okuyarak başlar. (Form olabildiğince optimize edilmemiştir, ancak bu amaçlar için yeterince iyi değildir.) Başka bir temel başlatma işleminden sonra, pano oluşturmaya ve puanlamaya başlar. Program makinemde saniyede yaklaşık 20k pano inceliyor ve yaklaşık 200k panodan sonra rastgele yaklaşım kurumaya başlıyor.

Herhangi bir zamanda sadece bir kart değerlendirildiğinden, puanlama verileri global değişkenlerde saklanır. Bu, özyinelemeli işlevlere bağımsız değişken olarak iletilmesi gereken sabit veri miktarını en aza indirmeme olanak tanır. (Eminim bu bazı insanlara kovan verir ve onlardan özür dilerim.) Kelime listesi ikili bir arama ağacı olarak saklanır. Bulunan her kelimenin kelime listesinde aranması gerekir, böylece yinelenen kelimeler iki kez sayılmaz. Kelime listesi sadece değerlendirme sürecinde gereklidir, bu yüzden skor bulunduktan sonra atılır. Bu nedenle, programın sonunda, seçilen kartın tekrar tekrar puanlanması gerekir, böylece kelime listesi yazdırılabilir.

İlginç gerçek: Rastgele oluşturulmuş Boggle tahtasının skoru english.0, 61.7 puan.


Açıkçası, kendi verimliliğimi artırmam gerekiyor. :-)
Gaffi

Genetik yaklaşımım yaklaşık 200 bin pano üreten yaklaşık 700-800 puan alıyor, bu yüzden yeni nesli üretme şeklinizde benden çok daha iyi bir şey yapıyorsunuz.
Peter Taylor

Şimdiye kadar sadece ana kelime listesi için uygulanan kendi ağaç yapım, çalışırken ve panoları doğrulamama izin verirken, sistem belleğimi azaltıyor (süreci zorlamak için önemli ölçüde zaman aldığı noktaya kadar aktif olarak kalıyor) erken fesih). Bu kesinlikle benim hatam, ama üzerinde çalışıyorum! Düzenleme: Zaten düzeltildi! ;-)
Gaffi

@PeterTaylor Genetik bir algoritmayı denemeyi düşündüm, ancak iki kartı birleştirmek için makul bir mekanizma düşünemedim. Bunu nasıl yapıyorsun? Karttaki her yuva için ebeveyni rastgele seçiyor musunuz?
ekmek kutusu

Tahta durumunu zar permütasyonuna ve zarda gösterilen yüzlere böldüm. Permütasyon geçişi için cs.colostate.edu/~genitor/1995/permutations.pdf adresinden "order crossover 1" komutunu kullanıyorum ve yüz geçişi için açık olanı yapıyorum. Ama uygulamak için zaman bulmam gereken tamamen farklı bir yaklaşım hakkında bir fikrim var.
Peter Taylor

3

VBA (şu anda ortalama 80-110 puan arasında değişen, tamamlanmamış)

İşte benim çalışma sürecim, ama mümkün olan en iyi şeyden uzak; birçok test çalışmasından sonra herhangi bir tahtada bulunan mutlak en iyi puanım 120 civarındadır. Hala daha iyi bir genel temizlik olması gerekiyor ve eminim bazı yerlerde daha fazla verimlilik kazanılacak.

  • 2012/05/09:
    • Orijinal yayın
  • 2012.05.10 - 2012.05.18:
    • Puanlama algoritması geliştirildi
    • Yol bulma mantığı geliştirildi
  • 2012.06.07 - 2012.06.12 :
    • Sözcük sınırı 8'den 6'ya düşürüldü. Daha küçük sözcüklere sahip daha fazla tahtaya izin verir. Ortalama puanda hafif bir iyileşme olduğu görülüyor. (10-15 veya daha fazla kart çalışma başına 1 ila 2 arasında kontrol edilir)
    • Breadbox'ın önerisini takiben, kelime listesini barındırmak için bir ağaç yapısı oluşturdum. Bu, bir tahtadaki kelimelerin arka uç kontrolünü önemli ölçüde hızlandırır.
    • Maksimum kelime boyutunu (hız ve skor) değiştirerek oynadım ve 5 veya 6'nın benim için daha iyi bir seçenek olup olmadığına henüz karar vermedim. 6, 100-120 toplam pano kontrol edilirken, 5 tanesi 500-1000 ile sonuçlanır (her ikisi de, şimdiye kadar sağlanan diğer örneklerin hala çok altındadır).
    • Sorun : Birçok ardışık çalışmadan sonra süreç yavaşlamaya başlar, bu yüzden hala yönetilecek bir miktar bellek vardır.

Bu muhtemelen bazılarınız için korkunç görünüyor, ama dediğim gibi WIP. Yapıcı eleştirilere çok açığım ! Çok uzun beden için özür dilerim ...


Zar Sınıfı Modülü :

Option Explicit

Private Sides() As String

Sub NewDie(NewLetters As String)
    Sides = Split(NewLetters, ",")
End Sub

Property Get Side(i As Integer)
    Side = Sides(i)
End Property

Ağaç Sınıfı Modülü :

Option Explicit

Private zzroot As TreeNode


Sub AddtoTree(ByVal TreeWord As Variant)
Dim i As Integer
Dim TempNode As TreeNode

    Set TempNode = TraverseTree(TreeWord, zzroot)
    SetNode TreeWord, TempNode

End Sub

Private Function SetNode(ByVal Value As Variant, parent As TreeNode) As TreeNode
Dim ValChar As String
    If Len(Value) > 0 Then
        ValChar = Left(Value, 1)
        Select Case Asc(ValChar) - 96
            Case 1:
                Set parent.Node01 = AddNode(ValChar, parent.Node01)
                Set SetNode = parent.Node01
            Case 2:
                Set parent.Node02 = AddNode(ValChar, parent.Node02)
                Set SetNode = parent.Node02
            ' ... - Reduced to limit size of answer.
            Case 26:
                Set parent.Node26 = AddNode(ValChar, parent.Node26)
                Set SetNode = parent.Node26
            Case Else:
                Set SetNode = Nothing
        End Select

        Set SetNode = SetNode(Right(Value, Len(Value) - 1), SetNode)
    Else
        Set parent.Node27 = AddNode(True, parent.Node27)
        Set SetNode = parent.Node27
    End If
End Function

Function AddNode(ByVal Value As Variant, NewNode As TreeNode) As TreeNode
    If NewNode Is Nothing Then
        Set AddNode = New TreeNode
        AddNode.Value = Value
    Else
        Set AddNode = NewNode
    End If
End Function
Function TraverseTree(TreeWord As Variant, parent As TreeNode) As TreeNode
Dim Node As TreeNode
Dim ValChar As String
    If Len(TreeWord) > 0 Then
        ValChar = Left(TreeWord, 1)

        Select Case Asc(ValChar) - 96
            Case 1:
                Set Node = parent.Node01
            Case 2:
                Set Node = parent.Node02
            ' ... - Reduced to limit size of answer.
            Case 26:
                Set Node = parent.Node26
            Case Else:
                Set Node = Nothing
        End Select

        If Not Node Is Nothing Then
            Set TraverseTree = TraverseTree(Right(TreeWord, Len(TreeWord) - 1), Node)
            If Not TraverseTree Is Nothing Then
                Set TraverseTree = parent
            End If
        Else
            Set TraverseTree = parent
        End If
    Else
        If parent.Node27.Value Then
            Set TraverseTree = parent
        Else
            Set TraverseTree = Nothing
        End If
    End If
End Function

Function WordScore(TreeWord As Variant, Step As Integer, Optional parent As TreeNode = Nothing) As Integer
Dim Node As TreeNode
Dim ValChar As String
    If parent Is Nothing Then Set parent = zzroot
    If Len(TreeWord) > 0 Then
        ValChar = Left(TreeWord, 1)

        Select Case Asc(ValChar) - 96
            Case 1:
                Set Node = parent.Node01
            Case 2:
                Set Node = parent.Node02
            ' ... - Reduced to limit size of answer.
            Case 26:
                Set Node = parent.Node26
            Case Else:
                Set Node = Nothing
        End Select

        If Not Node Is Nothing Then
            WordScore = WordScore(Right(TreeWord, Len(TreeWord) - 1), Step + 1, Node)
        End If
    Else
        If parent.Node27 Is Nothing Then
            WordScore = 0
        Else
            WordScore = Step
        End If
    End If
End Function

Function ValidWord(TreeWord As Variant, Optional parent As TreeNode = Nothing) As Integer
Dim Node As TreeNode
Dim ValChar As String
    If parent Is Nothing Then Set parent = zzroot
    If Len(TreeWord) > 0 Then
        ValChar = Left(TreeWord, 1)

        Select Case Asc(ValChar) - 96
            Case 1:
                Set Node = parent.Node01
            Case 2:
                Set Node = parent.Node02
            ' ... - Reduced to limit size of answer.
            Case 26:
                Set Node = parent.Node26
            Case Else:
                Set Node = Nothing
        End Select

        If Not Node Is Nothing Then
            ValidWord = ValidWord(Right(TreeWord, Len(TreeWord) - 1), Node)
        Else
            ValidWord = False
        End If
    Else
        If parent.Node27 Is Nothing Then
            ValidWord = False
        Else
            ValidWord = True
        End If
    End If
End Function

Private Sub Class_Initialize()
    Set zzroot = New TreeNode
End Sub

Private Sub Class_Terminate()
    Set zzroot = Nothing
End Sub

TreeNode Sınıfı Modülü :

Option Explicit

Public Value As Variant
Public Node01 As TreeNode
Public Node02 As TreeNode
' ... - Reduced to limit size of answer.
Public Node26 As TreeNode
Public Node27 As TreeNode

Ana Modül :

Option Explicit

Const conAllSides As String = ";a,a,e,e,g,n;e,l,r,t,t,y;a,o,o,t,t,w;a,b,b,j,o,o;e,h,r,t,v,w;c,i,m,o,t,u;d,i,s,t,t,y;e,i,o,s,s,t;d,e,l,r,v,y;a,c,h,o,p,s;h,i,m,n,qu,u;e,e,i,n,s,u;e,e,g,h,n,w;a,f,f,k,p,s;h,l,n,n,r,z;d,e,i,l,r,x;"
Dim strBoard As String, strBoardTemp As String, strWords As String, strWordsTemp As String
Dim CheckWordSub As String
Dim iScore As Integer, iScoreTemp As Integer
Dim Board(1 To 4, 1 To 4) As Integer
Dim AllDice(1 To 16) As Dice
Dim AllWordsTree As Tree
Dim AllWords As Scripting.Dictionary
Dim CurWords As Scripting.Dictionary
Dim FullWords As Scripting.Dictionary
Dim JunkWords As Scripting.Dictionary
Dim WordPrefixes As Scripting.Dictionary
Dim StartTime As Date, StopTime As Date
Const MAX_LENGTH As Integer = 5
Dim Points(3 To 8) As Integer

Sub Boggle()
Dim DiceSetup() As String
Dim i As Integer, j As Integer, k As Integer

    StartTime = Now()

    strBoard = vbNullString
    strWords = vbNullString
    iScore = 0

    ReadWordsFileTree

    DiceSetup = Split(conAllSides, ";")

    For i = 1 To 16
        Set AllDice(i) = New Dice
        AllDice(i).NewDie "," & DiceSetup(i)
    Next i

    Do While WithinTimeLimit

        Shuffle

        strBoardTemp = vbNullString
        strWordsTemp = vbNullString
        iScoreTemp = 0

        FindWords

        If iScoreTemp > iScore Or iScore = 0 Then
            iScore = iScoreTemp
            k = 1
            For i = 1 To 4
                For j = 1 To 4
                    strBoardTemp = strBoardTemp & AllDice(k).Side(Board(j, i)) & "  "
                    k = k + 1
                Next j
                strBoardTemp = strBoardTemp & vbNewLine
            Next i
            strBoard = strBoardTemp
            strWords = strWordsTemp

        End If

    Loop

    Debug.Print strBoard
    Debug.Print strWords
    Debug.Print iScore & " points"

    Set AllWordsTree = Nothing
    Set AllWords = Nothing
    Set CurWords = Nothing
    Set FullWords = Nothing
    Set JunkWords = Nothing
    Set WordPrefixes = Nothing

End Sub

Sub ShuffleBoard()
Dim i As Integer

    For i = 1 To 16
        If Not WithinTimeLimit Then Exit Sub
        Board(Int((i - 1) / 4) + 1, 4 - (i Mod 4)) = Int(6 * Rnd() + 1)
    Next i

End Sub

Sub Shuffle()
Dim n As Long
Dim Temp As Variant
Dim j As Long

    Randomize
    ShuffleBoard
    For n = 1 To 16
        If Not WithinTimeLimit Then Exit Sub
        j = CLng(((16 - n) * Rnd) + n)
        If n <> j Then
            Set Temp = AllDice(n)
            Set AllDice(n) = AllDice(j)
            Set AllDice(j) = Temp
        End If
    Next n

    Set FullWords = New Scripting.Dictionary
    Set CurWords = New Scripting.Dictionary
    Set JunkWords = New Scripting.Dictionary

End Sub

Sub ReadWordsFileTree()
Dim FSO As New FileSystemObject
Dim FS
Dim strTemp As Variant
Dim iLength As Integer
Dim StartTime As Date

    StartTime = Now()
    Set AllWordsTree = New Tree
    Set FS = FSO.OpenTextFile("P:\Personal\english.txt")

    Points(3) = 1
    Points(4) = 1
    Points(5) = 2
    Points(6) = 3
    Points(7) = 5
    Points(8) = 11

    Do Until FS.AtEndOfStream
        strTemp = FS.ReadLine
        If strTemp = LCase(strTemp) Then
            iLength = Len(strTemp)
            iLength = IIf(iLength > 8, 8, iLength)
            If InStr(strTemp, "'") < 1 And iLength > 2 Then
                AllWordsTree.AddtoTree strTemp
            End If
        End If
    Loop
    FS.Close

End Sub

Function GetScoreTree() As Integer
Dim TempScore As Integer

    If Not WithinTimeLimit Then Exit Function

    GetScoreTree = 0

    TempScore = AllWordsTree.WordScore(CheckWordSub, 0)
    Select Case TempScore
        Case Is < 3:
            GetScoreTree = 0
        Case Is > 8:
            GetScoreTree = 11
        Case Else:
            GetScoreTree = Points(TempScore)
    End Select

End Function

Sub SubWords(CheckWord As String)
Dim CheckWordScore As Integer
Dim k As Integer, l As Integer

    For l = 0 To Len(CheckWord) - 3
        For k = 1 To Len(CheckWord) - l
            If Not WithinTimeLimit Then Exit Sub

            CheckWordSub = Mid(CheckWord, k, Len(CheckWord) - ((k + l) - 1))

            If Len(CheckWordSub) >= 3 And Not CurWords.Exists(CheckWordSub) Then
                CheckWordScore = GetScoreTree

                If CheckWordScore > 0 Then
                    CurWords.Add CheckWordSub, CheckWordSub
                    iScoreTemp = iScoreTemp + CheckWordScore
                    strWordsTemp = strWordsTemp & CheckWordSub & vbNewLine
                End If

                If Left(CheckWordSub, 1) = "q" Then
                    k = k + 1
                End If
            End If

        Next k
    Next l

End Sub

Sub FindWords()
Dim CheckWord As String
Dim strBoardLine(1 To 16) As String
Dim Used(1 To 16) As Boolean
Dim i As Integer, j As Integer, k As Integer, l As Integer, m As Integer, n As Integer
Dim StartSquare As Integer
Dim FullCheck As Variant

    n = 1
    For l = 1 To 4
        For m = 1 To 4
            If Not WithinTimeLimit Then Exit Sub
            strBoardLine(n) = AllDice(n).Side(Board(m, l))
            n = n + 1
        Next m
    Next l

    For i = 1 To 16
        For k = 1 To 16

            If Not WithinTimeLimit Then Exit Sub
            If k Mod 2 = 0 Then
                For j = 1 To 16
                    Used(j) = False
                Next j

                Used(i) = True
                MakeWords strBoardLine, Used, i, k / 2, strBoardLine(i)
            End If

        Next k
    Next i

    For Each FullCheck In FullWords.Items
        SubWords CStr(FullCheck)
    Next FullCheck

End Sub

Function MakeWords(BoardLine() As String, Used() As Boolean, _
    Start As Integer, _
    Direction As Integer, CurString As String) As String
Dim i As Integer, j As Integer, k As Integer, l As Integer

    j = 0

    Select Case Direction
        Case 1:
            k = Start - 5
        Case 2:
            k = Start - 4
        Case 3:
            k = Start - 3
        Case 4:
            k = Start - 1
        Case 5:
            k = Start + 1
        Case 6:
            k = Start + 3
        Case 7:
            k = Start + 4
        Case 8:
            k = Start + 5
    End Select

    If k >= 1 And k <= 16 Then
        If Not WithinTimeLimit Then Exit Function

        If Not Used(k) Then
            If ValidSquare(Start, k) Then
                If Not (JunkWords.Exists(CurString & BoardLine(k))) And Not FullWords.Exists(CurString & BoardLine(k)) Then
                    Used(k) = True
                    For l = 1 To MAX_LENGTH
                        If Not WithinTimeLimit Then Exit Function
                        MakeWords = CurString & BoardLine(k)
                        If Not (JunkWords.Exists(MakeWords)) Then
                            JunkWords.Add MakeWords, MakeWords
                        End If
                        If Len(MakeWords) = MAX_LENGTH And Not FullWords.Exists(MakeWords) Then
                            FullWords.Add MakeWords, MakeWords
                        ElseIf Len(MakeWords) < MAX_LENGTH Then
                            MakeWords BoardLine, Used, k, l, MakeWords
                        End If
                    Next l
                    Used(k) = False
                End If
            End If
        End If
    End If

    If Len(MakeWords) = MAX_LENGTH And Not FullWords.Exists(MakeWords) Then
        FullWords.Add MakeWords, MakeWords
        Debug.Print "FULL - " & MakeWords
    End If

End Function

Function ValidSquare(StartSquare As Integer, EndSquare As Integer) As Boolean
Dim sx As Integer, sy As Integer, ex As Integer, ey As Integer

    If Not WithinTimeLimit Then Exit Function

    sx = (StartSquare - 1) Mod 4 + 1
    ex = (EndSquare - 1) Mod 4 + 1

    sy = Int((StartSquare - 1) / 4 + 1)
    ey = Int((EndSquare - 1) / 4 + 1)

    ValidSquare = (sx - 1 <= ex And sx + 1 >= ex) And (sy - 1 <= ey And sy + 1 >= ey) And StartSquare <> EndSquare

End Function

Function WithinTimeLimit() As Boolean
    StopTime = Now()
    WithinTimeLimit = (Round(CDbl(((StopTime - StartTime) - Int(StopTime - StartTime)) * 86400), 0) < 120)
End Function

2
Kodlara bakmadım, ama 50 puan gülünç derecede düşük. Ben 1000 üzerinde puanları ile rastgele oluşturulan panoları oynadım (SOWPODS kullanarak - sağlanan kelime listesi daha az kapsamlı olabilir). Bir işaret hatası olup olmadığını kontrol etmek isteyebilirsiniz!
Peter Taylor

@PeterTaylor Öneri için teşekkürler. Bu puanın çok düşük olduğunu biliyorum ve sorunun bir kısmının, açık sözlerin kaçırıldığını görebildiğimde olduğunu biliyorum ...
Gaffi

@PeterTaylor Ayrıca, kayıt için, son ürünümü beklemek yerine sürekli ilerlememi gönderiyorum, çünkü henüz kimse bıçaklamamıştı. Bu gerçekleşene kadar soruyu biraz canlı tutmak istiyorum.
Gaffi

Ayrıca, bunun en hızlı makinede çalıştırılmadığını da not etmeliyim, bu da yardımcı olmuyor.
Gaffi

1
@Gaffi skoru hesaplamak için 10 saniye? Bu 9.999 saniye çok uzun. Kodunuzu yeniden düşünmelisiniz. Sözcük listenizi bir ağaca dönüştürmeyi reddederseniz, en azından şunu yapın: Tüm iki harfli öneklerin bir listesini (karma, her ne olursa olsun) yapın. Ardından, tahtadaki bir yolu izlemeye başladığınızda, ilk iki harf listede yoksa, olası yolların tüm alt ağacını atlayın. Yine, ağacın tamamını oluşturmak en iyisidir, ancak iki harfli önek listesi yardımcı olacaktır ve yapmak çok ucuzdur.
breadbox

2

Arama alanının boyutuna hızlı bir bakış.

   16! => 20922789888000 Dice Permutations
(6^16) =>  2821109907456 Face Permutations
 59025489844657012604928000 Boggle Grids 

Her kalıptaki tekrarı hariç tutmak için azaltma.

              16! => 20922789888000 Dice Permutations
(4^4)*(5^6)*(6^5) => 31104000000 Unique Face Permutations
   650782456676352000000000 Boggle Grids 

@breadbox sözlüğü bir Karma Tablo O (1) denetimi olarak saklar.

DÜZENLE

En İyi Kurul (şimdiye kadar tanık oldum)

L  E  A  N
S  E  T  M
T  S  B  D
I  E  G  O

Score: 830
Words: 229
SLEETIEST  MANTELETS
MANTEELS  MANTELET  MATELESS
MANTEEL  MANTELS  TESTEES  BETISES  OBTESTS  OBESEST
SLEETS  SLEEST  TESTIS  TESTES  TSETSE  MANTES  MANTEL  TESTAE  TESTEE
STEELS  STELES  BETELS  BESETS  BESITS  BETISE  BODGES  BESEES  EISELS
GESTES  GEISTS  OBTEST
LEANT  LEATS  LEETS  LEESE  LESES  LESTS  LESBO  ANTES  NATES  SLEET  SETAE
SEATS  STIES  STEEL  STETS  STEAN  STEAM  STELE  SELES  TAELS  TEELS  TESTS
TESTE  TELES  TETES  MATES  TESTA  TEATS  SEELS  SITES  BEETS  BETEL  BETES
BESET  BESTS  BESIT  BEATS  BODGE  BESEE  DOGES  EISEL  GESTS  GESTE  GESSE
GEITS  GEIST  OBESE
LEAN  LEAT  LEAM  LEET  LEES  LETS  LEST  LESS  EATS  EELS  ELSE  ETNA  ESES
ESTS  ESSE  ANTE  ANTS  ATES  AMBO  NATS  SLEE  SEEL  SETA  SETS  SESE  SEAN
SEAT  SEAM  SELE  STIE  STET  SEES  TAEL  TAES  TEEL  TEES  TEST  TEAM  TELE
TELS  TETS  TETE  MATE  MATS  MAES  TIES  TEAT  TEGS  SELS  SEGO  SITS  SITE
BEET  BEES  BETA  BETE  BETS  BEST  BEAN  BEAT  BEAM  BELS  BOGS  BEGO  BEGS
DOGE  DOGS  DOBS  GOBS  GEST  GEIT  GETS  OBES
LEA  LEE  LET  LES  EAN  EAT  EEL  ELS  ETA  EST  ESS  ANT  ATE  NAT  NAE  NAM
SEE  SET  SEA  SEL  TAN  TAE  TAM  TEE  TES  TEA  TEL  TET  MNA  MAN  MAT  MAE
TIE  TIS  TEG  SEG  SEI  SIT  BEE  BET  BEL  BOD  BOG  BEG  DOG  DOB  ITS  EGO
GOD  GOB  GET  OBS  OBE
EA  EE  EL  ET  ES  AN  AT  AE  AM  NA  ST  TA  TE  MA
TI  SI  BE  BO  DO  IT  IS  GO  OD  OB

Bana bu kadar RAM içeren bir makine getirin ve konuşalım.
ekmek kutusu

Karenin simetrilerini hesaba katmak için zar permütasyonlarını 8'e bölmeniz gerekir. Ayrıca, (4 ^ 4) (5 ^ 6) (6 ^ 5) nasıl elde edilir? 2 ^ 79'un biraz üzerinde toplam arama alanı için (4 ^ 3) (5 ^ 7) (6 ^ 6) yapıyorum.
Peter Taylor

@Peter Taylor: Haklısın. Eşsiz yüzleri yaparken bire kadar silmiş olmalıyım. Sanırım 83 eşsiz yüz olduğu konusunda hemfikiriz (kalıpta tekrarlar hariç). Tekrarlamadan 16 tanesini seçin. '83 x 82 x 81 x 80 x 79 x 78 x 77 x 76 x 75 x 74 x 73 x 72 x 71 x 70 x 69 x 68 'Yaklaşık: 1.082 x (10 ^ 30) ==> ~ 2 ^ 100 Ne hiç olmadığı kadar büyük bir sayı.
Adam Speight

2
@AdamSpeight Başlangıçta sözlüğü bir hashtable olarak saklamak hakkındaki yorumunuzun sadece bir şaka olduğunu varsaydım ve bu yüzden temelde onu görmezden geldim. Özür dilerim. Uygun bir yanıt şöyle olabilir: Aslında, bir karma tablo bu sorun için berbat bir veri yapısıdır. Sadece "X geçerli bir sözcük mü?" Sorusunu cevaplayabilir, bu yüzden kelimeleri bulmak için tüm olası dizeleri oluşturmanız gerekir. Bir DAWG size "X geçerli bir kelimenin öneki mi? Ve eğer öyleyse hangi harfleri takip edebilir?" Bu, arama alanını toplam boyutunun küçük bir kısmına göre ayarlamanıza olanak tanır.
ekmek kutusu

Hashtable, hiçbir zaman tam kelimeler olmayacak kelime parçalarını kaldırmanızı önlediğinden korkunçtur (dicttree.ceiling (fragment) .startsWith (fragment)). Herhangi bir boggle tahtasında milyonlarca potansiyel kelime olmasına rağmen, 2-3 harf bir araya getirildikten sonra büyük bir kısmını dışarı atabilirsiniz. Ağaçta gezinme, karma aramadan daha yavaştır, ancak ağaç, geri izleme yoluyla işin yüzde 99'dan fazlasını azaltmanıza izin verir.
Jim W

1

Girişim bitti burada bir pano arama başına 30ms (2 çekirdek makine üzerinde, daha fazla çekirdekli daha hızlı olmalıdır) ~ Dream.In.Code üzerinde


Hala içine bakarak, ama o sayfada ilk bağlantı eksik :in http://. ;-)
Gaffi

Çok hoş. Bunu kendim için bir öğrenme deneyimi olarak çalmaya çalışacağım. .NETiçin VBAdeğil çok zor.
Gaffi

Cevabı, ISPELL listesini çalıştırırken (SOWPODS değil) ortalama puanınızı içerecek şekilde güncellemeyi düşünür müsünüz? Bu zorluğun bir parçası ve sonuçlarınızın breadbox'larla nasıl karşılaştırıldığını görmek istiyorum.
Gaffi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.