Implementa un calcolatore grafico


12

Ci sono state molte domande riguardanti i calcolatori; tuttavia, non sembra che nessuno implichi l'implementazione di una calcolatrice grafica.

La sfida

Devi scrivere un programma completo che prende più formule come input da STDIN e le rappresenta graficamente su STDOUT. L'input prenderà la forma f1(x)=x^2-x-1. Ci sarà un fseguito da un numero 0-9 (incluso), seguito da (x)=, seguito dalla formula da rappresentare graficamente. Il tuo programma dovrebbe essere in grado di prendere input, grafico, prendere più input, grafico, ecc.

Questo è il codice golf.

Il grafico dovrebbe avere un intervallo dell'asse X da -5 a 5, con una risoluzione di almeno un punto ogni 1/2 unità. I requisiti dell'asse Y sono gli stessi. Questo può sembrare un piccolo intervallo rispetto ai calcolatori moderni, ma molto probabilmente sarà banale aumentarlo. Il grafico dovrebbe avere l'asse disegnato su di essi, con segni di spunta sotto forma di +numeri interi.

La formula deve essere valutata con il normale ordine di funzionamento. Non ci saranno asintoti verticali / regioni indefinite in queste formule. La variabile sarà sempre x. Se vengono inserite due formule con lo stesso numero di equazione, quella più vecchia deve essere cancellata e sostituita con la nuova formula. Le formule vuote devono essere valutate a zero. Poiché è probabile che la formula non fornisca sempre un bel multiplo di 1/2, devi arrotondare al 1/2 più vicino.

Quando una formula viene rappresentata graficamente, la sua linea dovrebbe essere formata dal numero della formula. Quando una linea attraversa un asse, l'asse deve essere disegnato in alto. Quando due linee si incrociano, non importa quale sia mostrato.

Esempio di input

f1(x)=x+1

Produzione

          +       1
          |      1
          +     1
          |    1
          +   1
          |  1
          + 1
          |1
          +
         1|
+-+-+-+-+-+-+-+-+-+-+
       1  |
      1   +
     1    |
    1     +
   1      |
  1       +
 1        |
1         +
          |
          +

Ingresso

f2(x)=(x^2)^0.25

Produzione

          +       1
          |      1
          +     1
          |    1
          +   1
          |  1
2222      + 1    2222
    222   |1  222
       22 + 22
         2|2
+-+-+-+-+-+-+-+-+-+-+
       1  |
      1   +
     1    |
    1     +
   1      |
  1       +
 1        |
1         +
          |
          +

Ingresso

f1(x)=-x  

(nota, è accettabile per il tuo programma rifiutare questo input e solo tranne 0-xo x * -1, ma questo dovrebbe essere documentato)

Produzione

1         +
 1        |
  1       +
   1      |
    1     +
     1    |
2222  1   +      2222
    2221  |   222
       22 + 22
         2|2
+-+-+-+-+-+-+-+-+-+-+
          |1
          + 1
          |  1
          +   1
          |    1
          +     1
          |      1
          +       1
          |        1
          +         1

Risposte:


5

Perl, 177 caratteri (+1 interruttore della riga di comando)

perl -nE 's!\^!**!g;s!x!(\$k/2-6)!g;s/\d.*=/;/;$f[$&]=$_;my%a;for$k(@x=2..22){$i=0;$a{int 12.5-2*eval}[$k-2]=$i++for@f}$p="|";$$_[10]=$p^=W,$a{12}=[$p."-+"x10],say map$_//$",@$_ for@a{@x}'

Per questo meta thread , credo che questo dovrebbe contare come 178 caratteri in totale.

Come la soluzione di Ruby, sto utilizzando anche evale la sostituzione ^con **.

L'analisi dell'input è sia incredibilmente fragile che incredibilmente robusta allo stesso tempo: f1(x)=può essere scritta come f 1 ( x ) =o foo 1 bar =o anche solo 1=, ma potrebbero succedere cose molto strane se lo sostituissi fcon qualcosa che non è un'affermazione Perl valida e senza effetti collaterali. Sei stato avvertito.

Altri dettagli di interesse includono il modo in cui viene disegnato l'asse verticale, che sfrutta il fatto che lo XOR bit a bit dei caratteri +ed |è W. Ovviamente, questo non funzionerà sui sistemi EBCDIC.

L'output viene sottoposto a rendering in un hash di array, non in un array di array: si scopre che sono necessari meno caratteri per troncare esplicitamente le chiavi di hash a numeri interi e quindi eseguire il ciclo su una sezione di hash di quella necessaria per garantire che un array non lo sia indicizzato con valori negativi. Potrei radere altri due caratteri se non fosse per il modo fastidioso che Perl inttronca i valori negativi verso zero, il che mi ha costretto a numerare le righe di output da 2 a 22 anziché da 0 a 20 per evitare artefatti di arrotondamento sul bordo superiore dell'area di uscita.

Uso la conversione da stringa a numero liberale di Perl nell'analisi dell'input, dove uso l'intera stringa 1(x)=come indice di array (viene convertita in solo 1).

Potrei anche salvare altri tre caratteri (e rendere l'analisi leggermente più robusta) sostituendoli s/\d.*=/;/;$f[$&]=$_con /\d.*=/;$f[$&]=$', ma poi dovrei spendere lo stesso numero di caratteri extra per scrivere $'come $'\''in una stringa di shell a virgoletta singola. Suppongo che tecnicamente non avrei dovuto contarli, ma sembra un po 'come imbrogliare.


6

Rubino, 200 caratteri

f={}
r=0..20
(f[gets[1]]=$_[6..-1].gsub /\^/,'**'
s=r.map{' '*21}
f.map{|n,k|r.map{|y|x=y*0.5-5
v=(2*eval(k)).round
v.abs<11&&y!=10&&s[10-v][y]=n
s[y][10]='+|'[y%2]
s[10][y]='+-'[y%2]}}
puts s)while 1

Un'implementazione semplice del rubino che utilizza il valutatore standard per le espressioni ( ^sarà sostituito in modo che gli esempi sopra riportati funzionino bene). Non è molto robusto e assume l'input esattamente come specificato nella domanda.


Sulla quinta riga, potrebbe cambiare y*0.5per y/2e sbarazzarsi di due personaggi? Non conosco Ruby, quindi potrei non avere ragione.
PhiNotPi il

2
@PhiNotPi Purtroppo questo non funzionerà. y/2fa divisione intera.
Howard,

Puoi usare loop{}invece di ()while 1?
defhlt

Trovato questo tramite il collegamento sulla barra laterale sul lato destro. Questo è abbastanza ben fatto. Mi sono divertito un po 'a cercare di ridurlo, ma ho trovato solo 9 byte , un byte basandosi sui letterali razionali introdotti in ruby ​​2.1 (?).
Blutorange,

5

Python 2: 320 caratteri

N=20
r=range(N+1)
d={}
while(1):
 l=raw_input()
 d[l[1]]=l[6:].replace('^','**')
 g=[[' ']*(N+1) for i in r]
 for n,f in d.items():
  for x in r:
   v=N/2+int(round(2*eval(f.replace('x','(%f)'%(x/2.0-N/4)))))
   if 0<=v<=N:g[N-v][x]=n
 for i in r:
  g[i][N/2]='+|'[i%2]
  g[N/2][i]='+-'[i%2]
 for l in g:print''.join(l)

Probabilmente potrebbe essere abbreviato, ma sono un po 'un principiante in questo :)

Fare Nuna variabile spreca 9 caratteri, ma mi piace così.

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.