Bảng chấm điểm tốt nhất


16

Tôi đã quan tâm đến việc xem các câu trả lời cho câu hỏi này (hiện không còn tồn tại) , nhưng nó chưa bao giờ được sửa chữa / cải thiện.

Đưa ra một bộ xúc xắc Boggle 6 mặt (cấu hình bị đánh cắp từ câu hỏi này ), xác định trong hai phút thời gian xử lý cấu hình bảng nào sẽ cho phép điểm cao nhất có thể. (tức là con xúc xắc nào ở vị trí nào hướng lên trên cho phép nhóm từ ghi điểm lớn nhất?)


MỤC TIÊU

  • Mã của bạn sẽ chạy không quá 2 phút (120 giây). Tại thời điểm đó, nó sẽ tự động dừng chạy và in kết quả.

  • Điểm thử thách cuối cùng sẽ là điểm số trung bình của Boggle trong 5 lần chạy của chương trình.

    • Trong trường hợp hòa, người chiến thắng sẽ là thuật toán nào tìm được nhiều từ hơn .
    • Trong trường hợp vẫn còn một sự ràng buộc, người chiến thắng sẽ là bất kỳ thuật toán nào tìm thấy nhiều từ (8+) dài hơn .

QUY TẮC / XÂY DỰNG

  • Đây là một thách thức mã; chiều dài mã là không liên quan.

  • Vui lòng tham khảo liên kết này để biết danh sách từ ( ISPELL "english.0"danh sách sử dụng - danh sách SCOWL thiếu một số từ khá phổ biến).

    • Danh sách này có thể được tham chiếu / nhập / đọc trong mã của bạn theo bất kỳ cách nào bạn muốn.
    • Chỉ những từ phù hợp với regex ^([a-pr-z]|qu){3,16}$sẽ được tính. (Chỉ các chữ cái viết thường, 3-16 ký tự, qu phải được sử dụng làm đơn vị.)
  • Các từ được hình thành bằng cách liên kết các chữ cái liền kề (ngang, dọc và chéo) để đánh vần các từ theo đúng thứ tự, mà không sử dụng một lần chết nhiều lần trong một từ.

    • Các từ phải có 3 chữ cái hoặc dài hơn; từ ngắn hơn sẽ không kiếm được điểm.
    • Chữ trùng lặp được chấp nhận, chỉ không xúc xắc.
    • Các từ trải dài từ các cạnh / chéo từ một bên của bảng sang bên kia không được phép.
  • Điểm số cuối cùng của Boggle ( không phải thử thách ) là tổng giá trị điểm cho tất cả các từ được tìm thấy.

    • Giá trị điểm được gán cho mỗi từ dựa trên độ dài của từ. (xem bên dưới)
    • Các quy tắc Boggle thông thường sẽ khấu trừ / giảm giá các từ được tìm thấy bởi người chơi khác. Giả sử ở đây không có người chơi nào khác tham gia và tất cả các từ được tìm thấy đều được tính vào tổng số điểm.
    • Tuy nhiên, các từ được tìm thấy nhiều lần trong cùng một lưới chỉ nên được tính một lần.
  • Chức năng / chương trình của bạn phải TÌM sắp xếp tối ưu; chỉ đơn giản là mã hóa cứng một danh sách định trước sẽ không làm.

  • Đầu ra của bạn phải là một lưới 4 x 4 của bảng trò chơi lý tưởng của bạn, một danh sách tất cả các từ tìm thấy cho bảng đó và điểm số Boggle để khớp với các từ đó.


CẤU HÌNH DIE

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

BẢNG CHUẨN BOGGLE BORGLE

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.

VÍ DỤ ĐẦU RA

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

CUT
THE
LUCK
HEX
....

140 points

Nếu cần làm rõ thêm, xin vui lòng hỏi!


2
Tôi muốn có một từ điển được cung cấp để chuẩn hóa mục tiêu. Cũng lưu ý rằng đây không phải là một ý tưởng mới, vì một tìm kiếm google đơn giản sẽ tiết lộ :) Điểm số cao nhất tôi thấy là 4527( 1414tổng số từ), được tìm thấy ở đây: ai.stanford.edu/~chuongdo/boggle/index.html
mellamokb

4
Là chương trình cần thiết để chấm dứt thế kỷ này?
Peter Taylor

1
@GlitchMr Trong tiếng Anh, Q thường chỉ được sử dụng với các tài khoản U. Boggle cho việc này bằng cách đặt hai chữ cái trên cùng một khuôn là một đơn vị.
Gaffi

1
Các đặc điểm kỹ thuật danh sách từ là không rõ ràng. Bạn chỉ đếm những từ được liệt kê trong tiếng Anh.0 bằng chữ thường? (Quy tắc trò chơi từ tiêu chuẩn loại trừ chữ viết tắt / chữ viết tắt và danh từ riêng).
Peter Taylor

1
Tôi đã suy nghĩ regex ^([a-pr-z]|qu){3,16}$(sẽ loại trừ không chính xác các từ 3 chữ cái với qu, nhưng không có từ nào).
Peter Taylor

Câu trả lời:


9

C, trung bình 500+ 1500 1750 điểm

Đây là một cải tiến tương đối nhỏ so với phiên bản 2 (xem bên dưới để biết ghi chú về các phiên bản trước). Có hai phần. Đầu tiên: Thay vì chọn các bảng ngẫu nhiên từ nhóm, chương trình hiện lặp lại trên mỗi bảng trong nhóm, sử dụng lần lượt từng bảng trước khi quay lại đỉnh của nhóm và lặp lại. (Vì nhóm đang được sửa đổi trong khi lặp lại này xảy ra, vẫn sẽ có các bảng được chọn hai lần liên tiếp hoặc tệ hơn, nhưng đây không phải là vấn đề nghiêm trọng.) Thay đổi thứ hai là chương trình hiện theo dõi khi nhóm thay đổi và nếu chương trình diễn ra quá lâu mà không cải thiện nội dung của nhóm, nó sẽ xác định rằng tìm kiếm đã bị "đình trệ", làm trống hồ bơi và bắt đầu lại với một tìm kiếm mới. Nó tiếp tục làm điều này cho đến khi hai phút là hết.

Ban đầu tôi đã nghĩ rằng tôi sẽ sử dụng một số loại tìm kiếm heuristic để vượt ra ngoài phạm vi 1500 điểm. Nhận xét của @ mellamokb về một bảng 4527 điểm khiến tôi cho rằng có nhiều chỗ để cải thiện. Tuy nhiên, chúng tôi đang sử dụng một danh sách từ tương đối nhỏ. Bảng 4527 điểm đã được chấm điểm bằng YAWL, đây là danh sách từ bao gồm nhiều nhất ngoài đó - nó thậm chí còn lớn hơn cả danh sách từ chính thức của Scrabble Hoa Kỳ. Với suy nghĩ này, tôi đã kiểm tra lại các bảng mà chương trình của tôi đã tìm thấy và nhận thấy rằng dường như có một bộ bảng giới hạn trên 1700 hoặc hơn. Vì vậy, ví dụ, tôi đã có nhiều lần chạy đã phát hiện ra một bảng ghi điểm 1726, nhưng nó luôn luôn là cùng một bảng được tìm thấy (bỏ qua các phép quay và phản xạ).

Như một thử nghiệm khác, tôi đã chạy chương trình của mình bằng cách sử dụng YAWL làm từ điển và nó đã tìm thấy bảng 4527 điểm sau khoảng một chục lần chạy. Vì điều này, tôi giả thuyết rằng chương trình của tôi đã ở giới hạn trên của không gian tìm kiếm, và do đó, việc viết lại mà tôi đang lên kế hoạch sẽ giới thiệu thêm độ phức tạp để thu được rất ít.

Dưới đây là danh sách năm bảng điểm cao nhất mà chương trình của tôi đã tìm thấy bằng cách sử dụng english.0danh sách từ:

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

Tôi tin rằng "bảng grep" năm 1772 (như tôi đã gọi nó), với 531 từ, là bảng có điểm cao nhất có thể với danh sách từ này. Hơn 50% thời lượng hai phút của chương trình của tôi kết thúc với bảng này. Tôi cũng đã để chương trình của mình chạy qua đêm mà không tìm thấy gì tốt hơn. Vì vậy, nếu có một bảng điểm cao hơn, nó có thể sẽ phải có một số khía cạnh đánh bại kỹ thuật tìm kiếm của chương trình. Ví dụ, một bảng trong đó mọi thay đổi nhỏ có thể xảy ra đối với bố cục gây ra sự sụt giảm lớn trong tổng số điểm, chẳng hạn, có thể không bao giờ được phát hiện bởi chương trình của tôi. Linh cảm của tôi là một bảng như vậy rất khó tồn tại.

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

Ghi chú cho phiên bản 2 (ngày 9 tháng 6)

Đây là một cách để sử dụng phiên bản ban đầu của mã của tôi làm điểm xuất phát. Các thay đổi của phiên bản này bao gồm ít hơn 100 dòng, nhưng tăng gấp ba điểm số trò chơi trung bình.

Trong phiên bản này, chương trình duy trì một "nhóm" các ứng cử viên, bao gồm N bảng điểm cao nhất mà chương trình đã tạo ra cho đến nay. Mỗi khi một bảng mới được tạo, nó sẽ được thêm vào nhóm và bảng có điểm thấp nhất trong nhóm sẽ bị xóa (rất có thể là bảng vừa được thêm vào, nếu điểm của nó thấp hơn những gì đã có). Nhóm ban đầu được lấp đầy với các bảng được tạo ngẫu nhiên, sau đó nó giữ kích thước không đổi trong suốt quá trình chạy chương trình.

Vòng lặp chính của chương trình bao gồm việc chọn một bảng ngẫu nhiên từ nhóm và thay đổi nó, xác định điểm số của bảng mới này và sau đó đưa nó vào nhóm (nếu nó đủ điểm). Theo cách này, chương trình liên tục cải tiến các bảng điểm cao. Hoạt động chính là thực hiện các cải tiến từng bước, tăng dần, nhưng kích thước của nhóm cũng cho phép chương trình tìm các cải tiến nhiều bước tạm thời làm cho điểm của bảng trở nên tồi tệ hơn trước khi có thể làm cho nó tốt hơn.

Thông thường, chương trình này tìm thấy một mức tối đa cục bộ khá nhanh, sau đó có lẽ là bất kỳ mức tối đa tốt hơn nào là quá xa để tìm thấy. Và một lần nữa, có một điểm nhỏ để chạy chương trình dài hơn 10 giây. Điều này có thể được cải thiện bằng cách ví dụ như chương trình phát hiện tình huống này và bắt đầu tìm kiếm mới với nhóm ứng viên mới. Tuy nhiên, điều này sẽ chỉ tăng một chút. Một kỹ thuật tìm kiếm heuristic thích hợp có thể sẽ là một con đường khám phá tốt hơn.

(Lưu ý bên lề: Tôi thấy rằng phiên bản này đã tạo ra khoảng 5k bảng / giây. Vì phiên bản đầu tiên thường làm 20k bảng / giây, ban đầu tôi lo ngại. Tuy nhiên, khi tôi tìm hiểu thêm rằng tôi đã dành thời gian để quản lý danh sách từ. Nói cách khác, đó hoàn toàn là do chương trình tìm thấy rất nhiều từ trên mỗi bảng. Về vấn đề này, tôi đã cân nhắc việc thay đổi mã để quản lý danh sách từ, nhưng cho rằng chương trình này chỉ sử dụng 10 trong số 120 giây được phân bổ, như vậy tối ưu hóa sẽ rất sớm.)

Ghi chú cho phiên bản 1 (ngày 2 tháng 6)

Đây là một giải pháp rất, rất đơn giản. Tất cả những gì nó tạo ra các bảng ngẫu nhiên, và sau 10 giây, nó xuất ra bảng có số điểm cao nhất. (Tôi mặc định là 10 giây vì thêm 110 giây được cho phép bởi đặc tả vấn đề thường không cải thiện giải pháp cuối cùng đủ để đáng chờ đợi.) Vì vậy, nó cực kỳ ngu ngốc. Tuy nhiên, nó có tất cả các cơ sở hạ tầng để tạo điểm khởi đầu tốt cho tìm kiếm thông minh hơn và nếu có ai muốn sử dụng nó trước thời hạn, tôi khuyến khích họ làm như vậy.

Chương trình bắt đầu bằng cách đọc từ điển thành một cấu trúc cây. (Biểu mẫu không hoàn toàn được tối ưu hóa như có thể, nhưng nó không đủ tốt cho các mục đích này.) Sau một số khởi tạo cơ bản khác, sau đó nó bắt đầu tạo bảng và ghi điểm. Chương trình kiểm tra khoảng 20k bảng mỗi giây trên máy của tôi và sau khoảng 200 nghìn bảng, phương pháp ngẫu nhiên bắt đầu cạn.

Vì chỉ có một bảng thực sự được đánh giá tại bất kỳ thời điểm nào, dữ liệu cho điểm được lưu trữ trong các biến toàn cục. Điều này cho phép tôi giảm thiểu lượng dữ liệu không đổi phải được truyền dưới dạng đối số cho các hàm đệ quy. (Tôi chắc chắn rằng điều này sẽ cung cấp cho một số người tổ ong và tôi xin lỗi.) Danh sách từ được lưu trữ dưới dạng cây tìm kiếm nhị phân. Mỗi từ được tìm thấy phải được tra cứu trong danh sách từ, để các từ trùng lặp không được tính hai lần. Tuy nhiên, danh sách từ chỉ cần thiết trong quá trình sơ tán, vì vậy nó bị loại bỏ sau khi tìm thấy điểm. Do đó, vào cuối chương trình, bảng được chọn phải được ghi lại một lần nữa, để có thể in ra danh sách từ.

Sự thật thú vị: Điểm trung bình cho một bảng Boggle được tạo ngẫu nhiên, như được ghi bởi english.0, là 61,7 điểm.


Rõ ràng, tôi cần nâng cao hiệu quả của chính mình. :-)
Gaffi

Phương pháp di truyền của tôi nhận được khoảng 700-800 điểm tạo ra khoảng 200 nghìn bảng, vì vậy rõ ràng bạn đang làm điều gì đó tốt hơn tôi nhiều so với cách bạn tạo ra thế hệ tiếp theo.
Peter Taylor

Cấu trúc cây của riêng tôi, chỉ được triển khai cho danh sách từ chính cho đến nay, trong khi nó hoạt động và cho phép tôi xác nhận các bảng, nó làm mất bộ nhớ hệ thống của tôi (chủ động chậm đến mức phải mất một khoảng thời gian đáng kể để buộc quá trình chấm dứt sớm). Đây chắc chắn là lỗi của riêng tôi, nhưng tôi đang làm việc với nó! Chỉnh sửa: Đã sửa! ;-)
Gaffi

@PeterTaylor Tôi đã nghĩ về việc thử một thuật toán di truyền, nhưng tôi không thể nghĩ ra một cơ chế hợp lý để kết hợp hai bảng. Làm thế nào bạn đang làm điều đó? Bạn đang chọn ngẫu nhiên cha mẹ cho mỗi khe trên bảng?
hộp bánh mì

Tôi chia trạng thái bảng thành hoán vị xúc xắc và các mặt hiển thị trên súc sắc. Đối với crossover hoán vị, tôi sử dụng "crossover order 1" từ cs.colostate.edu/~genitor/1995/permutations.pdf và đối với crossover mặt tôi làm điều hiển nhiên. Nhưng tôi có một ý tưởng cho một cách tiếp cận hoàn toàn khác mà tôi cần tìm thời gian để thực hiện.
Peter Taylor

3

VBA (trung bình hiện tại dao động 80-110 điểm, chưa hoàn thành)

Đây là quá trình làm việc của tôi, nhưng nó còn lâu mới có thể; Điểm số tuyệt đối tốt nhất của tôi được tìm thấy trên bất kỳ bảng nào sau nhiều lần chạy thử là khoảng 120. Vẫn cần có một số dọn dẹp tổng quát tốt hơn và tôi chắc chắn sẽ có nhiều hiệu quả hơn để đạt được ở một số nơi.

  • 2012.05 / 09:
    • Đăng bài gốc
  • 2012.05.10 - 2012.05.18:
    • Cải thiện thuật toán chấm điểm
    • Cải thiện logic tìm đường
  • 2012,06 - 2012,06.12 :
    • Giảm giới hạn từ xuống 6 từ 8. Cho phép nhiều bảng hơn với các từ nhỏ hơn. Xuất hiện để có một sự cải thiện nhẹ trong điểm trung bình. (10-15 bảng hoặc hơn được kiểm tra mỗi lần chạy so với 1 đến 2)
    • Theo đề nghị của Breadbox, tôi đã tạo một cấu trúc cây để chứa danh sách từ. Điều này làm tăng tốc độ kiểm tra back-end của các từ trên bảng một cách đáng kể.
    • Tôi đã chơi với việc thay đổi kích thước từ tối đa (tốc độ so với điểm số) và tôi vẫn chưa quyết định liệu 5 hoặc 6 là lựa chọn tốt hơn cho tôi. 6 kết quả trong tổng số 100-120 bảng đã được kiểm tra, trong khi 5 kết quả trong 500-1000 (cả hai bảng vẫn còn thấp hơn nhiều so với các ví dụ khác được cung cấp cho đến nay).
    • Vấn đề : Sau nhiều lần chạy liên tiếp, quá trình bắt đầu chậm lại, do đó vẫn còn một số bộ nhớ cần quản lý.

Điều này có thể trông khủng khiếp với một số bạn, nhưng như tôi đã nói, WIP. Tôi rất cởi mở với những lời chỉ trích mang tính xây dựng ! Xin lỗi vì cơ thể rất dài ...


Mô-đun súc sắc :

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

Mô đun lớp cây :

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

Mô-đun lớp 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

Mô-đun chính :

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
Tôi đã không xem qua mã, nhưng 50 điểm thì thấp đến mức nực cười. Tôi đã chơi các bảng được tạo ngẫu nhiên với số điểm trên 1000 (sử dụng SOWPODS - danh sách từ được cung cấp có thể ít rộng hơn). Bạn có thể muốn kiểm tra một dấu hiệu lỗi!
Peter Taylor

@PeterTaylor Cảm ơn bạn đã gợi ý. Tôi biết rằng điểm số quá thấp và tôi biết rằng một phần của vấn đề nằm ở chỗ tôi có thể thấy những từ rõ ràng bị bỏ qua ...
Gaffi

@PeterTaylor Ngoài ra, đối với hồ sơ, tôi liên tục đăng tiến trình của mình, thay vì chờ đợi sản phẩm cuối cùng của mình, vì chưa có ai khác đâm vào nó. Tôi muốn giữ câu hỏi phần nào còn sống cho đến khi điều đó xảy ra.
Gaffi

Tôi cũng nên lưu ý rằng điều này không được chạy trên máy nhanh nhất ngoài đó, vì vậy điều đó cũng không giúp được gì.
Gaffi

1
@Gaffi 10 giây để tính điểm? Đó là 9,999 giây quá dài. Bạn phải suy nghĩ lại mã của bạn. Nếu bạn từ chối biến danh sách từ của bạn thành một cái cây, thì ít nhất hãy làm điều này: Tạo một danh sách (có thể băm, bất cứ điều gì) của tất cả các tiền tố hai chữ cái. Sau đó, khi bạn bắt đầu đi theo một đường dẫn trên bảng, nếu hai chữ cái đầu tiên không có trong danh sách, hãy bỏ qua toàn bộ cây con của các đường dẫn có thể. Một lần nữa, xây dựng cây đầy đủ là tốt nhất, nhưng danh sách tiền tố hai chữ cái sẽ giúp ích và rất rẻ để thực hiện.
hộp bánh mì

2

Nhìn nhanh vào kích thước của không gian tìm kiếm.

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

Giảm để loại trừ sự lặp lại trên mỗi chết.

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

@breadbox lưu trữ từ điển dưới dạng kiểm tra Bảng O (1).

BIÊN TẬP

Ban tốt nhất (tôi đã chứng kiến ​​cho đến nay)

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

Hãy cho tôi một cỗ máy có nhiều RAM và chúng ta sẽ nói chuyện.
hộp bánh mì

Bạn cần chia các hoán vị xúc xắc cho 8 để tính các đối xứng của hình vuông. Ngoài ra, làm thế nào để bạn có được (4 ^ 4) (5 ^ 6) (6 ^ 5)? Tôi làm cho nó (4 ^ 3) (5 ^ 7) (6 ^ 6), với tổng không gian searc chỉ hơn 2 ^ 79.
Peter Taylor

@Peter Taylor: Bạn nói đúng. Tôi phải xóa một đến nhiều, khi làm những khuôn mặt độc đáo. Tôi nghĩ rằng chúng ta có thể đồng ý có 83 khuôn mặt độc đáo, (không bao gồm lặp lại trên die). Chọn bất kỳ 16 mà không lặp lại. '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 'Xấp xỉ: 1.082 x (10 ^ 30) ==> ~ 2 ^ 100 Gì bao giờ nó là một con số lớn
Adam Speight

2
@AdamSpeight Ban đầu tôi cho rằng nhận xét của bạn về việc lưu trữ từ điển dưới dạng hashtable chỉ là một trò đùa, và vì vậy về cơ bản tôi đã bỏ qua nó. Lời xin lỗi của tôi. Một câu trả lời thích hợp sẽ là: Trên thực tế, hashtable là cấu trúc dữ liệu tệ hại cho vấn đề này. Nó chỉ có thể trả lời câu hỏi "X có phải là một từ hợp lệ không?", Vì vậy bạn phải xây dựng tất cả các chuỗi có thể để tìm các từ. Một DAWG cho phép bạn hỏi "X có phải là tiền tố của bất kỳ từ hợp lệ nào không? Và nếu vậy, những chữ cái nào có thể theo sau nó?" Điều này cho phép bạn cắt không gian tìm kiếm thành một phần rất nhỏ trong tổng kích thước của nó.
hộp bánh mì

Hashtable là khủng khiếp vì nó ngăn bạn loại bỏ các đoạn từ sẽ không bao giờ trở thành từ hoàn chỉnh (dicttree.ceiling (đoạn) .startsWith (đoạn)). Mặc dù bất kỳ bảng boggle cụ thể nào cũng có nhiều triệu từ tiềm năng, bạn có thể loại bỏ một phần rất lớn trong số chúng sau 2-3 chữ cái được xâu chuỗi lại với nhau. Tree traversal chậm hơn tra cứu hashtable, nhưng cây cho phép bạn vượt qua 99% công việc thông qua quay lui.
Jim W

1

Mục nhập của tôi đã kết thúc tại đây trên Dream.In.Code ~ 30ms cho mỗi lần tìm kiếm bảng (trên máy 2 lõi, nên nhanh hơn với nhiều lõi hơn)


Tuy nhiên nhìn vào nó, nhưng liên kết đầu tiên của bạn trên trang đó thiếu :trong http://. ;-)
Gaffi

Rất đẹp. Tôi sẽ cố gắng đánh cắp điều đó cho bản thân mình như một kinh nghiệm học tập. .NETđể VBAkhông phải là quá khó khăn.
Gaffi

Bạn có phiền cập nhật câu trả lời để bao gồm điểm trung bình của bạn khi chạy danh sách ISPELL (không phải SOWPODS) không? Đó là một phần của thử thách và tôi rất muốn xem kết quả của bạn so với hộp bánh mì như thế nào.
Gaffi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.