Risolvi la notazione del problema matematico


14

Immagina di avere un numero infinito di problemi a casa (!) Ognuno con un numero intero.

Math Problem Notation è una notazione per la descrizione di sottoinsiemi del problema utilizzando gli identificatori del problema.

Un'espressione MPN può consistere in diverse cose:

  • Un singolo valore Questo rappresenta un insieme contenente il numero: 99 -> {99}.
  • Una gamma semplice. Questo rappresenta l'insieme contenente tutti i numeri dall'inizio alla fine dell'intervallo: 10~13 -> {10, 11, 12, 13}. Se i lati sinistro o destro sono mancanti, allora si presume che siano rispettivamente -Infinity o infinito: ~10 -> {x|x ≤ 10}; ~ -> ℤ.
  • Un'espressione MPN, seguita da "skip" e un'altra espressione MPN. Questo rappresenta la differenza tra i due gruppi: 10~20 skip 12~14 -> {10, 11, 15, 16, 17, 18, 19, 20}.
  • Due espressioni MPN, separate da una virgola. Questo rappresenta l'unione di due insiemi: 1,8~9,15~17 -> {1,8,9,15,16,17}.

L'operatore "salta" si lega più strettamente dell'operatore virgola, quindi 16,110~112 skip 16 -> {16,110,111,112}(16 non è incluso nel set {110,111,112}, quindi i 16 esclusi non contano.)

Puoi anche mettere espressioni tra parentesi per chiarire le ambiguità: 1~9 skip (2~8 skip (3~7 skip (4~6 skip 5))) -> {1,3,5,7,9}

Questa è la grammatica:

<expr>  ::= "(" <expr> ")"
         || <number>
         || [<number>] "~" [<number>]
         || <expr> "skip" <expr>
         || <expr> "," <expr>

Il tuo compito è scrivere un programma che accetta due input:

  • Un'espressione MPN
  • Un numero

e genera un valore di verità o falsità a seconda che il problema si trovi nell'insieme descritto dall'espressione MPN.

specificazioni

  • Puoi presumere che il primo input sia un'espressione MPN ben formata (cioè che corrisponda alla grammatica sopra)
  • I numeri in un'espressione MPN sono sempre numeri interi. Possono essere negativi o zero, ma non avranno mai una parte frazionaria.
  • Questo è , quindi vince l'invio valido più breve (misurato in byte).
  • Puoi usare caratteri diversi per ~e ,, se lo desideri.

Casi test

10~20             14 -> True
10~20             20 -> True
10~20 skip 14~18  17 -> False
~ skip 6          8  -> True
16,17 skip 16     16 -> True
(16,17) skip 16   16 -> False
~10,5~            8  -> True
~10,5~            4  -> True
6 skip 6,~        6  -> True

È possibile usare altri caratteri per rappresentare gli operatori? Ad esempio usando # invece di ~
rahnema1

1
@ rahnema1 per ~e ,, ma non per skip.
Esolanging Fruit

3
Perché ~ 10,5 ~ è falso per 4? Perché questa è l'unione di -infinito con 10 e 5 con l'infinito, il primo dei quali include 4
ev3commander

@ ev3commander Edited. Ho sempre incasinato i miei casi di test. Scommetto che le mie sfide sarebbero più chiare se non le aggiungessi: P
Esolanging Fruit

1
@ Challenger5 Ho aggiunto un caso di prova 6 skip 6,~che credo di aver interpretato correttamente. Le altre 2 risposte finora non lo soddisfano (di nuovo, supponendo che io stia interpretando correttamente). Se ho frainteso, correggilo e chiariscilo, ma dalla mia comprensione, dovrebbe corrispondere a tutto (è l'unione di un set che non corrisponde a un set che corrisponde a tutto). Questi sono i tipi di casi di cui parlavo prima che penso possano aiutare molto quando testiamo le nostre soluzioni.
Briantist

Risposte:


3

PowerShell , 189 195 byte

param($m,$q)('$m',"'(\d*)~(\d*)','($q-ge(`$1)-and$q-le(`$2))'","'\(\)',$q","'((?<=,|skip )\d+|\d+(?=,| skip))','($q-eq`$1)'","'skip','-and!'"-join'-replace'|iex|% Sp* ','|%{"($_)"})-join'-or'|iex

Spiegazione

Mi sono reso conto presto che gli infiniti lo rendono insostenibile per generare array e testare valori.

Ho esaminato gli intervalli ma in .Net non hanno l'intervallo necessario (la lunghezza dell'intervallo è limitata a un numero intero con segno (32 bit), quindi anche se fosse corretto limitare l'intervallo a un int con segno a 32 bit , Non sarei stato in grado di gestire tutte le gamme.

Quindi ho iniziato a pensarci solo in termini di inizio e fine, e alla fine una serie di test booleani e ho iniziato a creare un gruppo di regex sostituisce per trasformare un MPN in un'espressione booleana che PowerShell capisce.

Fondamentalmente ho suddiviso questo in alcune regole:

  • Gli intervalli erano più facili da lavorare per primi perché non possono essere espressioni su entrambe le estremità, ma l'apertura a tempo indeterminato è stata una sofferenza da implementare a breve. La premessa è 2~8come dire n >=2 && n <=8, ma quando manca una delle estremità, tralasciare &&il lato mancante. Quando mancavano entrambi, inizialmente lo avrei sostituito $true. Quello che ho finito per fare non è stato davvero testare i lati mancanti, ma mi sono assicurato di inserire tutti i numeri ().
  • e quindi fare una sostituzione diretta che sostituisce le parentesi vuote ()con il valore di input. Quindi, nel caso di un MPN come ~8con un valore di input di 55, il primo rimpiazzo genererà (55-ge()-and55-le(8)), quindi il secondo rimpiazzo arriva per farlo(55-ge55-and55-le(8)) , annullando sostanzialmente quella parte dell'intervallo.
  • Successivamente ho dovuto gestire i singoli numeri nella MPN, ma ho dovuto fare attenzione a non pasticciare con quelli che avevo inserito in precedenza. In realtà sono solo numeri in ,elenchi separati da virgole e numeri individuali prima o dopo un skip, quindi ho usato sfortunatamente lunghe ricerche.
  • skipè fondamentalmente la stessa -and -notcosì io una scala di sostituire skipa -and!(usando !come abbreviazione di-not ).
  • La prossima cosa delicata fu il basso ordine di precendenza per le rimanenti virgole. Inizialmente li ho appena sostituiti con, -orma non ha tenuto conto delle espressioni successive, quindi è 16,17 skip 16stato generato codice come ($n-eq16)-or($n-eq17) -and! ($n-eq16). Aveva bisogno di parentesi, ma sembrava inattuabile con una sostituzione diretta. Poiché tutte le altre cose sono state sostituite tranne le virgole e hanno la precedenza più bassa, ho semplicemente diviso l'intera stringa generata sulle virgole rimanenti, quindi ho avvolto ogni elemento tra parentesi e l'ho ricongiunto -or.

Alla fine il codice generato viene semplicemente reindirizzato in Invoke-Expression( iex) per essere eseguito e quindi otteniamo il risultato booleano (qui puoi vedere il codice che viene generato invece del risultato ).

Ci è voluto troppo tempo e sono sicuro che ci sia spazio per spremere qualche byte in più, ma non riesco più a guardarlo :-p


2

Perl, 99 130 byte

sub f{($_,$n)=@_;s/(-?\d+)?~(-?\d+)?|(-?\d+)/!(defined$3?$n!=$3:length$1&&$1>$n||length$2&&$n>$2)+0/ge;s/skip/&&!/g;s/,/||/g;eval}

Provalo su Ideone.

Ungolfed:

sub f {
    my ($e, $n) = @_;

    $e =~ s/(-?\d+)?~(-?\d+)?|(-?\d+)/ (defined($3) ? $n == $3 : (!length($1) || $n >= $1) && (!length($2) || $n <= $2)) + 0 /ge;
    $e =~ s/skip/ && ! /g;
    $e =~ s/,/ || /g;

    return eval($e);
}

1
Non riesce per ~ -2 per l'ingresso -2. Anche quando si inserisce -? prima di tutti e tre \ d *
Kjetil S.

@KjetilS. Risolto per numeri negativi e zero.
Denis Ibaev il

bel codice (l'analisi grammaticale completa spesso non è necessaria, le regex sono più facili)
Kjetil S.

1

JavaScript (ES6), 221 292 287 309 274 277 278 byte

(-5 byte grazie a Okx)

(j,v,m=1/0,Z=/(skip)([^,]+)/g)=>eval(j[M='replace'](/(-?\d*)~(-?\d*)/g,(e,a,b)=>(a[M]('-','#')||-m)+'<='+(T=v[M]('-','#'))+'&&'+T+'<='+(b[M]('-','#')||m))[M](Z,i=o=>o.match(Z)?i(o[M](Z,'&&!($2)')):o)[M](/,/g,'||')[M](/(^|[^=&#\d])(\d+)([^<\d]|$)/g,'$1$2=='+v+'$3')[M](/#/g,'-'))

Wow. Questo non è stato facile a causa di tutti i casi limite, ma penso di averlo fatto. Spero solo che non ci siano casi speciali che possano spezzare le espressioni regolari utilizzate. Lo giocherò di più ogni volta che posso.

Test snippet

D=(j,v,m=1/0,Z=/(skip)([^,]+)/g)=>eval(j[M='replace'](/(-?\d*)~(-?\d*)/g,(e,a,b)=>(a[M]('-','#')||-m)+'<='+(T=v[M]('-','#'))+'&&'+T+'<='+(b[M]('-','#')||m))[M](Z,i=o=>o.match(Z)?i(o[M](Z,'&&!($2)')):o)[M](/,/g,'||')[M](/(^|[^=&#\d])(\d+)([^<\d]|$)/g,'$1$2=='+v+'$3')[M](/#/g,'-'))
MPN Expression:<input type="text" value="1~9 skip (2~8 skip (3~7 skip (4~6 skip 5)))" id="MPN"></input>
<br>
Integer:<input type="number" id="INT" value=6></input>
<input type="button" value="Submit" onclick="T=r=>document.getElementById(r).value;console.log(D(T('MPN'),T('INT')))"></input>


@AriaAx Dovrebbe funzionare ora.
R. Kap

@ R.Kap È possibile utilizzare 1/0per Infinity.
Okx,

@ R.Kap Ho provato valore 6con l'espressione 6 skip 6,~che credo dovrebbe essere, truema restituisce false.
Briantist

@briantist In realtà, credo che dovrebbe tornare falsecome skipsi applica a tutto ciò che lo segue ( 6,~in questo caso) fintanto che è non è avvolto dentro parentesi. Pertanto, credo che dovrebbe tornare truesu (6 skip 6),~piuttosto che 6 skip 6,~con l'input intero 6.
R. Kap

@briantist In altre parole, non 6 skip 6,~dovrebbe corrispondere a nulla in quanto rappresenta la differenza tra il set {6}e il set {6,-Infinity...Infinity}.
R. Kap

0

Röda + bc, 183 byte

f x{{["x=",x,"\n"];replace" ","",",","||","skip\\(","&&!","skip([0-9~]+)","&&!($1)","(?<!~|\\d)(\\d+)(?!~|\\d)","x==$1","(\\d*)~(\\d*)","x>=($1)&&x<=($2)","\\(\\)",x;["\n"]}|exec"bc"}

È simile alla risposta di PowerShell (o penso di sì, non capisco PowerShell). Prende il numero come argomento e il codice come valore nel flusso di input, in questo modo:main { push("1~9") | f(5) } .

Penso che funzioni, almeno risolve tutti i casi di test. Lo script seguente può essere utilizzato per verificarlo.

main {
    readLines("/tmp/tests.txt") | split(sep=";") | for code, num, ans do
        push(code, " -> ")
        print(code) | replace" ","",",","||","skip\\(","&&!","skip([0-9~]+)","&&!($1)","(?<!~|\\d)(\\d+)(?!~|\\d)","x==$1","(\\d*)~(\\d*)","x>=($1)&&x<=($2)","\\(\\)",num
        a := push(code) | f(num) | head()
        result := push("OK") if [ (a = "0" and ans = "False") or (a = "1" and ans = "True") ] else push("FAIL")
        print code, " ; ", num, " -> ", a, " ", ans, " (", result, ")\n"
    done
}

E i test:

10~20;14;True
10~20;20;True
10~20 skip 14~18;17;False
~ skip 6;8;True
16,17 skip 16;16;True
(16,17) skip 16;16;False
~10,5~;8;True
~10,5~;4;True
6 skip 6,~;6;True
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.