-
-
Save amirrajan/5934a3fa15d9d1e752f34d7e37a5d530 to your computer and use it in GitHub Desktop.
Enemy encounter definition with loot drop probabilities: Python vs JS vs Lua vs Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Python version | |
class SnarlingBeastEvent(EncounterEvent): | |
title = "a snarling beast" | |
text = "a snarling beast leaps out of the underbrush." | |
enemy = 'snarling_beast' | |
damage = 1 | |
health = 5 | |
attack_delay = 1 | |
hit = 0.8 | |
# making this a def that returns a literal is an odd choice; | |
# here's something more typed | |
loot = MultiLoot( | |
Loot(Fur, min=1, max=3, chance=1), | |
Loot(Meat, min=1, max=3, chance=1), | |
Loot(Teeth, min=1, max=3, chance=0.8), | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Lua doesn't have built-in classes, just a toolbox of bits you can use to make them, so this will vary | |
local SnarlingBeastEvent = EncounterEvent:extend{ | |
title = "a snarling beast", | |
text = "a snarling beast leaps out of the underbrush.", | |
enemy = 'snarling_beast', | |
damage = 1, | |
health = 5, | |
attack_delay = 1, | |
hit = 0.8, | |
loot = MultiLoot( | |
Loot{item=Fur, min=1, max=3, chance=1}, | |
Loot{item=Meat, min=1, max=3, chance=1}, | |
Loot{item=Teeth, min=1, max=3, chance=0.8}), | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ES6 classes don't support class attributes (STILL, ugh), but you can cheat a bit | |
function make_encounter(data) { | |
let encounter_type = Object.create(EncounterEvent.prototype); | |
for (let [k, v] of Object.entries(data)) { | |
encounter_type.prototype[k] = v; | |
} | |
return encounter_type; | |
} | |
local SnarlingBeastEvent = make_encounter({ | |
title: "a snarling beast", | |
text: "a snarling beast leaps out of the underbrush.", | |
enemy: 'snarling_beast', | |
damage: 1, | |
health: 5, | |
attack_delay: 1, | |
hit: 0.8, | |
// ok js syntax kinda sucks here | |
loot: new MultiLoot( | |
new Loot(Fur, 1, 3, 1.0), | |
new Loot(Meat, 1, 3, 1.0), | |
new Loot(Teeth, 1, 3, 0.8), | |
), | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Ruby version (ideal/cleanest version) | |
class SnarlingBeastEvent < EncounterEvent | |
title "a snarling beast" | |
text "a snarling beast leaps out of the underbrush." | |
enemy :snarling_beast | |
damage 1 | |
health 5 | |
attack_delay 1 | |
hit 0.8 | |
loot Fur, min: 1, max: 3, chance: 1 | |
loot Meat, min: 1, max: 3, chance: 1 | |
loot Teeth, min: 1, max: 3, chance: 0.8 | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Evolution of the ideal Ruby version | |
# Completely vanilla syntax | |
class SnarlingBeastEvent < EncounterEvent | |
def initialize | |
@title = "a snarling beast" | |
@text = "a snarling beast leaps out of the underbrush." | |
@enemy = :snarling_beast | |
@damage = 1 | |
@health = 5 | |
@attack_delay = 1 | |
@hit = 0.8 | |
# taking your lead on the typed definition | |
@loot = MultiLoot.new Loot.new(Fur, min: 1, max: 3, chance: 1), | |
Loot.new(Meat, min: 1, max: 3, chance: 1), | |
Loot.new(Teeth, min: 1, max: 3, chance: 1) | |
end | |
end | |
# The Python version is syntactically cleaner in every way. | |
# But the version above really is meh. I don't want to create 50 encounters like that... | |
# You can make the initalization a little cleaner by using a constructor | |
# with named parameters and pushing the MultiLoot, Loot repetion into | |
# the base class. | |
# Still no meta programming involved. | |
# Any named parameters not provided can be defaulted (or can raise an exception). | |
# This version is alright I guess. | |
class SnarlingBeastEvent < EncounterEvent | |
def initialize | |
super title: "a snarling beast", | |
text: "a snarling beast leaps out of the underbrush.", | |
enemy: :snarling_beast, | |
damage: 1, | |
health: 5, | |
attack_delay: 1, | |
hit: 0.8, | |
# PS: Notice that multi_loot (and by extension its default value) are array types. | |
# Ref types as default values in Python are a special type of wtf. | |
multi_loot: [ | |
{ loot: Fur, min: 1, max: 3, chance: 1 }, | |
{ loot: Meat, min: 1, max: 3, chance: 1 }, | |
{ loot: Teeth, min: 1, max: 3, chance: 0.8 } | |
] | |
end | |
end | |
# I wanted to still make it cleaner. This is what I essentially have in ADR source | |
# (still using your typed loot construct). | |
# Both this version and the version above do not use the `=` | |
# assignment. Which gives me the ability to # expand past just the assignment of attributes. | |
# This is the first solution that uses meta programming. | |
class SnarlingBeastEvent < EncounterEvent | |
title "a snarling beast" | |
text "a snarling beast leaps out of the underbrush." | |
enemy :snarling_beast | |
damage 1 | |
health 5 | |
attack_delay 1 | |
hit 0.8 | |
loot Fur, min: 1, max: 3, chance: 1 | |
loot Meat, min: 1, max: 3, chance: 1 | |
loot Teeth, min: 1, max: 3, chance: 0.8 | |
end | |
# Here is an example of how title is meta programmed. | |
# I can understand how this can be perceived as clever/"too extra", | |
# but this extra-ness cleans up all of the encounter events significantly... which I have a lot of. | |
class EncounterEvent | |
def self.title value | |
define_method :title do | |
instance_variable_set :@title, value | |
end | |
end | |
end | |
# I liked your JS/Lua version too (and really do enjoy working with it's prototypical nature... | |
# just don't do any important math in js). | |
# This is how I'd do something comprable in Ruby. | |
# It uses significantly less meta programming that the version above, but isn't as clean as the version above. | |
EncounterEvent.create :SnarlingBeastEvent, | |
title: "a snarling beast", | |
text: "a snarling beast leaps out of the underbrush.", | |
enemy: :snarling_beast, | |
damage: 1, | |
health: 5, | |
attack_delay: 1, | |
hit: 0.8, | |
multi_loot: [ | |
{ loot: Fur, min: 1, max: 3, chance: 1 }, | |
{ loot: Meat, min: 1, max: 3, chance: 1 }, | |
{ loot: Teeth, min: 1, max: 3, chance: 0.8 } | |
] | |
# Supporting meta programming for the api above to work | |
class EncounterEvent | |
def self.create encounter_name, opts | |
Object.const_set encounter_name, Class.new(EncounterEvent) do | |
def initialize | |
super opts | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# readability of Ruby | |
puts "All unique Pythagorean Triples between 1 and 100 sorted by area of the triangle." | |
side_lengths = (1..100).to_a | |
triples = | |
side_lengths.product(side_lengths) | |
.map do |width, height| | |
[width, | |
height, | |
Math.sqrt(width ** 2 + height ** 2)] | |
end.find_all do |_, _, hypotenuse| | |
hypotenuse.to_i == hypotenuse | |
end.uniq do |triangle| | |
triangle.sort | |
end.map do |width, height, hypotenuse| | |
{ width: width, | |
height: height, | |
hypotenuse: hypotenuse, | |
area: (width * height) / 2 } | |
end.sort_by do |triangle| | |
triangle[:area] | |
end | |
triples.each do |triple| | |
puts "* Triple with area: #{triple[:area]}" | |
puts "** a: #{triple[:width]}" | |
puts "** b: #{triple[:height]}" | |
puts "** c: #{triple[:hypotenuse]}" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Context:
Part 1: https://twitter.com/amirrajan/status/1111697856912637954
Part 2: https://twitter.com/amirrajan/status/1111804996079833088
Part 3: https://twitter.com/amirrajan/status/1111805358824177664
Part 4: https://twitter.com/eevee/status/1111807140656631808
Part 5: https://twitter.com/amirrajan/status/1111855427657101312