8
\$\begingroup\$

Your task is to write a program that will take input like this:

a + b * c + a / 2

and will generate the source code for a program that takes user input and then evaluates the expression.

The expression can contain the operators +,-,*,/; single-letter lowercase variables; and integers between 0 and 32000. Standard arithmetic precedence must be correctly followed. The expression is limited to 26 unique variables a to z. However, a single variable can appear more than once.

You can assume that the input expression is valid (follows these rules).

The generated program must prompt for user input in this form, prompting only once for each variable:

a = 

User input from 0 to 32000 should be handled correctly. It will then print the expression and the correct result. You can use either integer or floating point arithmetic. The calculations should be performed with at least 32 bit precision. Beyond that, you don't have to worry about overflow or divide by zero.

Example of a non-golfed generated Perl program for the above expression:

print "a = ";
my $a = <>;
print "b = ";
my $b = <>;
print "c = ";
my $c = <>;
print "a + b * c + a / 2 = " . ($a + $b * $c + $a / 2); 

Example input and output of program generated for above expression:

a = 1
b = 2
c = 3
a + b * c + a / 2 = 7.5

The score is calculated as length of the program + length of the generated program for this expression:

1 + a * 4 * b + 2 / d * e - a - 3 + g / h * 32000

Lowest score wins.

Update: Just to highlight a couple of requirements of the problem, as stated above:

  • The output of the program must be source code for another program that evaluates the expression.
  • The program must print the original expression. Perhaps there is some ambiguity in this (one could argue that a+b is the same expression as a + b), but for clarity let's say that it must be the original expression with white space intact. All valid answers so far have done it that way.
\$\endgroup\$
1
\$\begingroup\$

Perl, 80 + 110 = 190

Directly inspired by another (now deleted) answer in Ruby. Requires Perl ≥ v5.14.

Following the usual rule I've seen of command-line switches counting as one character.

#!/usr/bin/perl -n
chomp;print'print $_="',$_,'"," = ",eval(s#\pL#${$&}//=do{print"$& = ";<>}#ger)'

Perl, 80 + 231 = 311

Because eval'ing in the output feels cheap.

#!/usr/bin/perl -p
chomp;print"print '$_ = ',";s/\pL/$s{$&}++?"\$$&":"do{print'$& = ';\$$&=<>}"/ge

Seems like the output could be shortened by moving the prompting into a sub, but I've run out of enthusiasm.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ This is code golf. Eval'ing the output isn't cheap! \$\endgroup\$ – user7486 Apr 16 '13 at 5:08
  • \$\begingroup\$ A few suggestions: \pL can replace [a-z]. No need for do block. Can just write: ${$&}//=print"$& = "and<> \$\endgroup\$ – user7486 Apr 16 '13 at 7:23
  • \$\begingroup\$ @dan1111 Thanks for the \pL, done. Can't use and in either program, because the precedence is too low; and is lower precedence than //=. \$\endgroup\$ – Kevin Reid Apr 18 '13 at 3:15
1
\$\begingroup\$

Lua, 202 + 166 = 368

File "generate_code.lua"

F=...
C='function G(v)io.write(v.." = ")_G[v]=io.read"*n"end 'V={}for v in F:gmatch'%l'do V[v]=0 end
for v in pairs(V)do C=C..'G"'..v..'"'end
print(C..'F="'..F..'"print(F.." = "..load("return "..F)())')

Usage:

$ lua generate_code.lua "1 + a * 4 * b + 2 / d * e - a - 3 + g / h * 32000"

Code generated (order of variables is not specified):

function G(v)io.write(v.." = ")_G[v]=io.read"*n"end G"g"G"e"G"d"G"b"G"a"G"h"F="1 + a * 4 * b + 2 / d * e - a - 3 + g / h * 32000"print(F.." = "..load("return "..F)())

Generated code in action:

g = 4
e = 3
d = 2
b = 1
a = 6.5
h = 4.3
1 + a * 4 * b + 2 / d * e - a - 3 + g / h * 32000 = 29787.941860465
|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

Tcl 198 + 155 = 352

gets stdin i;puts [string map [list @ [lsort -u [regexp -all -inline {[a-z]} $i]] & [regsub -all {[a-z]} [join $i {}] {$\0}] | $i] {foreach va {@} {puts "$va =";gets stdin $va};puts "| = [expr &]"}]

generates

foreach va {a b d e g h} {puts "$va =";gets stdin $va};puts "1 + a * 4 * b + 2 / d * e - a - 3 + g / h * 32000 = [expr 1+$a*4*$b+2/$d*$e-$a-3+$g/$h*32000]"
|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ foreach => lmap ; va => v \$\endgroup\$ – sergiol Jun 9 '18 at 23:28
0
\$\begingroup\$

Python 125 + 151 = 276

>>> t=raw_input();z=sorted(set(filter(str.isalpha,t)));print','.join(z)+'=[input(x+" = ")for x in%r];print"%s =",%s'%(z,t,t[::2])
1 + a * 4 * b + 2 / d * e - a - 3 + g / h * 32000
a,b,d,e,g,h=[input(x+" = ")for x in['a', 'b', 'd', 'e', 'g', 'h']];print"1 + a * 4 * b + 2 / d * e - a - 3 + g / h * 32000 =",1+a*4*b+2/d*e-a-3+g/h*300

Now executing it:

>>> exec"""a,b,d,e,g,h=[input(x+" = ")for x in['a', 'b', 'd', 'e', 'g', 'h']];print"1 + a * 4 * b + 2 / d * e - a - 3 + g / h * 32000 =",1+a*4*b+2/d*e-a-3+g/h*300"""
a = 1
b = 2
d = 3
e = 4
g = 5
h = 6
1 + a * 4 * b + 2 / d * e - a - 3 + g / h * 32000 = 5
|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ I don't think there's any requirement to sort the variables and I think it turns out to be better to use a string literal instead of a list. That is, replace z=sorted(set(filter(str,isalpha,t))) with z=''.join(set(filter(str.isalpha,t))). \$\endgroup\$ – Geoff Reedy Apr 17 '13 at 3:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy