Mari kita bermain Hangman?


8

Menurut halaman ini , strategi terbaik untuk menebak kata-kata algojo Inggris adalah dengan menghitung peluang setiap huruf dalam daftar kata yang memenuhi persyaratan kami. Tetapi, karena saya benar-benar malas, saya tidak benar-benar ingin menghitung setiap kata dalam kamus sendiri. Tapi, seperti yang saya tahu bahwa Anda selalu di sini untuk membantu saya, saya yakin Anda akan dapat membuat saya menjadi raja kode yang akan melakukan itu untuk saya. Dan, karena hard disk saya hampir penuh, saya ingin kode sekecil mungkin. Ini berarti bahwa ini adalah kode-golf, dan pengiriman dengan jumlah byte terendah akan menang, tetapi juga yang paling akurat! .

Input output

Kata acak dari daftar kata ini akan diambil.

Program Anda harus menerima, dalam argumen, atau dengan input pengguna (sembulan, stdin, apa pun),

  • Panjang kata
  • Surat yang salah sudah ditemukan, atau 0 jika kami baru saja memulai permainan, dan Anda tidak memberikan surat yang salah.
  • Surat sudah ditemukan DAN posisi mereka dalam kata

Contoh: ./hangsolver 6 XBZ 1P 4P 2E 6EDi sini, saya memilih kata "orang". Untuk kejelasan: PE _ P _ E (Huruf yang salah adalah XB dan Z)

Itu artinya, dalam satu pertandingan, saya harus meluncurkan skrip Anda berkali-kali!

Output akan menjadi satu huruf, percobaan Anda berikutnya.

Aturan

  • Salah satu yang akan menebak 10 kata dalam percobaan kurang dari yang lain akan menang.
  • Dalam kasus seri, kode terpendek dalam byte menang.
  • Jika masih ada seri, program tercepat akan menang.
  • Anda dapat berasumsi bahwa hanya ada kata - kata ini dalam bahasa Inggris
  • Saya hanya akan mencoba kata-kata yang valid dari daftar kata.
  • Saya memiliki komputer yang bagus, kekuatan CPU tidak akan menjadi masalah (tetapi cobalah untuk menjawab secepat mungkin!)
  • Anda tidak dapat menyelesaikan dengan solver online, tetapi Anda dapat mengunduh daftar kata, atau membiarkannya sebagai argumen. Anda dapat menganggap itu akan dinamai "wordlist.txt" dan di direktori yang sama dengan skrip Anda.
  • Kode Anda harus dapat dijalankan pada OS umum. Itu bisa windows, mac, atau ubuntu / debian / CentOS atau Redhat.
  • Anda tidak dapat menggunakan pemecah eksternal.
  • Namun Anda dapat mempersingkat URL ke daftar kata.
  • Golf kode ini akan berakhir pada awal September.
  • Anda HARUS menggunakan metode yang dijelaskan di atas.

Semoga berhasil !

Daftar kata ditemukan di sini di SE.


2
Kode terpendek dalam byte akan menang, dengan tebakan terbaik sebagai tiebreak? Itu berarti bahwa program saya yang hanya menebak huruf acak apa pun yang belum pernah digunakan sebelumnya akan mengalahkan orang lain yang benar-benar mencoba untuk menebak dengan baik. Anda mungkin ingin memikirkan kembali skor Anda, atau Anda akan mendapatkan jawaban yang sepele.
Level River St

"Anda HARUS menggunakan metode yang dijelaskan di atas.", Saya mengutip aturannya. Tetapi saya akan mengedit untuk menjadikan kriteria pemenang utama
WayToDoor

1
Agar lebih jelas, "menggunakan metode yang dijelaskan di atas" berarti menebak huruf yang muncul dalam jumlah terbesar dari kata-kata yang mungkin belum ditebak?
isaacg

Ya persis. Terima kasih atas kesalahan ketik!
WayToDoor

1
Bukankah seharusnya data input dalam contoh Anda menjadi "6 XBZ 1P 4P 2E 6E"?
Razvan

Jawaban:


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

Tidak disatukan

Yah, sebanyak yang saya bisa tanpa mengubah cara kerjanya:

$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

Kerusakan

Pendekatan yang saya ambil di sini adalah pertama-tama menghasilkan ekspresi reguler untuk mengeluarkan kata-kata yang mungkin keluar dari daftar kata. Karena saya tahu panjangnya kata, dan huruf-huruf yang tidak berfungsi, saya bisa membuat regex dengan mudah.

Jadi dalam contoh ORANG, 6 huruf dengan XBZ tidak menjadi bagian dari kata, saya akan mencari untuk menghasilkan ^PE[^XBZ]P[^XBZ]E$.

Saya mengeksploitasi fakta bahwa Get-Content( gc) mengembalikan array garis, dan -matchoperator ketika digunakan dengan array di sisi kiri, mengembalikan array yang cocok bukan bool, jadi saya bisa dengan cepat mendapatkan daftar kata-kata yang kandidat, begitu saya memiliki regex.

Untuk menghasilkan regex, saya mulai dengan array ( $e) dari kelas karakter pencocokan negatif dengan $celemen ( $cmenjadi jumlah huruf dalam kata). Iterasi melalui angka 1 sampai $c, saya memeriksa surat yang cocok di posisi itu, dan jika ada, saya mengganti elemen $edengan huruf itu.

Setelah saya mengulangi semua posisi, array terakhir adalah -joined (dengan string kosong) dan kami memiliki regex kami.

Jadi sekarang saya punya berbagai kata yang mungkin. Cepat -joindengan string kosong di atasnya, beri saya satu string besar bersambung dari semua kata, saya pisah \B(bukan batas kata, jika saya pisah pada string kosong saya akan mendapatkan 2 elemen kosong tambahan), jadi sekarang saya memiliki array dari setiap huruf di setiap kata yang mungkin.

Memipipkannya ke dalam Where-Objectmemungkinkan saya menyaring surat-surat yang sudah cocok. Bagian ini benar-benar menyakitkan. Itu harus berurusan dengan daftar huruf yang cocok (yang termasuk posisi) menjadi 1 elemen, lebih dari 1 elemen, atau 0 elemen, karenanya memaksa $bke dalam array terlebih dahulu sehingga -matchdapat beroperasi pada mereka semua, tetapi itu (sayangnya dalam hal ini ) mengembalikan array, jadi kita harus memeriksa .Count. Menggunakan !(thing).Countsedikit lebih kecil dari menggunakan (thing).Count-gt0.

Selanjutnya, sekarang kita punya array semua karakter tunggal ( stringtidak chars sebagai s) dari semua kata itu mungkin, minus huruf yang sudah dapat ditebak dengan benar.

Memipakan yang Group-Objectmemberi saya objek dengan jumlah setiap huruf, jadi pipa cepat ke Sort-Object countmembuatnya mudah untuk mendapatkan jumlah tertinggi. Daripada (thing|sort count -des)[0]kita bisa menggunakan (thing|sort count)[-1]. Di PowerShell [-1]mendapatkan elemen terakhir. Pada titik ini kita masih berurusan dengan objek yang berasal Group-Objectsehingga kita mendapatkan .Nameproperti yang merupakan huruf yang paling banyak muncul.

Catatan

  • Harus bekerja dengan PowerShell v3 +; hampir pasti akan tersedak 2.
  • Ingat ketika Anda memanggil skrip PowerShell, berikan argumen dengan spasi, bukan koma.
  • Meskipun saya tidak melihatnya dalam aturan, sepertinya semua orang menggunakan nama file wordlist.txtyang bisa mencukur beberapa byte.
  • Kecepatan seharusnya tidak menjadi masalah. Ini tampaknya berjalan instan untuk saya. .\hangman.ps1 7 0Laju paling lambat yang bisa saya lakukan ( ) berjalan sekitar 350ms.

1
Selamat datang di Programming Puzzles & Code Golf Stack Exchange, jawaban pertama yang bagus! :)
Gagang Pintu

@ Doorknob terima kasih banyak!
briantist

6

Python3, 299 Bytes

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])

cukup yakin ini bisa bermain golf lebih lanjut.

Memfilter daftar kata untuk pencocokan potensial, membuat peta frekuensi karakter, dan memilih karakter yang paling sering muncul yang belum diambil.


Anda punya banyak ''.join(..). Jika semua elemen di dalamnya adalah string dengan panjang 1, Anda dapat mengubahnya ke '..'[2::5], di mana apostrof adalah backticks.
Kade

3

Java, 646 640 631 607 606 (pendek) 790 789 779 (cepat) byte

PENDEK

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

CEPAT

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:"");}}

Masukkan file daftar kata ke dalam folder.

Algoritma versi pendek

  1. Memuat Args
  2. Buat kata yang kami coba tebak {'p', 'e', ​​'\ 0', 'p', '\ 0', 'e'}
  3. Muat Daftar Kata
  4. Pergi melalui setiap baris WordList
  5. Berhenti ketika Anda menemukan bahwa seluruh kata cocok dengan kondisi ini di p[i] == q[i] || q[i] == '\0'mana p adalah kata dari daftar kata (array char), dan q adalah kata yang kami coba tebak
  6. Loop melalui karakter yang salah dan bandingkan dengan kata
  7. Cetak karakter pertama yang hilang

Algoritma versi panjang

  1. Langkah pendek 1-7
  2. Menambahkan jumlah karakter dalam array n untuk karakter yang hilang
  3. Ulangi sampai semua kata keluar
  4. Cetak karakter yang memiliki jumlah tertinggi

dapatkah saya menghapus impor?
Roberto Anic Banić

Apakah boleh menghapus impor java dalam kode golf?
Roberto Anic Banić

tidak apa-apa, selama Anda tentukan saya harus mengimpornya (jika tidak jelas);)
WayToDoor

Kk. Saya akan memperbaruinya ketika saya kembali ke rumah. Pergi membeli router baru :) dan Cat5e 90 kaki
Roberto Anic Banić

1
Saya tidak berpikir itu berfungsi untuk kata-kata lebih dari 9 huruf. Coba gunakan "prospektif" dari daftar kata dengan input "6 XBZ 1P 5P 6E 11E" Mungkin mengubah loop pertama ke q [Integer.parseInt (a [i] .substring (0, a [i] .length () - 1) ) -1] = (char) (a [i] .charAt (a [i] .length () - 1) +32); Juga, tip bermain golf: Coba gunakan Pemindai s = Pemindai baru (java.io.File baru ("wordlist.txt"));
tanda

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;

Ia bekerja sebagai berikut:

  1. Membuat pola regex untuk mencocokkan huruf yang sudah ditebak sejauh ini
  2. Iterasi setiap kata dari file
  3. Jika kata itu cocok dengan regex, itu memastikan bahwa itu tidak mengandung salah satu huruf yang salah
  4. Menambahkan penghitung untuk setiap huruf yang mungkin dari kata itu (berdasarkan posisi mereka)
  5. Menghasilkan surat dengan penghitung tertinggi

Asumsi:

  • PHP >=5.4
  • Ada wordlist.txtfile di folder saat ini

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 1Mencoba membuatnya menebak orang
WayToDoor

1
Terima kasih telah menunjukkannya. Ada bug kecil dalam kode. Saya memperbaruinya (masih 346 byte).
Razvan

1

Powershell, 153 byte

Terinspirasi oleh jawaban briantist .

Sebagai penulis lain saya menggunakan nama file wordlist.txt. Meskipun dimungkinkan untuk memilih nama yang lebih pendek.

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]

Skrip uji yang kurang golf:

$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

Keluaran:

c
r
l

Nilai variabel untuk &$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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.