# Custom die class to take into account
# Multiple dice, bonuses added to dice and dropped dice
class Die
# Standard initializer
def self.[] str
raise TypeError, "Argument must be a String" unless str.is_a? String
raise ArgumentError, "Error: Malformed Argument\
\nUsage:\
\n\t<Number>d<Die>\
\n\t<Number>d<Die><+ or -><Bonus>\
\n\t<Number>d<Die><+ or -><Bonus> drop <NumDropped>\
\nExamples:\
\n\tDMT::Die[\"3d6\"]\
\n\tDMT::Die[\"3d6+4\"], DMT::Die[\"3d6-2\"]\
\n\tDMT::Die[\"4d6 drop 1\"], DMT::Die[\"4d6-2 drop 1\"]\
\n" unless str.match /\A(\d+d\d+\ ?([\+\-]\ ?\d+)?(\ drop\ \d+)?)\z/
args = (str.split /\D/).reject{|s| s.empty?}.map{|i| i.to_i}
if str.include? "drop" then
if str.include? "-" then
new args[0], args[1], -args[2], args[3]
else
(args.size.eql? 3) ? (new args[0], args[1], 0, args[2]) : (new *args)
end
else
if str.include? "-" then
new args[0], args[1], -args[2]
else
new *args
end
end
end
# Die roller, produces a random number
def roll
damage = @bonus
dies = []
@number.times { dies.push (rand @value) + 1 }
(dies.sort.last dies.size - @drop).each { |d| damage += d }
damage
end
def inspect
"<Die: #{@number}d#{@value}" +
(@bonus.zero?? "" : @bonus < 0 ? @bonus.to_s : "+#{@bonus}") +
(@drop.zero?? "" : " Drop #{@drop}") + ">"
end
protected
def initialize num, val, bonus = 0, drop = 0
@number = num
@value = val
@bonus = bonus
@drop = drop
end
end
end
Name:
Anonymous2012-06-30 5:39
Side note: DMT is a larger module called "Dungeon Master Toolkit", this die is supposed to make things like generating characters a hell of a lot easier. Things like generating stats is as simple as:
self.[] formats the string and translates it to new. Just calling new looks like crap and may end up in having to throw in unused arguments.
Like for example, 4d6 drop 1 would be new 4, 6, 0, 1. It says nothing to the end user what each of the values are. There's a reason smalltalk and obj-c used named arguments like
dieWithNumnber: 4, value: 6, bonus: 0, drop: 1
Name:
Anonymous2012-06-30 7:34
>>7
You are confused. It is not simple. The language is complex. Ruby might be easy for novice programmers working on small programs, but that doesn't mean it is simple. As the size of your Ruby programs grow, the complexity will overwhelm you and will not be easy to continue growing it.
print(5 ? 4D6-2 DROP 1);
MODE DIE = STRUCT(INT count, sides, dropped, multiplier, additive);
PRIO D = 6, DROP = 6, KEEP = 6, ? = 5;
OP D = (INT count, sides)DIE: (count, sides, 0, 1, 0);
OP D = (INT sides)DIE: (1, sides, 0, 1, 0);
OP DROP = (DIE d, INT n)DIE: (count OF d, sides OF d, n, multiplier OF d, additive OF d);
OP KEEP = (DIE d, INT n)DIE: (count OF d, sides OF d, count OF d - n, multiplier OF d, additive OF d);
OP + = (DIE d, INT n)DIE: (count OF d, sides OF d, dropped OF d, multiplier OF d, additive OF d + n);
OP - = (DIE d, INT n)DIE: (count OF d, sides OF d, dropped OF d, multiplier OF d, additive OF d - n);
OP * = (DIE d, INT n)DIE: (count OF d, sides OF d, dropped OF d, multiplier OF d * n, additive OF d);
OP ? = (INT lim)INT: ENTIER(random * lim) + 1;
OP ? = (DIE d)INT: roll(d);
OP ? = (INT n, DIE d)[]INT: ([n]INT r; FOR i TO n DO r[i] := roll(d) OD; r);
PROC roll = (DIE d)INT:
IF count OF d <= 0 OR dropped OF d >= count OF d THEN
0
ELIF dropped OF d > 0 THEN
[sides OF d]INT r, INT min := 1, n := 0;
FOR i TO UPB r DO r[i] := 0 OD;
TO count OF d DO r[?sides OF d] +:= 1 OD;
TO dropped OF d DO
WHILE r[min] = 0 DO min +:= 1 OD;
r[min] -:= 1
OD;
FOR i TO UPB r DO n +:= i * r[i] OD;
n
ELSE
INT n := 0;
TO count OF d DO n +:= ?sides OF d OD;
n
FI * multiplier OF d + additive OF d;
~
That's nice, but there's a fucking reason I made my die a class and not a function. It's designed to be used multiple times as a value
Longsword = DMT::Weapon.new "Longsword", DMT::Die["1d8"] # Other arguments follow
Longsword.damage # Calls @wpower.roll every time
You can't pass a function with the arguments already defined, as an argument to a constructor. You can however, pass an object. The reasoning for self.[] is to make the arguments more readable. Passing the arguments as a string allows for use of the constructor without having to look back at the original source.
>>37
It's perfectly acceptable here. Think of it as a mini-DSL for dice rolls.
Name:
Anonymous2012-07-01 18:55
>>35 You can't pass a function with the arguments already defined, as an argument to a constructor
This seems like an odd thing to leave out of a language. Partial application of function arguments is not something one can live without in a reasonably high level language.
Hell, with a good CPU architecture, you might argue that ASM can support partially applied functions
Name:
Anonymous2012-07-01 20:14
>>35 You can't pass a function with the arguments already defined
Sure you can
data Die = Die { number :: Integer
, die :: Integer
, bonus :: Integer
, drop :: Integer
, rnd :: StdGen
}
instance Show Die where
show (Die n d b dr _) = show n ++ ('d':show d) ++
if b == 0 then "" else ('+':show b) ++
if dr == 0 then "" else (" drop " ++ show dr)
roll :: Die -> (Integer, Die)
roll (Die n d b dr g) = (b + sum (sort rnds), Die n d b dr ng)
where (rnds, ng) = rndlist g (n - dr)
rndlist g 0 = ([], g)
rndlist g i = (a:a', g'')
where (a, g') = randomR (1, d) g
(a', g'') = rndlist g' (i - 1)
rolls :: Die -> [Integer]
rolls d = n : rolls nd
where (n, nd) = roll d
Stop using your shitty unintelligible languages of yesterday.
PWOGWAMMIN MUVA FARGER N MARTIAL ARTZ R SAME COZ I LIKE BOTH OF DEM. PWOGWAMMIN MUVA FARGER.
Name:
Anonymous2012-07-03 4:29
Awesome code. Great size. Looks concise. Efficient. Elegant. Keep us all posted on your continued progress with any new code factoring or compiler optimization. Show us what you got man. Wanna see how freakin' expressive, efficient, concise and elegant you can get. Thanks for the motivation.
Name:
Anonymous2012-07-03 5:30
>>42
Did you miss that a much smaller list version was posted?
Why embarrass yourself like that? >>20