Ai sẽ chiến thắng Ghost?


8

Trò chơi Ghost được chơi giữa hai người chơi thay phiên nhau nói một chữ cái trên mỗi lượt. Tại mỗi điểm, các chữ cái cho đến nay phải bắt đầu một số từ tiếng Anh hợp lệ. Người thua cuộc là người chơi hoàn thành một từ đầy đủ trước. Vì vậy, ví dụ, nếu các chữ cái cho đến nay là EAGL, thì chữ cái tiếp theo hợp lệ duy nhất để nói là "E" và do đó người chơi tiếp theo sẽ mất. (Mặc dù có những từ dài hơn như "eaglet".)

Các thách thức

Bạn phải viết một chương trình hoặc chức năng để xác định, đưa ra các chữ cái cho đến nay, ai sẽ giành chiến thắng với giả định hai người chơi hoàn hảo. Đầu vào là một chuỗi đại diện cho trạng thái hiện tại của trò chơi và một danh sách các chuỗi đại diện cho từ điển của các từ hợp lệ. Đầu ra nên phân biệt người chơi tiếp theo sẽ thắng hay thua.

Chi tiết

  • Mã phải xử lý trường hợp trạng thái hiện tại trống. Tuy nhiên, bạn có thể cho rằng không có từ nào trong từ điển trống.
  • Bạn có thể giả sử rằng mỗi chuỗi đầu vào chỉ bao gồm các chữ cái ASCII viết thường, tức là az.
  • Bạn có thể giả sử trạng thái hiện tại và tất cả các từ trong từ điển có tối đa 80 ký tự mỗi từ.
  • Từ điển được đảm bảo là không trống (để tránh trường hợp không có động thái đầu tiên hợp lệ).
  • Bạn có thể cho rằng "trạng thái hiện tại" sẽ hợp lệ: nhất thiết phải có một số từ bắt đầu bằng trạng thái hiện tại; Ngoài ra, trạng thái hiện tại sẽ không phải là một từ đầy đủ, cũng không có bất kỳ tiền tố nào của trạng thái hiện tại là một từ đầy đủ.
  • Từ điển sẽ được lọc trước theo các quy tắc trong đó "từ tiếng Anh" được coi là hợp lệ cho trò chơi - vì vậy, ví dụ, đối với một biến thể trong đó các từ có ba chữ cái trở xuống chưa kết thúc trò chơi, từ điển sẽ được lọc trước chỉ bao gồm các từ có bốn chữ cái trở lên.
  • Bạn có thể cho rằng từ điển sẽ được định sẵn.

Ví dụ

Giả sử từ điển là:

abbot
eager
eagle
eaglet
earful
earring

Sau đó, cho các trạng thái hiện tại sau đây, đầu ra nên như sau:

Current state   Result
=============   ======
                loss
a               win
eag             win
eagl            loss
ear             win
earf            win
earr            loss

Tương tự, đối với danh sách từ tại https://raw.githubusercontent.com/dschepler/ghost-word-list/master/wordlist.txt (được sản xuất trên hệ thống Debian bằng cách sử dụng pcregrep '^[a-z]{4,80}$' /usr/share/dict/american-english) ở đây là một phiên có thể:

Current state   Result
=============   ======
                win
h               loss
ho              win
hoa             loss
hoar            win
hoars           loss

(Và sau đó bước tiếp theo hoàn thành "khàn".)

Chấm điểm

Đây là : Chương trình ngắn nhất tính theo byte cho mỗi ngôn ngữ lập trình sẽ thắng.


Từ hàng đợi đánh giá, tôi không nghĩ rằng thách thức này không rõ ràng. Nếu bạn làm, xin vui lòng gửi lý do tại sao.
mbomb007

Tôi đã không bỏ phiếu để đóng, nhưng tôi nghĩ rằng câu hỏi có thể sử dụng một mô tả về đầu ra. Đầu ra phải là một boolean? Một trong hai giá trị? Một trong nhiều giá trị được phân chia thành hai?
Jakob

Tôi ổn với bất cứ điều gì từ đó có được kết quả thắng / thua là chuyện nhỏ. Hoặc là sự phân đôi trung thực / falsey (theo thứ tự) hoặc một trong hai giá trị, hoặc một cái gì đó như kết quả số nguyên dương so với âm, v.v.
Daniel Schepler

@ mbomb007 Tôi đã bình chọn là không rõ ràng. Tôi thực sự không thể nói những gì không rõ ràng cụ thể vì tôi không hiểu câu hỏi. Tôi đã đọc nó năm lần và tôi vẫn không hiểu nhiệm vụ gì cả.
Ad Hoc Garf Hunter

@WheatWizard Mỗi người chơi phải chọn chữ cái tiếp theo sao cho từ một phần vẫn là tiền tố của một từ trong từ điển. Khi không còn lựa chọn nào như vậy nữa, thì trò chơi kết thúc với người chơi cuối cùng là người thua cuộc.
mbomb007

Câu trả lời:


3

JavaScript, 54 byte

l=>g=w=>!(w+0)||l.some(t=>t==w||!g(t.match(`^${w}.`)))

gọi nó như thế này: f (wordlist_as_array) (current_word_as_opes), nó trả về true cho win, false cho thua.

hiệu suất khá kém T_T, chỉ hoạt động với trường hợp thử nghiệm nhỏ.


1
Wow, đó là một kiểm tra null khéo léo!
Neil

1

Python 3 , 135 129 84 byte

-4 byte nhờ ông Xcoder !

-42 byte nhờ Daniel Schepler !

g=lambda s,l:(s in l)or-min(g(w,l)for w in{w[:len(s)+1]for w in l if w[:len(s)]==s})

Hãy thử trực tuyến!

A 1cho biết người chơi hiện tại sẽ thắng, trong khi a -1cho biết họ sẽ thua.



1
Không chắc chắn, nhưng 131 byte ?
Ông Xcoder

Trên từ điển đầy đủ 61135 từ tôi đã đăng ở github và trạng thái trống tôi chưa thể chạy nó đến khi hoàn thành (nó đã chạy được vài phút rồi). Tôi không biết tùy chỉnh ở đây cho dù bạn cần để có thể chạy tất cả các trường hợp thử nghiệm mà tôi đã đăng trong một thời gian hợp lý. (Trên bài đăng trên hộp cát, ban đầu tôi có một yêu cầu rằng mã không phải là "không hiệu quả khủng khiếp" nhưng các nhà bình luận đề nghị bỏ nó hoặc chỉ định thời gian chạy không có triệu chứng - và tôi sợ nói "tuyến tính trong kích thước của đầu vào" sẽ là quá hạn chế.)
Daniel Schepler

1
Dưới đây là một thử nghiệm với việc sử dụng một bộ trung gian để loại bỏ các cuộc gọi đệ quy trùng lặp. Với điều này, ít nhất nó có thể xử lý từ điển đầy đủ trong vài phút. (Tôi cũng đang thử nghiệm một sự đơn giản hóa khác, vì vậy kết quả ròng giảm xuống còn 87 byte.)
Daniel Schepler

@DanielSchepler Đẹp quá! Tôi đã làm việc theo một cách tương tự để giảm các cuộc gọi đệ quy, nhưng phương pháp của bạn ngắn gọn hơn rất nhiều! Nó cũng cho phép tôi giảm điều này xuống a lambda.
notjagan

0

PHP, 192 154 100 98 byte

function t($w,$d){foreach(preg_grep("#^$w#",$d)as$p)if($p==$w||!t($w.$p[strlen($w)],$d))return 1;}

Hàm trả về 1cho thắng, NULLthua.
Gọi với t(string $word,array $dictionary) hoặc thử trực tuyến .

phá vỡ

function t($w,$d)
{
    // loop through matching words
    foreach(preg_grep("#^$w#",$d)as$p)if(
        $p==$w                      // if word is in dictionary (previous player lost)
        ||                          // or
        !t($w.$p[strlen($w)],$d)    // backtracking is falsy (next player loses)
    )
        return 1;                   // then win
    // implicit return NULL
}

0

C ++, 243 byte (không cạnh tranh)

FYI, đây là phiên bản chơi golf của triển khai tham chiếu của tôi (được đánh dấu là không cạnh tranh vì đó là thách thức của riêng tôi). Nó hy vọng danh sách từ trong wtham số là một mảng kết thúc null (của các chuỗi kết thúc null). Nó trả về 1nếu người chơi tiếp theo sẽ thua, hoặc 0người chơi tiếp theo sẽ thắng.

#define r return
int g(char*s,char**w){struct N{int d=0;N*c[128]{};int l(){if(d)r 0;for(N*p:c)if(p&&p->l())r 0;r 1;}void a(char*s){*s?(c[*s]?:c[*s]=new N)->a(s+1),0:d=1;}N*f(char*s){r*s?c[*s]->f(s+1):this;}}d;for(;*w;d.a(*w++));r d.f(s)->l();}

Hãy thử trực tuyến.

Phiên bản mở rộng và nhận xét:

int g(char* s, char** w) {
    /// Node of the prefix tree
    struct N {
        int d = 0;  ///< 1 if the node represents a word in the dictionary
        N* c[128] {};  ///< child nodes, indexed by integer value of character

        // Optional, if you want to eliminate the memory leak from the
        // golfed version.  (Though actually in practice, I would make
        // "c" into std::array<std::unique_ptr<N>, 128> so the default
        // destructor would be sufficient.)
        // ~N() { for (N* p : c) delete p; }

        /// \retval 1 if the next player going from this node will lose
        /// \retval 0 if they will win
        int l() {
            if (d)
                return 0;  // last player lost, so the player who would
                           // have gone next wins
            for (N* p : c)
                if (p && p->l())
                    return 0;  // found a letter to play which forces the
                               // other player to lose, so we win
            return 1;  // didn't find any such letter, we lose
        }

        /// Add word \p s under this node
        void a(char* s) {
            *s ?
                (c[*s] ?: c[*s] = new N) // use existing child node or create new one
                ->a(s+1), 0  // the ,0 just makes the branches of
                             // the ternary compatible
            :
                d = 1;
        }

        /// Find node corresponding to \p s
        N* f(char* s) {
            return *s ?
                c[*s]->f(s+1)
            :
                this;
        }
    } d;  // d is root node of the prefix tree

    // Construct prefix tree
    for (; *w; d.a(*w++))
        ;

    // Find node for input, then run the "loser" method
    return d.f(s)->l();
}
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.