Codice golf: risolvi un problema logico di Knights and Knaves analizzando l'inglese


16

sfondo

Ci sono due persone, Bill e John. Uno di questi è un cavaliere, che dice sempre la verità, e l'altro è un furfante, che dice sempre una bugia. Non sai chi è il cavaliere e chi è il furfante. Ogni persona poi dice diverse affermazioni su chi è il furfante e chi è il cavaliere. Usando queste informazioni, devi giungere a una conclusione su chi è il cavaliere e chi è il furfante.

Il problema logico di Knights and Knaves si basa sull'algebra di Booleen. Le parole che una persona dice formano un problema di soddisfacibilità di Booleen. Le dichiarazioni del furfante devono essere sempre false e le dichiarazioni dell'altro cavaliere devono essere sempre vere.

John dice "Entrambi io sono un furfante e Bill è un furfante". Se Giovanni fosse il cavaliere, questa affermazione sarebbe falsa, quindi non può essere il cavaliere. Se fosse il furfante e Bill il cavaliere, questa affermazione sarebbe ancora falsa, anche se la prima parte è vera. Quindi, John è il furfante.

La sfida

La tua sfida è quella di scrivere il programma più breve possibile che prenderà un elenco di dichiarazioni fatte da ogni persona e capirà chi è il furfante e chi è il cavaliere. Ci sono molti dettagli da trattare, quindi questo problema è descritto in tre sezioni.

Ingresso

L'input sarà composto da due righe seguite da una nuova riga. Ogni riga darà il nome di uno dei personaggi, seguito da due punti, seguito da diverse frasi dette da quella persona. Se una persona è il cavaliere, allora tutte le sue frasi saranno vere e tutte le frasi del furfante saranno false. La prima lettera di una frase sarà sempre in maiuscolo e ogni frase terminerà con un punto. Ecco un esempio:

Joe: Both I am a knight and neither Steve is a knave nor I am a knave.
Steve: Joe is a knave. Either Joe is a knight or I am a knight.

parsing

Ogni frase è composta da almeno una clausola. Ogni clausola contiene una delle diverse cose (speriamo che tu possa capire la mia notazione):

both [clause] and [clause]
either [clause] or [clause]
neither [clause] nor [clause]
[I am | (other person's name) is] a [knight | knave]

Questo è inequivocabile perché può essere compreso in un modo simile alla notazione polacca. Ecco un esempio di una frase:

Both I am a knight and neither Steve is a knave nor I am a knave.

La traduzione in algebra di Booleen è semplice. Le istruzioni "both" sono AND, le istruzioni "ither "sono XOR e le istruzioni" none "sono NOR.

(I am a knight) AND ((Steve is a knave) NOR (I am a knave))

Produzione

L'output sarà composto da due righe. Ogni riga è composta dal nome di una persona (in ordine) e quindi indica se è il cavaliere o il furfante. Ci saranno sempre un cavaliere e un furfante. Ecco l'output per l'esempio sopra:

Joe is the knave.
Steve is the knight.

Se il problema è irrisolvibile (o non si può dire chi è cosa, o non esiste una soluzione), il programma può fare qualsiasi cosa TRANNE produrre un output valido.

Più esempi

Ingresso

Sir Lancelot: Either both I am a knight and Merlin is a knave or both I am a knave and Merlin is a knight.
Merlin: Either both I am a knight and Sir Lancelot is a knight or both I am a knave and Sir Lancelot is a knave.

Produzione

Sir Lancelot is the knight.
Merlin is the knave.

Ingresso

David: Neither I am a knave nor Patrick is a knight. Either I am a knight or Patrick is a knave.
Patrick: Either I am a knight or both I am a knight and David is a knight.

Produzione

David is the knave.
Patrick is the knight.

Ingresso

Lizard: I am a knight.
Spock: I am a knave.

Un possibile output

Rock Paper Scissors

Regole, regolamenti e note

  1. Si applicano le regole standard per il golf
  2. Il tuo programma deve essere composto solo da ASCII stampabile
  3. Tutti gli ingressi e le uscite provengono da STDIN e STDOUT

Che dire della distinzione tra maiuscole e minuscole? La descrizione della sintassi è in minuscolo, i tuoi esempi sono in maiuscolo. L'insensibilità ai casi è un requisito?
ugoren,

La prima lettera di ogni frase sarà scritta in maiuscolo, ma a parte questo solo i nomi sarebbero in maiuscolo. Che problema specifico stai vedendo?
PhiNotPi

Dal momento che si utilizza la corretta capitalizzazione inglese, la prima lettera in entrambi / o / né dipende dal contesto. Immaginare che non distingue tra maiuscole e minuscole è il modo più semplice per affrontarlo.
ugoren,

Risposte:


6

Python, 491 caratteri

Funziona convertendo ciascuna riga in un'espressione Python e sviluppandola.
Il fante e il cavaliere vengono valutati come 0 e 1. Per le due persone, proviamo entrambe le opzioni.
Ad esempio, Joe: Steve is a knavediventa Joe==(Steve==knave). In questo modo, se Joeè un furfante, il risultato è vero solo se sta mentendo.
Ricevi brutti errori quando è impossibile o indeciso. Se impossibile, r[0]è un errore di indice, perché rè vuoto. Se indecidibile, concatenare r[1:]un elenco di stringhe causa problemi.

import sys
def p():
    a=s.pop(0)
    try:return{"both":"(%s*%s)","either":"(%s|%s)","neither":"(1-(%s|%s))"}[a.lower()]%(p(),p())
    except KeyError:r=s[2];del s[:4];return"(%s==%s)"%((a,m)[a=="I"],r)
x=[];w=[]
for l in sys.stdin:
    m,l=l.split(":");w+=[m]
    for s in l.split("."):
        s=s.split()
        while s:x+=["%s==%s"%(m,p())]
k=("knave","knight")
r=[a for a in[{w[0]:z,w[1]:1-z}for z in(0,1)]if all(eval(l,{k[0]:0,k[1]:1},a)for l in x)]
print"\n".join(x+" is the "+k[r[0][x]]+"."for x in w+r[1:])

3

Rubino, 352 caratteri

La soluzione è diventata piuttosto lunga, quindi potrebbe esserci ancora un posto dove giocare a golf. Richiede che l'input sia ben formato (come tutti gli esempi sopra riportati - ma non tentare di nominare una persona "Entrambi" ...).

q=->{gets.split /: |\.\s/}
C,*E=q[]
D,*F=q[]
r=->c,m{t=c.shift;t[1]?(x=r[c,m];c.shift;y=r[c,m];t[0]==?B?x&y :t[0]==?E?x^y :1-(x|y)):(c.shift(2);h=c.shift[2]==?I?m : 1-m;t==?I?h :1-h)}
s=->u,v,b{u.map{|c|r[c.gsub(v,?J).upcase.split,b]==b}.all?}
t=->b{s[E,D,b]&&s[F,C,1-b]}
u=->v,b{v+" is the kn#{b ?:ight: :ave}."}
puts t[1]^t[0]&&u[C,t[1]]+$/+u[D,t[0]]

Sembra che si interrompano i punti nell'output, ma sembra una correzione di due caratteri.
PhiNotPi

1
@PhiNotPi Fatto. È stata una correzione a zero caratteri ...
Howard

0

Perl - 483 byte

(($a,$b),($c,$d))=map{split':'}@ARGV;$h='y';$i='x';$s=' is the kn';$g='ight.';$v='ave.';for($b,$d){$_.=' 1';s/ am a | is a /==/g;s/knight/1)/g;s/knave/0)/g;s/I=/(\$$i=/g;s/($a|$c)=/(\$$h=/g;s/([^.]+)\./($1)and/g;s/ or / xor /g;s/ nor / or /g;while(s/(?<= )(\w+ \((?:[^()]+|(?1))\) \w+ \((?:[^()]+|(?1))\))/($1)/g){}s/neither/!/gi;s/both|either//gi;$h=$i++}$x=0;$y=1;$k=!eval($b)&&eval($d);$x=$y--;$n=!eval($d)&&eval($b);print"$a$s$v
$c$s$g"if($k&&!$n);print"$a$s$g
$c$s$v"if($n&&!$k)

Simile alla soluzione Python. Riduce le frasi in codice Perl e poi le evals. Può stampare un output quasi valido se l'input è strano ma non stampa nulla se è indecidibile. Un input ben formato funziona come previsto. Le frasi vengono passate nella riga di comando tra virgolette e non sono necessari flag speciali.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.