This is an RPN calculator. Implemented in 138 characters of Ruby.
Run it like such:
ruby calc.rb
And input your calculation, like:
1 3 +
And it will return:
4.0
Have fun!
p((_=[gets.split,[],"+-**/"])[0].map{|__|__=~/[0-9\.]+/?_[1]<<__.to_f : _[2][__]?_[1]<<_[1].pop.send(__,_[1].pop):0}[0][0]) |
Here's a freaking long explanation of how this code works. If you don't need to know, or just don't want to read this, you don't have to!
First off, here's the code split up a little with some whitespace:
p(
(_=[gets.split,
[],
"+-**/"]
)[0].map{|s|
s = ~/[0-9\.]+/ ?
_[1] << s.to_f :
_[2][s] ?
_[1] << _[1].pop.send(s.to_sym, _[1].pop) :
0
}[0][0])
It's still really cryptic. Maybe even more so. I'll go through it line, by line.
p(
The very first thing prints the result, once we get it.
(_=[gets.split,
[],
"+-**/"]
Next we want to initialize some variables. But separate variable names take up a lot of text. So instead we have a single variable: _
, that is an array. The first element is our input (split by whitespace into an array), the second is an empty stack, the third is a string list of operators. Normally you'd think a list of operators would be an array, not a string, but we've got some fancy stuff going on here!
)[0].map{|s|
Next we take the first element of our fancy array (the input array) and go through each element, with s
representing the current element. We don't do something like );_[0].map
because when assigning to a variable, the value is returned when the variable is assigned. Allowing us to chain methods like this.
s = ~/[0-9\.]+/ ?
Next we test if the current input token is a number (actually a float, since it can contain a decimal point). And we use the fun unary operator that works like: condition ? do_if_true : do_if_false
.
_[1] << s.to_f :
If it is a number, we push the string to the stack, after converting it to a float.
_[2][s] ?
And now we get some fun fancy stuff with that operator string. Here we're testing to see if the current operator token is a substring of our operator string. If it is, our current token is an operator. Otherwise it's not.
_[1] << _[1].pop.send(s.to_sym, _[1].pop) :
This is probably the craziest part of the code. In Ruby, you can dynamically call methods of course. And the standard infix methods (like 1 + 3
) can be represented like any other method, that is 1.+(3)
. Here's a run down of the program so far with the input of:
1 3 +
The 1
was pushed to the stack as a float: 1.0
.
The 3
was pushed to the stack as a float: 3.0
.
The +
operator is reached, and so:
+
) is converted to a symbol so we can call it (all methods in ruby also have a symbol equivalent).(3.0).+(1.0)
So we call this, and then push the result to the stack, so our stack now only has a single value in it: 4.0
.
0
If nothing else works (that is, if our input isn't a number or an operator). Just return zero, do nothing. Basically the shortest code I could come up with for this, because with unary conditionals you can't have an empty else
part of it.
}[0][0])
Then we get the first element of a crazy doubly-nested array we finally get so we just print out the final value.