Terapkan Kalkulator Grafik

12

Ada banyak pertanyaan yang melibatkan kalkulator; Namun, tampaknya tidak ada yang melibatkan penerapan kalkulator grafik.

Tantangan

Anda harus menulis program lengkap yang mengambil banyak rumus sebagai input dari STDIN dan grafik mereka ke STDOUT. Masukan akan berbentuk f1(x)=x^2-x-1. Akan ada fdiikuti oleh angka 0-9 (inklusif), diikuti oleh (x)=, diikuti oleh rumus untuk grafik. Program Anda harus dapat mengambil input, grafik, mengambil lebih banyak input, grafik, dll.

Ini golf kode.

Grafik Anda harus memiliki kisaran sumbu X dari -5 hingga 5, dengan resolusi setidaknya satu titik setiap 1/2 unit. Persyaratan sumbu Y sama. Ini mungkin tampak seperti kisaran kecil dibandingkan dengan kalkulator modern, tetapi kemungkinan besar akan sepele dalam meningkatkan ini. Grafik harus memiliki sumbu yang digambar di atasnya, dengan tanda centang dalam bentuk +pada bilangan bulat.

Formula harus dievaluasi dengan urutan operasi normal. Tidak akan ada asimtot vertikal / daerah tidak terdefinisi dalam formula ini. Variabel akan selalu x. Jika dua rumus dimasukkan dengan nomor persamaan yang sama, yang tertua harus dihapus dan diganti dengan rumus baru. Formula kosong harus dievaluasi menjadi nol. Karena kemungkinan formula tidak akan selalu memberikan kelipatan 1/2 yang bagus, Anda harus membulatkan ke 1/2 terdekat.

Ketika suatu rumus digambarkan, garisnya harus dibentuk dari jumlah rumus tersebut. Ketika sebuah garis melewati sumbu, sumbu harus digambarkan di atas. Ketika dua garis saling bersilangan, tidak masalah yang ditampilkan.

Contoh Input

f1(x)=x+1

Keluaran

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

Memasukkan

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

Keluaran

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

Memasukkan

f1(x)=-x  

(perhatikan, program Anda dapat menolak input ini dan hanya kecuali 0-x atau x * -1, tetapi ini harus didokumentasikan)

Keluaran

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
sumber

Jawaban:

5

Perl, 177 karakter (+1 command line switch)

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 thread meta ini , saya percaya ini harus dihitung sebagai total 178 karakter.

Seperti solusi Ruby, saya juga menggunakan evaldan mengganti ^dengan **.

Penguraian input sangat rapuh dan sangat kuat secara bersamaan: f1(x)=dapat ditulis sebagai f 1 ( x ) =atau foo 1 bar =atau bahkan adil 1=, tetapi hal-hal yang sangat aneh dapat terjadi jika Anda mengganti fdengan sesuatu yang bukan pernyataan Perl yang valid, tanpa efek samping. Anda telah diperingatkan.

Rincian lain yang menarik termasuk cara sumbu vertikal ditarik, yang mengeksploitasi fakta bahwa XOR bitwise dari karakter +dan |adalah W. Jelas, ini tidak akan bekerja pada sistem EBCDIC.

Output diterjemahkan menjadi hash array, bukan array array - ternyata dibutuhkan lebih sedikit karakter untuk secara eksplisit memotong kunci hash ke integer dan kemudian loop di atas potongan hash daripada yang diperlukan untuk memastikan bahwa array tidak diindeks dengan nilai negatif. Saya bisa mencukur dua karakter lagi jika bukan karena cara menjengkelkan Perl intmemotong nilai negatif ke nol, yang memaksa saya untuk menghitung baris output dari 2 hingga 22 bukannya 0 hingga 20 untuk menghindari pembulatan artefak di tepi atas dari area output.

Saya menggunakan konversi string-to-number liberal Perl di input parsing, di mana saya menggunakan seluruh string 1(x)=sebagai indeks array (itu akan dikonversi menjadi hanya 1).

Saya juga bisa menyimpan tiga karakter (dan membuat parsing sedikit lebih kuat) dengan mengganti s/\d.*=/;/;$f[$&]=$_dengan /\d.*=/;$f[$&]=$', tapi kemudian aku harus menghabiskan jumlah yang sama karakter ekstra untuk menulis $'sebagai $'\''di shell string tunggal dikutip. Saya kira secara teknis saya tidak perlu menghitungnya, tapi rasanya seperti curang.

Ilmari Karonen
sumber
6

Ruby, 200 karakter

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

Implementasi ruby ​​biasa menggunakan evaluator standar untuk ekspresi ( ^akan diganti sehingga contoh yang diberikan di atas berfungsi dengan baik). Itu tidak terlalu kuat dan mengasumsikan input persis seperti yang ditentukan dalam pertanyaan.

Howard
sumber
Pada baris kelima, bisa Anda mengubah y*0.5ke y/2dan menyingkirkan dua karakter? Saya tidak tahu Ruby, jadi saya mungkin tidak benar.
PhiNotPi
2
@PhiNotPi Sayangnya ini tidak akan berhasil. y/2melakukan pembagian integer.
Howard
Bisakah Anda menggunakan loop{}bukan ()while 1?
defhlt
Menemukan ini melalui tautan di bilah sisi ke sisi kanan. Ini cukup baik dilakukan. Saya bersenang-senang mencoba untuk mendapatkan yang lebih kecil ini, tetapi saya hanya menemukan 9 byte , satu byte mengandalkan literal rasional yang diperkenalkan pada ruby ​​2.1 (?).
blutorange
5

Python 2: 320 karakter

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)

Mungkin bisa dibuat lebih pendek, tapi saya sedikit pemula dalam hal ini :)

Membuat Nvariabel membuang 9 karakter tetapi saya lebih suka seperti itu.

NicolasP
sumber