최고 점수 Boggle 보드


16

나는 이 (현재 없어진) 질문에 대한 답변을 보는 데 관심 있었지만 결코 수정 / 개선되지 않았습니다.

6면의 Boggle 주사위 세트 ( 이 질문 에서 도난당한 구성)가 주어지면 2 분의 처리 시간으로 어떤 보드 구성이 가장 높은 점수를 얻을 수 있는지 결정하십시오. (즉, 어느 위치에서 어느 쪽의 주사위가 가장 큰 득점 단어 풀을 허용합니까?)


객관적인

  • 코드는 2 분 (120 초) 이상 실행되지 않아야합니다. 이때 자동으로 실행을 중지하고 결과를 인쇄해야합니다.

  • 최종 챌린지 점수는 프로그램의 5 회 평균 보글 점수입니다.

    • 동점 일 경우에는 알고리즘이 더 많은 단어를 찾은 사람이 승자가됩니다 .
    • 여전히 동점이있는 경우, 긴 (8+) 단어를 찾은 알고리즘이 승자가됩니다 .

규칙 / 제약

  • 이것은 코드 도전입니다. 코드 길이는 관련이 없습니다.

  • 단어 목록에 대해서는 이 링크 를 참조하십시오 (사용 ISPELL "english.0"목록-SCOWL 목록에 매우 일반적인 단어가 없음).

    • 이 목록은 원하는 방식으로 코드에서 참조 / 가져 오기 / 읽기를 할 수 있습니다.
    • 정규 표현식과 일치하는 단어 만 ^([a-pr-z]|qu){3,16}$계산됩니다. (단, 소문자, 3-16 자, qu 만 단위로 사용해야합니다.)
  • 단어는 하나의 주사위를 한 단어에 두 번 이상 사용하지 않고 인접한 글자 (가로, 세로 및 대각선)를 연결하여 올바른 순서로 단어를 철자하여 구성됩니다.

    • 단어는 3 글자 이상이어야합니다. 짧은 단어는 점수를 얻지 못합니다.
    • 주사위가 아닌 복제 된 글자를 사용할 수 있습니다.
    • 보드의 한쪽에서 다른쪽으로 가장자리에 걸쳐있는 단어는 허용되지 않습니다.
  • 최종 Boggle ( 챌린지 아님) 점수는 찾은 모든 단어에 대한 총점 값입니다.

    • 각 단어에 지정된 포인트 값은 단어의 길이를 기준으로합니다. (아래 참조)
    • 일반 Boggle 규칙은 다른 플레이어가 찾은 단어를 공제 / 할인합니다. 여기에 다른 플레이어가 참여하지 않고 발견 된 모든 단어가 총 점수에 포함된다고 가정합니다.
    • 그러나 같은 그리드에서 두 번 이상 발견 된 단어는 한 번만 계산해야합니다.
  • 기능 / 프로그램은 찾기 최적의 배열을; 미리 지정된 목록을 하드 코딩하면 안됩니다.

  • 당신의 결과는 이상적인 게임 보드의 4x4 그리드, 그 보드에 대해 발견 된 모든 단어의 목록, 그리고 그 단어와 일치하는 Boggle 점수 여야합니다.


다이 구성

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

표준 병 스코어링 테이블

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.

예제 출력

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

CUT
THE
LUCK
HEX
....

140 points

더 자세한 설명이 필요하면 문의하십시오!


2
목표를 표준화하기 위해 사전을 제공하는 것을 선호합니다. 또한 간단한 Google 검색으로 다음과 같이 새로운 아이디어가 아닙니다. :) 내가 본 가장 높은 점수는 4527( 1414총 단어)입니다. ai.stanford.edu/~chuongdo/boggle/index.html
mellamokb

4
이 세기를 끝내기 위해 프로그램이 필요합니까?
피터 테일러

1
@GlitchMr 영어에서 Q는 일반적으로 U와 함께 만 사용됩니다. Boggle은 두 문자를 하나의 장치와 동일한 주사위에 놓음으로써이를 설명합니다.
Gaffi

1
단어 목록 사양이 명확하지 않습니다. english.0에 나열된 단어들만 소문자로 세고 있습니까? (표준 단어 게임 규칙에는 약어 / 초기 법 및 고유 명사 제외)
피터 테일러

1
나는 정규 표현식을 생각하고 있었다 ^([a-pr-z]|qu){3,16}$(qu와 함께 3 글자 단어를 잘못 제외하지만 아무것도 없다).
피터 테일러

답변:


9

C, 평균 500+ 1500 1750 점

이것은 버전 2에 비해 상대적으로 약간 개선 된 것입니다 (이전 버전에 대한 참고 사항은 아래 참조). 두 부분이 있습니다. 첫째 : 풀에서 보드를 무작위로 선택하는 대신, 프로그램은 풀의 모든 보드를 차례로 반복하여 각 보드를 차례로 사용하여 풀의 맨 위로 돌아가 반복합니다. (이 반복이 진행되는 동안 풀이 수정되고 있기 때문에 여전히 두 번 연속으로 선택되는 보드가 있거나 더 나빠질 수 있지만 심각한 문제는 아닙니다.) 두 번째 변경은 풀이 변경 될 때 프로그램이 추적한다는 것입니다. 풀의 내용을 개선하지 않고 프로그램이 너무 오래 지속되면 검색이 "중지 된"것으로 판별하고 풀을 비운 후 새 검색으로 다시 시작합니다. 2 분이 끝날 때까지이 작업을 계속합니다.

처음에는 1500 포인트 범위를 초과하는 휴리스틱 검색을 사용할 것이라고 생각했습니다. 4527 포인트 보드에 대한 @mellamokb의 의견으로 개선의 여지가 충분하다고 가정했습니다. 그러나 우리는 상대적으로 작은 단어 목록을 사용하고 있습니다. 4527 포인트 보드는 YAWL을 사용하여 점수를 매겼습니다. YAWL은 가장 포괄적 인 단어 목록으로 공식 미국 글자 맞추기 단어 목록보다 훨씬 큽니다. 이 점을 염두에두고 프로그램에서 찾은 보드를 다시 검토하고 1700 이상으로 제한된 보드 세트가있는 것으로 나타났습니다. 예를 들어, 1726 점을 얻은 보드를 발견 한 여러 런이 있었지만 항상 같은 보드였습니다 (회전 및 반사 무시).

또 다른 테스트로 YAWL을 사전으로 사용하여 프로그램을 실행했으며 약 12 ​​회 실행 후 4527 포인트 보드를 찾았습니다. 이 점을 감안할 때, 내 프로그램이 이미 검색 공간의 상한에 있다고 가정하고 있으므로 계획했던 재 작성은 약간의 이득을 얻기 위해 추가 복잡성을 초래할 것입니다.

내 프로그램이 english.0단어 목록을 사용하여 찾은 5 개의 최고 점수 보드 목록은 다음과 같습니다 .

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

내 생각은 1772 "grep board"(내가 부르기로했듯이)는 531 단어 로이 단어 목록에서 가능한 최고 점수 보드입니다. 내 프로그램의 2 분 런 중 50 % 이상이이 보드로 끝납니다. 또한 프로그램을 더 잘 찾지 않고 밤새 프로그램을 실행했습니다. 따라서 점수가 더 높은 보드가 있으면 프로그램의 검색 기술을 무너 뜨릴 수있는 측면이 있어야합니다. 예를 들어, 레이아웃에 대한 모든 가능한 작은 변경으로 인해 총 점수가 크게 떨어질 수있는 보드는 내 프로그램에서 결코 발견하지 못할 수 있습니다. 내 직감은 그러한 보드가 존재하지 않을 가능성이 높다는 것입니다.

#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;
}

버전 2 참고 사항 (6 월 9 일)

다음은 코드의 초기 버전을 점프 포인트로 사용하는 한 가지 방법입니다. 이 버전의 변경 사항은 100 줄 미만으로 구성되어 있지만 평균 게임 점수는 3 배입니다.

이 버전에서는 프로그램이 지금까지 생성 한 N 개의 최고 점수 보드로 구성된 후보 풀을 유지합니다. 새 보드가 생성 될 때마다 보드가 풀에 추가되고 풀에서 가장 낮은 점수의 보드가 제거됩니다 (이 점수가 이미 존재하는 것보다 낮은 경우 방금 추가 된 보드 일 수 있음). 풀은 처음에 임의로 생성 된 보드로 채워진 후 프로그램 실행 전체에서 일정한 크기를 유지합니다.

프로그램의 메인 루프는 풀에서 임의의 보드를 선택하고 변경하여이 새로운 보드의 점수를 결정한 다음 풀에 넣습니다 (만약 점수가 충분한 경우). 이러한 방식으로 프로그램은 지속적으로 고득점 보드를 개선하고 있습니다. 주요 활동은 단계적으로 점진적으로 개선하는 것이지만 풀의 크기는 프로그램이 보드 점수를 향상시키기 전에 보드 점수를 일시적으로 악화시키는 다단계 개선을 찾을 수있게합니다.

일반적으로이 프로그램은 좋은 로컬 최대 값을 빠르게 찾은 후에 더 나은 최대 값을 찾기에는 너무 먼 것으로 보입니다. 그리고 다시 한 번 10 초 이상 프로그램을 실행해야 할 점은 거의 없습니다. 예를 들어 프로그램이이 상황을 감지하고 새로운 후보 풀을 사용하여 새로 검색을 시작하면이를 개선 할 수 있습니다. 그러나 이것은 조금만 증가 할 것입니다. 적절한 휴리스틱 검색 기술이 더 나은 탐색 방법 일 것입니다.

(Side note :이 버전은 초당 약 5k 보드를 생성하는 것을 보았습니다. 첫 번째 버전은 일반적으로 초당 20k 보드를 수행했기 때문에 처음에 관심이 있었지만 프로파일 링을 수행 할 때 단어 목록을 관리하는 데 추가 시간이 소요되었음을 알게되었습니다. 다시 말해서 프로그램은 보드 당 더 많은 단어를 찾는 것이 전부 였기 때문에 단어 목록을 관리하기 위해 코드를 변경하는 것을 고려했지만이 프로그램은 할당 된 120 초 중 10 개만 사용한다는 점에서 최적화는 매우 시기상조입니다.)

버전 1 참고 사항 (6 월 2 일)

이것은 매우 간단한 솔루션입니다. 모든 것이 무작위 보드를 생성 한 다음 10 초 후에 가장 높은 점수를 얻은 보드를 출력합니다. (문제 사양에서 허용하는 추가 110 초가 일반적으로 기다릴만한 가치가있는 최종 솔루션을 개선하지 못하기 때문에 기본값은 10 초입니다.) 따라서 멍청합니다. 그러나보다 지능적인 검색을위한 좋은 출발점을 마련 할 수있는 모든 인프라가 갖추어져 있으며, 마감일 전에이를 사용하려는 사람은 그렇게 할 것을 권장합니다.

프로그램은 사전을 트리 구조로 읽어서 시작합니다. (양식은 가능한 한 최적화되지는 않았지만 이러한 목적을 달성하기에 충분합니다.) 다른 기본 초기화 후 보드 생성 및 스코어링이 시작됩니다. 이 프로그램은 내 컴퓨터에서 초당 약 20k 보드를 검사하고 약 200k 보드 후에 임의 접근 방식이 건조하기 시작합니다.

한 번에 하나의 보드 만 실제로 평가되므로 스코어링 데이터는 전역 변수에 저장됩니다. 이를 통해 재귀 함수에 인수로 전달해야하는 상수 데이터의 양을 최소화 할 수 있습니다. (이것은 일부 사람들에게 두드러기를 줄 것이라고 확신하며 그들에게 사과합니다.) 단어 목록은 이진 검색 트리로 저장됩니다. 찾은 모든 단어는 단어 목록에서 찾아야하므로 중복 단어는 두 번 계산되지 않습니다. 단어 목록은 증발 과정 중에 만 필요하므로 점수를 찾은 후에는 삭제됩니다. 따라서 프로그램이 끝날 때 선택한 보드는 다시 점수를 매겨 단어 목록을 인쇄 할 수 있습니다.

재미있는 사실 : 무작위로 생성 된 Boggle 보드의 평균 점수 english.0는 61.7 점입니다.


분명히, 나는 내 자신의 효율성을 향상시켜야합니다. :-)
Gaffi

내 유전자 접근 방식은 약 200k 보드를 생성하는 약 700-800 포인트를 얻으므로 다음 세대를 생산하는 방식에서 나보다 훨씬 나은 것을 분명히하고 있습니다.
피터 테일러

내 자신의 트리 구조는 지금까지 마스터 단어 목록에 대해서만 구현되었으며, 작동하고 보드를 검증 할 수 있지만 시스템 메모리를 멈 춥니 다. 조기 종료). 이것은 분명히 내 자신의 잘못이지만 나는 노력하고 있습니다! 편집 : 이미 수정되었습니다! ;-)
Gaffi 2016

@PeterTaylor 유전자 알고리즘을 시도하는 것에 대해 생각했지만 두 보드를 결합하는 그럴듯한 메커니즘을 생각할 수 없었습니다. 어떻게 지내세요? 보드의 각 슬롯에 대해 부모를 무작위로 선택합니까?
breadbox

나는 보드 상태를 주사위의 순열과 주사위에 보이는면으로 나누었다. 순열 교차의 경우 cs.colostate.edu/~genitor/1995/permutations.pdf의 "순서 교차 1"을 사용 하고 얼굴 교차의 경우 분명합니다. 그러나 구현할 시간을 찾아야하는 완전히 다른 접근법에 대한 아이디어가 있습니다.
피터 테일러

3

VBA (현재 80-110 포인트 범위, 미완성)

여기 내 작업 과정이 있지만 가능한 한 멀리 떨어져 있습니다. 많은 테스트 실행 후 모든 보드에서 찾은 내 절대 최고 점수는 약 120입니다. 여전히 더 나은 일반적인 정리가 필요하며 여러 곳에서 더 많은 효율성을 얻을 것이라고 확신합니다.

  • 2012.05.09 :
    • 원본 게시
  • 2012.05.10-2012.05.18 :
    • 스코어링 알고리즘 개선
    • 길 찾기 로직 개선
  • 2012.06.07-2012.06.12 :
    • 단어 제한을 8에서 6으로 줄였습니다. 더 작은 단어로 더 많은 보드를 허용합니다. 평균 점수가 약간 개선 된 것으로 보입니다. (1 ~ 2에 대한 런당 10-15 정도의 보드 확인)
    • breadbox의 제안에 따라 단어 목록을 저장할 트리 구조를 만들었습니다. 이렇게하면 보드의 단어에 대한 백엔드 검사 속도가 크게 향상됩니다.
    • 나는 최대 단어 크기 (속도 대 점수)를 변경하면서 놀았으며 5 또는 6이 나에게 더 좋은 옵션인지 아직 결정하지 않았습니다. 6 개는 100-120 개의 전체 보드를 확인한 반면 5 개는 500-1000을 나타냅니다 (둘 다 지금까지 제공된 다른 예보다 훨씬 낮습니다).
    • 문제 : 연속해서 여러 번 실행 한 후 프로세스 속도가 느려지기 때문에 관리 할 메모리가 여전히 남아 있습니다.

이것은 아마도 여러분 중 일부에게는 끔찍한 것처럼 보이지만 WIP입니다. 나는 건설적인 비판에 매우 개방적입니다 !몸이 길어서 미안해


주사위 클래스 모듈 :

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

트리 클래스 모듈 :

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 클래스 모듈 :

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

메인 모듈 :

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
코드를 살펴 보지는 않았지만 50 포인트는 엄청나게 낮습니다. 점수가 1000 이상인 무작위로 생성 된 보드를 연주했습니다 (SOWPODS 사용-제공된 단어 목록이 덜 광범위 할 수 있음). 부호 오류를 확인하고 싶을 수도 있습니다!
피터 테일러

@PeterTaylor 제안 해 주셔서 감사합니다. 나는 점수가 너무 낮다는 것을 알고 있으며, 문제의 일부는 명백한 단어가 빠진 것을 볼 수 있다는 사실에 있습니다.
Gaffi

@PeterTaylor 또한, 기록을 위해, 나는 아직 아무도 찌르지 않았기 때문에 최종 제품을 기다리지 않고 지속적으로 진행 상황을 게시하고 있습니다. 나는 그 일이 일어날 때까지 질문을 어느 정도 살아있게 유지하고 싶습니다.
Gaffi

또한 이것이 가장 빠른 컴퓨터에서 실행되고 있지 않으므로 도움이되지 않습니다.
Gaffi

1
@Gaffi 점수를 계산하는 데 10 초? 9.999 초가 너무 깁니다. 코드를 다시 생각해야합니다. 단어 목록을 나무로 바꾸지 않으려면 최소한 다음과 같이하십시오. 두 글자 접두사를 모두 목록으로 만드십시오. 그런 다음 보드의 경로를 따라갈 때 처음 두 글자가 목록에 없으면 가능한 경로의 하위 트리 전체를 건너 뜁니다. 다시 한 번 전체 트리를 작성하는 것이 가장 좋지만 두 문자 접두사 목록이 도움이되며 매우 저렴합니다.
breadbox

2

검색 공간의 크기를 빠르게 살펴보십시오.

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

각 다이에서 반복을 배제하기 위해 감소.

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

@breadbox는 사전을 해시 테이블 O (1) 검사로 저장합니다.

편집하다

Best Board (지금까지 목격했습니다)

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

RAM이 많은 기계를 가져 오면 이야기하겠습니다.
breadbox

제곱의 대칭을 설명하기 위해 주사위 순열을 8로 나눕니다. 또한 (4 ^ 4) (5 ^ 6) (6 ^ 5)는 어떻게 얻습니까? 나는 2 ^ 79 이상의 총 선원 공간을 위해 (4 ^ 3) (5 ^ 7) (6 ^ 6)으로 만듭니다.
피터 테일러

@ 피터 테일러 : 당신이 맞아요. 나는 독특한 얼굴을 할 때 일대 다를 삭제해야합니다. 우리는 83 개의 독특한 얼굴이 존재한다는 것에 동의 할 수 있다고 생각합니다. 반복하지 않고 16을 선택하십시오. '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 '약 : 1.082 x (10 ^ 30) ==> ~ 2 ^ 100 지금까지는 큰 숫자입니다.
Adam Speight

2
@AdamSpeight 나는 원래 사전을 해시 테이블로 저장하는 것에 대한 귀하의 의견이 농담이라고 가정했기 때문에 기본적으로 그것을 무시했습니다. 사과드립니다. 적절한 응답은 다음과 같습니다. 실제로 해시 테이블은 이 문제에 대한 데이터 구조 가 거대 합니다. "X는 유효한 단어입니까?"라는 질문에만 답할 수 있으므로 단어를 찾으려면 가능한 모든 문자열을 작성해야합니다. DAWG를 사용하면 "X는 유효한 단어 의 접두사 입니까? 그렇다면 어떤 문자가 뒤에 올 수 있습니까?" 이를 통해 검색 공간을 전체 크기의 작은 부분으로 정리할 수 있습니다.
breadbox 2016 년

해시 테이블은 완전한 단어가 될 수없는 단어 조각을 컬링하는 것을 막기 때문에 끔찍합니다 (dicttree.ceiling (fragment) .startsWith (fragment)). 주어진 boggle 보드에는 수백만 개의 잠재적 인 단어가 있지만 2-3 글자가 함께 쓰인 후에는 상당 부분을 버릴 수 있습니다. 트리 탐색은 해시 테이블 조회보다 느리지 만 트리 추적을 통해 역 추적을 통해 작업의 99 % 이상을 회피 할 수 있습니다.
Jim W

1

내 항목은 끝났다 여기 보드 검색 당 30ms의 (2 코어 시스템에서이, 더 많은 코어와 더 빨리해야한다) ~ Dream.In.Code에


그럼에도 불구하고 그것으로보고 있지만, 해당 페이지의 첫 번째 링크는없는 :의를 http://. ;-)
Gaffi 2016 년

아주 좋아요 나는 그것을 학습 경험으로 도용하려고 노력할 것입니다. .NET에가 VBA아닙니다 너무 열심히.
Gaffi

ISPELL 목록 (SOWPODS 아님)을 실행할 때 평균 점수를 포함하도록 답변을 업데이트 하시겠습니까? 그것은 도전의 일부이며, 결과가 빵 상자와 어떻게 비교되는지 관심이 있습니다.
Gaffi
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.