Visualizzatore di equazioni d'arte Ascii


10

Gestire le equazioni in assenza di un buon editor di equazioni è disordinato e spiacevole. Ad esempio, se volessi esprimere un integrale e la sua soluzione, potrebbe assomigliare a questo:

Integrale [x ^ 3 e ^ (- mx ^ 2 b / 2), dx] = - ((2 + b m x ^ 2) / (b ^ 2 * e ^ ((b m x ^ 2) / 2) * m ^ 2))

A integrals.wolfram.com , questo si chiama "modulo di input". A nessuno piace vedere un'equazione in "forma di input". Il modo ideale di visualizzare questa equazione sarebbe:

inserisci qui la descrizione dell'immagine

(Wolfram chiama questa "forma tradizionale")

Per questo codegolf, scrivi un programma che prenderà alcune equazioni in "forma di input" come input e visualizzi quell'equazione in una rappresentazione ascii di "forma tradizionale". Quindi, per questo esempio, potremmo ottenere qualcosa del genere:

       /\      3
       |      x
       | ------------  dx = 
       |       2
      \/   (m x  b)/2
          e

              2
     2 + b m x
-(-----------------)
            2
   2  (b m x )/2  2
  b  e           m

Requisiti:

  1. Non mescolare, semplificare o riorganizzare l'input in alcun modo. Renderlo esattamente nella stessa forma che è stata descritta dall'input.
  2. Supporta le quattro operazioni matematiche di base (+, -, *, /). Quando non si moltiplicano due numeri adiacenti, il simbolo * è implicito e deve essere omesso.
  3. Il supporto per l'integrazione (come mostrato nell'esempio sopra) non è richiesto. Essere in grado di supportare input con funzioni come Integrate [...] o Sqrt [...] è un vantaggio.
  4. Supporta i poteri come mostrato nell'esempio sopra (l'ennesima radice può essere modellata aumentando all'1 / ennesima potenza).
  5. Le parentesi ridondanti (come quelle attorno al denomentatore e al numeratore della grande frazione nell'esempio sopra) dovrebbero essere omesse.
  6. L'espressione nel denominatore e nel numeratore di una frazione deve essere centrata sopra e sotto la linea di divisione orizzontale.
  7. Puoi scegliere se iniziare o meno una nuova riga dopo un segno di uguale. Nell'esempio sopra, viene avviata una nuova riga.
  8. L'ordine delle operazioni deve essere esattamente lo stesso nell'output come nell'input.

Alcuni esempi di input e output associati per testare la tua soluzione:

Ingresso:

1/2 + 1/3 + 1/4

Produzione:

1   1   1
- + - + -
2   3   4

Ingresso:

3x^2 / 2 + x^3^3

Produzione:

   2     3
3 x     3
---- + x   
 2

Ingresso:

(2 / x) / (5 / 4^2)

Produzione:

2
-
x
--
5
--
 2
4

Ingresso:

(3x^2)^(1/2)

Produzione:

    2 1/2
(3 x )

La tua domanda dovrebbe generalmente avere un tag che esprima il tipo di contest. Mi sono preso la libertà di aggiungerne uno perché hai detto "codegolf" nel testo.
dmckee --- ex gattino moderatore

3
Questo problema è troppo nebuloso per essere code-golf. Non dici quali costrutti devono essere supportati o come devono apparire. Supporterebbe solo +, -, * e / sarebbe sufficiente? Sigma deve essere supportato? E le lettere greche? Le possibili soluzioni alla domanda, come hai posto, potrebbero essere troppo varie nella funzionalità per essere confrontate per la lunghezza del codice.
MtnViewMark

@MtnViewMark, ho aggiunto alcuni "Requisiti" ... fammi sapere se il golf è migliore ora.
Ami,

@Ami - sì, molto.
MtnViewMark,

Sono d'accordo con MtnViewMark, questo sembra molto aperto e vago. Forse sarebbe meglio limitare l'input e l'output a una serie ben definita di test per gli scopi del golf. Hai fatto un'implementazione di riferimento?
Gnibbler,

Risposte:


10

Python 2, 1666 caratteri

Il layout è in realtà abbastanza semplice: è l'analisi dell'ingresso che è un dolore reale. Non sono ancora sicuro che sia completamente corretto.

import re,shlex
s=' '
R=range

# Tokenize.  The regex is because shlex doesn't treat 3x and x3 as two separate tokens.  The regex jams a space in between.                                                 
r=r'\1 \2'
f=re.sub
x=shlex.shlex(f('([^\d])(\d)',r,f('(\d)([^\d])',r,raw_input())))
T=[s]
while T[-1]:T+=[x.get_token()]
T[-1]=s

# convert implicit * to explicit *                                                                                                                                          
i=1
while T[i:]:
 if(T[i-1].isalnum()or T[i-1]in')]')and(T[i].isalnum()or T[i]in'('):T=T[:i]+['*']+T[i:]
 i+=1

# detect unary -, replace with !                                                                                                                                            
for i in R(len(T)):
 if T[i]=='-'and T[i-1]in'=+-*/^![( ':T[i]='!'
print T

# parse expression: returns tuple of op and args (if any)                                                                                                                   
B={'=':1,',':2,'+':3,'-':3,'*':4,'/':4,'^':5}
def P(t):
 d,m=0,9
 for i in R(len(t)):
  c=t[i];d+=c in'([';d-=c in')]'
  if d==0and c in B and(B[c]<m or m==B[c]and'^'!=c):m=B[c];r=(c,P(t[:i]),P(t[i+1:]))
 if m<9:return r
 if'!'==t[0]:return('!',P(t[1:]))
 if'('==t[0]:return P(t[1:-1])
 if'I'==t[0][0]:return('I',P(t[2:-1]))
 return(t[0],)

# parenthesize a layout                                                                                                                                                     
def S(x):
 A,a,b,c=x
 if b>1:A=['/'+A[0]+'\\']+['|'+A[i]+'|'for i in R(1,b-1)]+['\\'+A[-1]+'/']
 else:A=['('+A[0]+')']
 return[A,a+2,b,c]

# layout a parsed expression.  Returns array of strings (one for each line), width, height, centerline                                                                      
def L(z):
 p,g=z[0],map(L,z[1:])
 if p=='*':
  if z[1][0]in'+-':g[0]=S(g[0])
  if z[2][0]in'+-':g[1]=S(g[1])
 if p=='^'and z[1][0]in'+-*/^!':g[0]=S(g[0])
 if g:(A,a,b,c)=g[0]
 if g[1:]:(D,d,e,f)=g[1]
 if p in'-+*=,':
  C=max(c,f);E=max(b-c,e-f);F=C+E;U=[s+s+s]*F;U[C]=s+p+s;V=3
  if p in'*,':U=[s]*F;V=1
  return([x+u+y for x,u,y in zip((C-c)*[s*a]+A+(E-b+c)*[s*a],U,(C-f)*[s*d]+D+(E-e+f)*[s*d])],a+d+V,F,C)
 if'^'==p:return([s*a+x for x in D]+[x+s*d for x in A],a+d,b+e,c+e)
 if'/'==p:w=max(a,d);return([(w-a+1)/2*s+x+(w-a)/2*s for x in A]+['-'*w]+[(w-d+1)/2*s+x+(w-d)/2*s for x in D],w,b+e+1,b)
 if'!'==p:return([' -  '[i==c::2]+A[i]for i in R(b)],a+2,b,c)
 if'I'==p:h=max(3,b);A=(h-b)/2*[s*a]+A+(h-b+1)/2*[s*a];return(['  \\/|/\\  '[(i>0)+(i==h-1)::3]+A[i]for i in R(h)],a+3,h,h/2)
 return([p],len(p),1,0)

print'\n'.join(L(P(T[1:-1]))[0])

Per il grande input nella domanda, ottengo:

 /\         2                     2 
 |     - m x  b          2 + b m x  
 |     --------    = - -------------
 |  3      2                    2   
\/ x  e         dx         b m x    
                           ------   
                        2     2    2
                       b  e       m 

Ecco alcuni casi di test più complicati:

I:(2^3)^4
O:    4
  / 3\ 
  \2 / 

I:(2(3+4)5)^6
O:             6
  (2 (3 + 4) 5) 

I:x Integral[x^2,dx] y
O:   /\ 2     
  x  | x  dx y
    \/        

I:(-x)^y
O:     y
  (- x) 

I:-x^y
O:     y
  (- x)

Quest'ultimo è sbagliato, un errore di precedenza nel parser.


la base dell'argomento integrale non dovrebbe essere centrata in modo veritiero rispetto all'integrale? Attualmente sembra più un indice per l'integrale.
Joey,

Non è difficile da cambiare, ma sprecherebbe un po 'di spazio. Attualmente faccio il segno integrale abbastanza grande da coprire la sua discussione (con un minimo di 3).
Keith Randall,

Leggero golf: utilizzare le schede anziché i doppi spazi.
Calcolatrice
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.