Hãy chơi Hangman?


8

Theo trang này , chiến lược tốt nhất để đoán các từ hangman tiếng Anh là tính toán tỷ lệ cược của mỗi chữ cái trong một danh sách từ đáp ứng các điều kiện của chúng tôi. Nhưng, vì tôi thực sự lười biếng, tôi không thực sự muốn tự mình tính toán từng từ trong từ điển. Nhưng, như tôi biết rằng bạn luôn ở đây để giúp tôi, tôi chắc chắn rằng bạn sẽ có thể biến tôi thành vua của một bộ luật sẽ làm điều đó cho tôi. Và, vì đĩa cứng của tôi đã gần đầy, tôi muốn mã nhỏ nhất có thể. Điều đó có nghĩa rằng đây là môn đánh gôn và bài nộp có số byte thấp nhất sẽ giành chiến thắng, nhưng cũng chính xác nhất! .

Đầu ra đầu vào

Một từ ngẫu nhiên từ danh sách từ này sẽ được thực hiện.

Chương trình của bạn nên chấp nhận, trong các đối số hoặc theo đầu vào của người dùng (cửa sổ bật lên, stdin, bất cứ điều gì),

  • Độ dài của từ
  • Đã tìm thấy chữ không chính xác hoặc 0 nếu chúng tôi mới bắt đầu trò chơi và bạn không cung cấp chữ cái không chính xác.
  • Chữ cái đã được tìm thấy VÀ vị trí của chúng trong từ

Ví dụ: ./hangsolver 6 XBZ 1P 4P 2E 6EỞ đây, tôi chọn từ "người". Để rõ ràng: PE _ P _ E (Chữ sai là XB và Z)

Điều đó có nghĩa là, trong một trò chơi, tôi sẽ phải khởi chạy kịch bản của mình nhiều lần!

Đầu ra sẽ là một chữ cái duy nhất, lần thử tiếp theo của bạn.

Quy tắc

  • Người nào đoán được 10 từ trong ít lần thử hơn những người khác sẽ giành chiến thắng.
  • Trong trường hợp hòa, mã ngắn nhất tính bằng byte sẽ thắng.
  • Nếu vẫn còn hòa, chương trình nhanh nhất sẽ thắng.
  • Bạn có thể cho rằng chỉ có những từ này trong tiếng Anh
  • Tôi sẽ chỉ thử những từ hợp lệ từ danh sách từ.
  • Tôi đã có một máy tính tốt, sức mạnh CPU sẽ không phải là vấn đề (nhưng hãy cố gắng trả lời nhanh nhất có thể!)
  • Bạn không thể giải quyết bằng một bộ giải trực tuyến, nhưng bạn có thể tải xuống danh sách từ hoặc thông qua nó như một đối số. Bạn có thể giả sử nó sẽ được đặt tên là "wordlist.txt" và trong cùng thư mục với tập lệnh của bạn.
  • Mã của bạn phải có khả năng chạy trên một hệ điều hành chung. Nó có thể là windows, mac hoặc ubfox / debian / CentOS hoặc Redhat.
  • Bạn không thể sử dụng một bộ giải bên ngoài.
  • Tuy nhiên, bạn có thể rút ngắn URL vào danh sách từ.
  • Golf-code này sẽ kết thúc vào đầu tháng Chín.
  • Bạn PHẢI sử dụng phương pháp được mô tả ở trên.

Chúc may mắn !

Danh sách từ được tìm thấy ở đây trên SE.


2
Mã ngắn nhất trong byte sẽ giành chiến thắng, với dự đoán tốt nhất là tiebreak? Điều đó có nghĩa là chương trình của tôi chỉ đơn giản là đoán bất kỳ chữ cái ngẫu nhiên nào chưa được sử dụng trước đó sẽ đánh bại những người thực sự cố gắng đoán ra một dự đoán tốt. Bạn có thể muốn suy nghĩ lại về điểm số của bạn, hoặc bạn sẽ nhận được câu trả lời tầm thường.
Cấp sông St

"Bạn PHẢI sử dụng phương pháp được mô tả ở trên.", Tôi trích dẫn các quy tắc. Nhưng tôi sẽ chỉnh sửa để làm cho tiêu chí chiến thắng chính
WayToDoor

1
Để rõ ràng, "sử dụng phương pháp được mô tả ở trên" có nghĩa là đoán chữ cái xuất hiện với số lượng lớn nhất các từ có thể chưa được đoán ra?
isaacg

Đúng chính xác. Cảm ơn đã chỉnh sửa lỗi đánh máy!
WayToDoor 17/08/2015

1
Không phải dữ liệu đầu vào trong ví dụ của bạn là "6 XBZ 1P 4P 2E 6E"?
Razvan

Câu trả lời:


5

PowerShell, 248 246 241 byte

$a=$args;$c=$a[0];$b=$a[2..$c];((gc wordlist.txt)-match"^$((1..$c|%{$e=,"[^$($a[1])]"*$c}{$e[$_-1]=(((@($b)-match"^$_\D")[0]-split$_)[-1],$e[$_-1]-ne'')[0]}{$e-join''}))$"-join''-split'\B'|?{!(@($b)-match$_).Count}|group|sort count)[-1].Name

Ung dung

Chà, nhiều nhất có thể mà không thay đổi cách thức hoạt động:

$a=$args
$c=$a[0]
$b=$a[2..$c]
(
    (gc wordlist.txt) -match "^$(
        (
            1..$c | ForEach-Object -Begin {
                $e = ,"[^$($a[1])]" * $c
            } -Process {
                $e[$_-1] = (
                    ( ( @($b) -match "^$_\D" )[0] -split $_ )[-1] , $e[$_-1] -ne ''
                )[0]
            } -End {
                $e-join''
            }
        )
    )$" -join '' -split'\B' |
    Where-Object {
        -not (@($b) -match $_).Count
    } | 
    Group-Object |
    Sort-Object count
)[-1].Name

Phá vỡ

Cách tiếp cận tôi thực hiện ở đây là trước tiên tạo một biểu thức chính quy để lấy các từ có thể ra khỏi danh sách từ. Vì tôi biết độ dài của từ và các chữ cái không hoạt động, tôi có thể tạo ra một biểu thức chính xác từ đó khá dễ dàng.

Vì vậy, trong ví dụ NHÂN DÂN, 6 chữ cái với XBZ không phải là một phần của từ, tôi sẽ tìm cách tạo ^PE[^XBZ]P[^XBZ]E$.

Tôi đang khai thác thực tế là Get-Content( gc) trả về một mảng các dòng và -matchtoán tử khi được sử dụng với một mảng ở bên trái, trả về một mảng khớp thay vì một bool, vì vậy tôi có thể nhanh chóng nhận được một danh sách chỉ các từ ứng cử viên, một khi tôi có regex.

Để tạo regex, tôi bắt đầu với một mảng ( $e) của lớp ký tự khớp âm với $ccác phần tử ( $clà số lượng chữ cái trong từ). Lặp lại các số từ 1 đến hết $c, tôi kiểm tra một chữ cái phù hợp ở vị trí đó và nếu nó tồn tại, tôi thay thế phần tử trong $ebằng chữ cái đó.

Khi tôi đã lặp qua tất cả các vị trí, mảng cuối cùng là -joined (với chuỗi rỗng) và chúng ta có biểu thức chính quy.

Vì vậy, bây giờ tôi đã có một loạt các từ có thể có. Một cách nhanh chóng -joinvới chuỗi trống trên đó, cung cấp cho tôi một chuỗi kết hợp lớn của tất cả các từ, tôi tách ra \B(không phải là một ranh giới từ, nếu tôi tách trên chuỗi trống, tôi sẽ có thêm 2 phần tử trống), vì vậy bây giờ tôi có một mảng của mỗi chữ cái trong mỗi từ có thể.

Điều đó Where-Objectcho phép tôi lọc ra các chữ cái đã được khớp. Phần này là một nỗi đau thực sự. Nó phải xử lý danh sách các chữ cái phù hợp (bao gồm vị trí) là 1 phần tử, nhiều hơn 1 phần tử hoặc 0 phần tử, do đó buộc $bvào một mảng trước để -matchcó thể hoạt động trên tất cả chúng, nhưng điều đó (không may trong trường hợp này ) trả về một mảng, vì vậy chúng ta phải kiểm tra .Count. Sử dụng !(thing).Countlà một chút nhỏ hơn so với sử dụng (thing).Count-gt0.

Tiếp tục, bây giờ chúng ta đã có một mảng gồm tất cả các ký tự đơn ( stringkhông phải là chars) từ tất cả các từ có thể có, trừ các chữ cái đã được đoán chính xác.

Việc đưa nó vào Group-Objectcho tôi một đối tượng với số lượng của mỗi chữ cái, do đó, một đường ống nhanh vào Sort-Object countgiúp bạn dễ dàng có được số đếm cao nhất. Thay vì (thing|sort count -des)[0]chúng ta có thể sử dụng (thing|sort count)[-1]. Trong PowerShell [-1]được phần tử cuối cùng. Tại thời điểm này, chúng tôi vẫn đang xử lý các đối tượng xuất phát Group-Objectđể chúng tôi có được .Nametài sản là chữ cái xuất hiện nhiều nhất.

Ghi chú

  • Nên hoạt động với PowerShell v3 +; gần như chắc chắn sẽ nghẹt thở trên 2.
  • Hãy nhớ khi bạn gọi một tập lệnh PowerShell, truyền các đối số bằng dấu cách, không phải dấu phẩy.
  • Mặc dù tôi không thấy nó trong các quy tắc, nhưng có vẻ như mọi người đang sử dụng tên tệp wordlist.txtnếu không điều đó có thể làm mất đi một vài byte.
  • Tốc độ không phải là một vấn đề. Điều này dường như để chạy ngay lập tức cho tôi. .\hangman.ps1 7 0Chạy chậm nhất tôi có thể làm cho nó làm ( ) chạy trong khoảng 350ms.

1
Chào mừng bạn đến với Câu đố lập trình & trao đổi mã Golf, câu trả lời đầu tiên tuyệt vời! :)
Doorknob

@Doorknob cảm ơn rất nhiều!
nghĩa tự do

6

Python3, 299 byte

import sys,collections as c;x,X,N,*Z=sys.argv;print([x for x in c.Counter(''.join([''.join(x)for x in map(set,filter(lambda l:len(l)==int(X)+1and all(x not in X.lower()for x in l)and all(l[int(x[0])-1]==x[1].lower()for x in Z),open('wordlist.txt')))]))if x not in ''.join(Z).lower()and x!='\n'][0])

khá chắc chắn rằng điều này có thể được chơi golf hơn nữa.

Lọc danh sách từ cho các kết quả khớp tiềm năng, xây dựng bản đồ tần số char và chọn ký tự thường xuyên nhất chưa được chọn.


Bạn có rất nhiều ''.join(..)s. Nếu tất cả các phần tử bên trong là các chuỗi có độ dài 1, bạn có thể thay đổi nó thành '..'[2::5], trong đó các dấu nháy đơn là backticks.
Kade

3

Java, 646 640 631 607 606 (ngắn) 790 789 779 (nhanh) byte

NGẮN

import java.util.*;class I{public static void main(String[]a)throws Exception{char[]w=a[1].toCharArray(),p,q;int l=Integer.parseInt(a[0]),i,z=w.length,j;q=new char[l];for(i=2;i<a.length;i++)q[Character.getNumericValue(a[i].charAt(0))-1]=(char)(a[i].charAt(1)+32);java.io.File u=new java.io.File("wordlist.txt");Scanner s=new Scanner(u);while(s.hasNextLine()){p=s.nextLine().toCharArray();if(p.length==l)for(i=0;i<l;i++)if(p[i]==q[i]||q[i]=='\0'){if(i==l-1)y:for(i=0;i<l;i++)for(j=0;j<z;j++)if(!(p[i]==w[j])){if(j==z-1){System.out.print(p[new String(q).indexOf('\0')]);return;}}else break y;}else{break;}}}}

NHANH

import java.util.*;class I{public static void main(String[]a)throws Exception{char[]w=a[1].toCharArray(),p,q;int l=Integer.parseInt(a[0]),i,z=w.length,j,k,o,n[]=new int[255],r[];q=new char[l];for(i=2;i<a.length;i++)q[Character.getNumericValue(a[i].charAt(0))-1]=(char)(a[i].charAt(1)+32);String m=new String(q);java.io.File u=new java.io.File("wordlist.txt");Scanner s=new Scanner(u);while(s.hasNextLine()){p=s.nextLine().toCharArray();h:if(p.length==l)for(i=0;i<l;i++)if(p[i]==q[i]||q[i]=='\0'){if(i==l-1)y:for(i=0;i<l;i++)for(j=0;j<z;j++)if(p[i]!=w[j]){if(j==z-1){for(k=0;k<l-m.replace("\0","").length();k++)n[(int)p[new String(q).indexOf('\0',k)]]++;break h;}}else break y;}else{break;}}r=n.clone();Arrays.sort(n);for(o=0;o<255;o++)System.out.print(r[o]==n[254]?(char)o:"");}}

Đặt tệp danh sách từ trong thư mục.

Thuật toán phiên bản ngắn

  1. Tải đối số
  2. Xây dựng từ mà chúng tôi đang cố gắng đoán {'p', 'e', ​​'\ 0', 'p', '\ 0', 'e'}
  3. Tải WordList
  4. Đi qua từng dòng của WordList
  5. Dừng lại khi bạn thấy rằng toàn bộ từ khớp với điều kiện này trong p[i] == q[i] || q[i] == '\0'đó p là một từ trong danh sách từ (mảng char) và q là từ chúng tôi đang cố gắng đoán
  6. Lặp lại các ký tự sai và so sánh với từ
  7. In ký tự bị thiếu đầu tiên

Thuật toán phiên bản dài

  1. Bước ngắn 1-7
  2. Tăng số lượng ký tự trong mảng n cho các ký tự bị thiếu
  3. Lặp lại cho đến khi tất cả các từ đi qua
  4. In ký tự có số đếm cao nhất

Tôi có thể loại bỏ hàng nhập khẩu không?
Roberto Anić Banić

Có thể loại bỏ nhập khẩu java trong mã golf?
Roberto Anić Banić 17/08/2015

không sao, miễn là bạn chỉ định tôi nên nhập chúng (nếu không rõ ràng);)
WayToDoor 17/08/2015

Kk. Tôi sẽ cập nhật nó khi tôi trở về nhà. Gonna đi mua một bộ định tuyến mới :) và 90 feet của Cat5e
Roberto Anić Banić

1
Tôi không nghĩ rằng nó hoạt động cho các từ dài hơn 9 chữ cái. Hãy thử sử dụng "triển vọng" từ danh sách từ với đầu vào "6 XBZ 1P 5P 6E 11E" Có lẽ thay đổi vòng lặp đầu tiên thành q [Integer.parseInt (a [i] .sub chuỗi (0, a [i] .length () - 1) ) -1] = (char) (a [i] .charAt (a [i] .length () - 1) +32); Ngoài ra, một mẹo chơi gôn: Hãy thử sử dụng Scanner s = new Scanner (new java.io.File ("wordlist.txt"));
đánh dấu

2

PHP, 346 byte

<?php $a='array_shift';$p='preg_match';$a($v=&$argv);$w=array_fill(1,$a($v),'(.)');$c=$a($v);foreach($v as$q)$p('/(\d+)(\w)/',$q,$m)&&$w[$m[1]]=$m[2];foreach(file('wordlist.txt')as$y)if($p("/^".implode($w)."$/",$y=strtoupper(trim($y)),$m)&&(!$c||!$p("/[$c]/",$y)))for($i=0;$i++<count($m);)($v=@++$g[$m[$i].$i])&&$v>@$t&&$t=$v&&$l=$m[$i];echo @$l;

Nó hoạt động như sau:

  1. Tạo một mẫu biểu thức chính quy để khớp với các chữ cái đã đoán từ trước đến nay
  2. Lặp lại từng từ trong tệp
  3. Nếu từ khớp với biểu thức chính quy, nó đảm bảo rằng từ đó không chứa một trong các chữ cái sai
  4. Tăng một bộ đếm cho mỗi chữ cái có thể có của từ đó (dựa trên vị trí của chúng)
  5. Xuất thư với bộ đếm cao nhất

Giả định:

  • PHP >=5.4
  • Có một wordlist.txttập tin trong thư mục hiện tại

php hangman.php 6 YH 2E 6E 3O 1P 4P PHP Notice: Undefined offset: 2 in ./Desktop/hangman.php on line 1 Notice: Undefined offset: 2 in ./Desktop/hangman.php on line 1Đã cố gắng để làm cho anh ta đoán mọi người
WayToDoor

1
Cảm ơn đã chỉ ra điều đó. Có một lỗi nhỏ trong mã. Tôi đã cập nhật nó (vẫn còn 346 byte).
Razvan

1

Powershell, 153 byte

Lấy cảm hứng từ câu trả lời của briantist .

Như các nhà văn khác, tôi đã sử dụng tên tệp wordlist.txt. Mặc dù có thể chọn một tên ngắn hơn.

param($l,$b,$c)((sls "^$(-join(1..$l|%{$p=$c|sls "$_."|% m*
("$p"[1],"[^$b$c]")[!$p]}))$" wordlist.txt|% l*e|% t*y|group|sort c*).Name-match"[^ $c]")[-1]

Kịch bản kiểm tra ít chơi gôn hơn:

$f = {

param($length,$bad,$chars)

$wordPattern=-join(1..$length|%{                  # join all subpatterns for $_ from 1 to $length
    $c=$chars|sls "$_."|% Matches                 # find subpattern in char array
    ("$c"[1],"[^$bad$chars]")[!$c]                # return a first char of subpattern if subpattern found, or bad characters
})

# Note 1: The word subpattern is similar to 'PE[^XBZ1P 4P 2E 6E]P[^XBZ1P 4P 2E 6E]E'
#         Spaces and digits does not affect the search for letters, only letters are important.
#
# Note 2: The same applies to 0. [^0] matches any letter.
#

$matches=sls "^$wordPattern$" wordlist.txt|% Line # find matched words in file wordlist.txt and return matched string only
$groups=$matches|% toCharArray|group|sort Count   # group all chars in matched words by count
$name=$groups.Name-match"[^ $chars]"              # select property Name from all grouped elements (chars itself) and return not matched to $chars only
$name[-1]                                         # return last element in the sorted array (most frequently found char)

# Note 3: The space is important in the regexp "[^ $chars]"
#         The space makes the regexp valid if the $chars array is empty

}

&$f 7 0 2o,5e,7t
&$f 7 nl 2o,5e,7t
&$f 6 XBZ 1P,4P,2E,6E

Đầu ra:

c
r
l

Giá trị biến cho &$f 7 0 2o,5e,7t:

$WordPattern: "[^02o 5e 7t]o[^02o 5e 7t][^02o 5e 7t]e[^02o 5e 7t]t"
$Matches: concept collect comment correct connect convert consent concert
$Groups:
    Count Name                      Group
    ----- ----                      -----
        1 p                         {p}
        1 v                         {v}
        1 s                         {s}
        2 m                         {m, m}
        2 l                         {l, l}
        4 r                         {r, r, r, r}
        8 n                         {n, n, n, n...}
        8 o                         {o, o, o, o...}
        8 t                         {t, t, t, t...}
        8 e                         {e, e, e, e...}
       13 c                         {c, c, c, c...}
$name: p v s m l r n c
$name[-1]: c
return: c
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.