Implemente una calculadora gráfica

12

Ha habido muchas preguntas relacionadas con calculadoras; sin embargo, no parece que ninguno implique implementar una calculadora gráfica.

El reto

Debe escribir un programa completo que tome múltiples fórmulas como entrada de STDIN y las grafica en STDOUT. La entrada tomará la forma f1(x)=x^2-x-1. Habrá fseguido de un número 0-9 (inclusive), seguido de (x)=, seguido de la fórmula para representar gráficamente. Su programa debería ser capaz de tomar entradas, gráficos, tomar más entradas, gráficos, etc.

Este es el código de golf.

Su gráfico debe tener el rango del eje X de -5 a 5, con una resolución de al menos un punto cada 1/2 unidad. Los requisitos del eje Y son los mismos. Esto puede parecer un rango pequeño en comparación con las calculadoras modernas, pero lo más probable es que sea trivial para aumentar esto. El gráfico debe tener el eje dibujado sobre ellos, con marcas de verificación en forma de +números enteros.

La fórmula debe evaluarse con el orden normal de operación. No habrá asíntotas verticales / regiones indefinidas en estas fórmulas. La variable siempre será x. Si se ingresan dos fórmulas con el mismo número de ecuación, la más antigua debe borrarse y reemplazarse con la nueva fórmula. Las fórmulas en blanco deben evaluar a cero. Como es probable que la fórmula no siempre dé un buen múltiplo de 1/2, debe redondear al 1/2 más cercano.

Cuando se representa gráficamente una fórmula, su línea debe formarse a partir del número de la fórmula. Cuando una línea cruza un eje, el eje debe dibujarse en la parte superior. Cuando dos líneas se cruzan, no importa cuál se muestre.

Entrada de ejemplo

f1(x)=x+1

Salida

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

Entrada

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

Salida

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

Entrada

f1(x)=-x  

(tenga en cuenta que es aceptable que su programa rechace esta entrada y solo excepto 0-x o x * -1, pero esto debe documentarse)

Salida

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
PhiNotPi
fuente

Respuestas:

5

Perl, 177 caracteres (cambio de línea de comando +1)

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}'

Según este metahilo , creo que esto debería contar como 178 caracteres en total.

Al igual que la solución Ruby, también estoy usando evaly reemplazando ^con **.

El análisis de entrada es increíblemente frágil e increíblemente robusto al mismo tiempo: f1(x)=puede escribirse como f 1 ( x ) =o foo 1 bar =simplemente 1=, pero podrían ocurrir cosas muy extrañas si reemplazaras fpor algo que no sea una declaración Perl válida y sin efectos secundarios. Usted ha sido advertido.

Otros detalles de interés incluyen la forma en que se dibuja el eje vertical, que explota el hecho de que el XOR bit a bit de los personajes +y |es W. Obviamente, esto no funcionará en los sistemas EBCDIC.

La salida se procesa en un hash de matrices, no en una matriz de matrices; resulta que se necesitan menos caracteres para truncar explícitamente las claves hash a enteros y luego recorrer un segmento hash de lo que se necesita para garantizar que una matriz no sea indexado con valores negativos. Podría eliminar dos caracteres más si no fuera por la molesta forma en que Perl inttrunca los valores negativos hacia cero, lo que me obligó a numerar las filas de salida del 2 al 22 en lugar del 0 al 20 para evitar redondear los artefactos en el borde superior del área de salida.

Hago uso de la conversión liberal de cadena a número de Perl en el análisis de entrada, donde uso toda la cadena 1(x)=como un índice de matriz (se convierte en solo 1).

También podría guardar tres caracteres más (y hacer que el análisis sea un poco más robusto) reemplazándolo s/\d.*=/;/;$f[$&]=$_con /\d.*=/;$f[$&]=$', pero luego tendría que gastar la misma cantidad de caracteres adicionales para escribir $'que $'\''en una cadena de shell entre comillas simples. Supongo que técnicamente no tendría que contarlos, pero se siente como hacer trampa.

Ilmari Karonen
fuente
6

Ruby, 200 caracteres.

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

Una implementación simple de ruby ​​usando el evaluador estándar para expresiones ( ^será reemplazado para que los ejemplos dados arriba funcionen bien). No es muy robusto y asume la entrada exactamente como se especifica en la pregunta.

Howard
fuente
En la quinta línea, se puede cambiar y*0.5a y/2y deshacerse de dos personajes? No conozco a Ruby, así que puede que no tenga razón.
PhiNotPi
2
@PhiNotPi Lamentablemente, esto no funcionará. y/2hace división entera.
Howard
¿Se puede usar en loop{}lugar de ()while 1?
defhlt
Encontré esto a través del enlace en la barra lateral a la derecha. Esto está bastante bien hecho. Me divertí un poco tratando de hacer esto más pequeño, pero solo encontré 9 bytes , un byte confiando en los literales racionales introducidos en ruby ​​2.1 (?).
blutorange
5

Python 2: 320 caracteres

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)

Probablemente podría acortarse, pero soy un poco novato en esto :)

Hacer Nuna variable desperdicia 9 caracteres, pero así me gusta más.

NicolasP
fuente