Odszyfruj symbole matematyczne

13

Jeśli przeczytałeś książkę Kontakt Carla Sagana, to wyzwanie może ci się wydawać znajome.


Biorąc pod uwagę zbiór równań matematycznych składający się z liczby, nieznanego operatora, innej liczby i wyniku, wywnioskuj, które operatory reprezentują dodawanie, odejmowanie, mnożenie lub dzielenie.

Każde równanie wejściowe zawsze będzie się składało

  • nieujemna liczba całkowita
  • jedna z liter A, B, C, lubD
  • kolejna nieujemna liczba całkowita
  • charakter =
  • końcowa nieujemna liczba całkowita

połączone razem. Na przykład możliwe dane wejściowe 1A2=3, z których można wywnioskować, że Areprezentuje dodanie. Każda z liczb całkowitych będzie wystarczająca 0 ≤ x ≤ 1,000.

Jednak nie zawsze jest to takie proste. Możliwe jest niejednoznaczność między:

  • 5A0=5: dodawanie odejmowanie
  • 1A1=1: mnożenie / dzielenie
  • 0A5=0: mnożenie / dzielenie
  • 2A2=4: dodawanie / mnożenie
  • 4A2=2: odejmowanie / dzielenie
  • 0A0=0: dodawanie / odejmowanie / mnożenie

i tak dalej. Wyzwaniem jest wykorzystanie tej zdolności do zawężenia wyboru w połączeniu z procesem eliminacji, aby dowiedzieć się, jaki operator reprezentuje każdą literę. (Zawsze będzie co najmniej jedno równanie wejściowe i zawsze będzie możliwe jednoznaczne, jednoznaczne dopasowanie każdej litery użytej na wejściu z jednym operatorem).

Załóżmy na przykład, że dane wejściowe to następujące równania:

  • 0A0=0: zawęża to A do dodawania, odejmowania lub mnożenia (nie można podzielić przez 0).
  • 10B0=10: B musi być dodawaniem lub odejmowaniem.
  • 5C5=10: C jest oczywiście dodawaniem, co powoduje odejmowanie B, co powoduje pomnożenie A.

Dlatego dane wyjściowe dla tych równań wejściowych powinny być zgodne Az *, B z -i Cz +.

Dane wejściowe można podać jako pojedynczy ciąg rozdzielany spacjami / przecinkami lub tablicę ciągów, z których każdy reprezentuje jedno równanie. Dane wyjściowe mogą być pojedynczym ciągiem ( "A*B-C+"), tablicą ( ["A*", "B-", "C+"]) lub słownikową / dictową tablicą 2D ( {"A": "*", ...}lub [["A", "*"], ...]).

Możesz założyć, że liczba nigdy nie zostanie podzielona przez inną liczbę, przez którą nie jest podzielna (więc nie musisz się martwić, czy dzielenie powinno być zmiennoprzecinkowe, czy obcięte).

Ponieważ jest to , wygrywa najkrótszy kod w bajtach.

Przypadki testowe:

In                       Out
-------------------------------
0A0=0 10B0=10 5C5=10     A*B-C+
100D100=10000            D*
4A2=2 4B2=2 0A0=0        A-B/
15A0=15 4B2=2 2C2=0      A+B/C-
1A1=1 0A0=0              A*
0A0=0 2A2=4 5B0=5 2B2=4  A*B+
2A2=4 0C0=0 5B0=5 5A0=5  A+B-C*
0A1000=0 4A2=2           A/
Klamka
źródło
1
Czy wykonujemy (okrojony) podział na liczby całkowite?
Martin Ender,
@ MartinBüttner Możesz założyć, że nigdy nie będzie podziału przez liczbę, która nie spowoduje liczby całkowitej. (Poddane w wątpliwość.)
Klamka
Czy możemy generować jako słownik?
lirtosiast
@ThomasKwa Pewnie, słownik jest również akceptowalnym wyjściem.
Klamka
Większość przykładów jest niespójnych z „ zawsze będzie możliwe jednoznaczne, jednoznaczne określenie, która litera oznacza, który operator ”, chociaż są one zgodne z „ zawsze będzie można jednoznacznie określić, który operator jest reprezentowany przez każdą literę użytą w wejście ”.
Peter Taylor

Odpowiedzi:

9

MATL , 53 bajty

j61tthYX'+-*/'X{Y@!"t'ABCD'!XKX{@YXU?K@Y}hwxKGm1L3$).

Wykorzystuje aktualną wersję (10.1.0)

EDYCJA (12 czerwca 2016 r.): Aby dostosować się do zmian w języku, zastąp Y}przez gi 1L3$)przez Y). Poniższy link zawiera te modyfikacje

Wypróbuj online!

Wyjaśnienie

Testuje to wszystkie możliwe permutacje czterech operatorów w pętli, dopóki jedna permutacja nie spełni wszystkich równań.

Aby sprawdzić, czy równania są prawdziwe, stosuje się wyrażenie regularne w celu zastąpienia czterech liter operatorami (w kolejności podanej przez bieżącą permutację), a ciąg jest konwertowany na liczby (obliczane). Daje to tablicę z tyloma liczbami, ile równań, w których stają się prawdziwe 1równania i równania fałszywe 0. Jeśli ten wektor zawiera tylko 1wartości, jesteśmy skończeni.

Znalezione rozwiązanie przypisuje operatory do czterech liter, ale nie wszystkie muszą koniecznie pojawiać się na wejściu. Tak więc przeprowadzany jest końcowy test, aby odrzucić nieużywane litery (i odpowiadające im operatory).

j            % input data string
61           % '=' (ASCII)
tth          % duplicate twice and concat: '==' (ASCII)
YX           % regexprep to change '=' into '==' in input string
'+-*/'       % push string
X{           % transform into cell array {'+','-','*','/'}
Y@!          % all permutations, each in a column
"            % "for" loop. Iterate columns (that is, permutations)
  t          %   duplicate data string containing '=='
  'ABCD'!XK  %   create column array ['A';'B';'C';'D'] and copy to clipboard K
  X{         %   transform into column cell array {'A';'B';'C';'D'} 
  @          %   push column cell array with current permutation of operator symbols
  YX         %   regexprep. Replaces 'A',...,'D' with current permutation of operators
  U          %   convert to numbers, i.e. evaluate string
  ?          %   if all numbers are 1 (truthy result): found it! But before breaking...
    K        %     push column array ['A';'B';'C';'D']
    @Y}      %     push column array with current permutation of operator symbols
    h        %     concatenate horizontally into 4x2 char array
    wx       %     delete original input so it won't be displayed
    K        %     push ['A';'B';'C';'D']
    G        %     push input string
    m        %     logical index that tells which of 'A',...,'D' were in input string
    1L3$)    %     apply that index to select rows of the 4x2 char array
    .        %     we can now break "for" loop
             %   implicitly end "if"
             % implicitly end "for"
             % implicitly display stack contents
Luis Mendo
źródło
6

Python, 278 znaków

Moja pierwsza odpowiedź na temat kodu golfa ...

Jest to tylko funkcja implementująca algorytm brutalnej siły, którą nazywamy przekazywaniem argumentu ciągu równań.

from itertools import *
def f(s):
    l=list("ABCD")
    for p in permutations("+-*/"):
        t=s
        for v,w in zip(l+["="," "],list(p)+["=="," and "]):
            t=t.replace(v, w)
        try:
            o=""
            if eval(t):
                for c,r in zip(l,p):
                    if c in s:
                        o+=c+r
                return o
        except:
            pass
Kok
źródło
Nie jestem pewien, czy to działa, ale można zastąpić ["A","B","C","D"]z list("ABCD")?
Adnan
To, co sugeruje @Adnan, rzeczywiście działa. Możesz także usunąć spacje wokół =w definicji l.
Alex A.
@Adnan i Alex A. dzięki, edytowałem kod.
Bob
Oto 257 bajtów dla tego samego podejścia oraz środowisko testowe online.
Alex A.
Wprowadzono pewne zmiany - repl.it/BfuU . Możesz wyciąć o wiele więcej bajtów, wybierając inny format wyjściowy. To rozwiązanie działa tylko na python 3 btw ( 4A2=2 4B3=1).
Nabb
4

JavaScript (ES6), 213 208 bajtów

f=(l,s="+-*/",p="",r)=>s?[...s].map(o=>r=f(l,s[g="replace"](o,""),p+o)||r)&&r:l.split` `.every(x=>(q=x.split`=`)[1]==eval(q[0][g](/[A-D]/g,m=>p[(a="ABCD").search(m)])))&&a[g](/./g,(c,i)=>l.match(c)?c+p[i]:"")

Wyjaśnienie

Dane wejściowe i wyjściowe są łańcuchami.

Definiuje funkcję, fktóra pełni również funkcję funkcji rekurencyjnej do generowania wszystkich permutacji operatorów i testuje pełne permutacje za pomocą równań wejściowych eval.

f=(
  l,                          // l = input expression string
  s="+-*/",                   // s = remaining operators
  p="",                       // p = current permutation of operators
  r                           // r is here so it is defined locally
)=>
  s?                          // if there are remaining operators
    [...s].map(o=>            // add each operator o
      r=f(
        l,
        s[g="replace"](o,""), // remove it from the list of remaining operators
        p+o                   // add it to the permutation
      )
        ||r                   // r = the output of any permutation (if it has output)
    )
    &&r                       // return r
  :                           // else if there are no remaining operators
    l.split` `.every(x=>      // for each expression
      (q=x.split`=`)          // q = [ equation, result ]
      [1]==eval(              // if the results is equal to the eval result

        // Replace each letter with the current permutation
        q[0][g](/[A-D]/g,m=>p[(a="ABCD").search(m)])
      )
    )

    // If all results matched, add permutation symbols to present characters and return
    &&a[g](/./g,(c,i)=>l.match(c)?c+p[i]:"")

Test

Test nie używa domyślnych argumentów dla zgodności przeglądarki.

użytkownik 81655
źródło