Skip to content

Instantly share code, notes, and snippets.

@CoderPuppy
Last active August 29, 2015 14:01
Show Gist options
  • Save CoderPuppy/fa4820c1915363d762d9 to your computer and use it in GitHub Desktop.
Save CoderPuppy/fa4820c1915363d762d9 to your computer and use it in GitHub Desktop.
Applied Energistics like system written in Fancy
class ItemSpec {
read_slots: ('name, 'dmg, 'data)
def initialize: @name with_dmg: @dmg with_data: @data
def initialize: @name with_dmg: @dmg
def initialize: @name with_data: @data {
@dmg = 0
}
def initialize: @name {
@dmg = 0
}
def key { (@name, @dmg, @data) inspect }
def of_qty: qty {
ItemStack new: self of_qty: qty
}
def inspect {
(@name to_s) + ":" + (@dmg to_s)
}
}
class ItemStack {
read_slot: 'spec
read_write_slot: 'qty
def initialize: @spec of_qty: @qty
def initialize: @spec {
@qty = 1
}
def dup {
ItemStack new: @spec of_qty: @qty
}
def key { @spec key }
def increase_qty: amt {
@qty = @qty + amt
self
}
def decrease_qty: amt {
@qty = @qty - amt
self
}
def with_qty: qty {
ItemStack new: @spec of_qty: qty
}
def inspect {
@spec inspect + " x #{@qty}"
}
}
class Inventory {
def initialize {
@items = Hash new
}
def get: spec {
@items fetch: (spec key) else_put: { spec of_qty: 0 }
}
def insert: stack {
existing_stack = get: $ stack spec
existing_stack . increase_qty: $ stack qty
Console println: $ "inserting #{stack inspect}, now: #{existing_stack inspect}"
self
}
def extract: spec {
if:(has?: spec) then: {
@items delete: $ spec key
}
}
def extract: qty of: spec {
if:(has: qty of?: spec) then: {
stack = @items at: $ spec key
if:(stack qty > qty) then: {
stack decrease_qty: qty
stack with_qty: qty
} else: {
@items delete: $ spec key
}
}
}
def has: amt of?: spec {
if:(has?: spec) then: {
(@items at: $ spec key) qty >= amt
} else: {
false
}
}
def has?: spec {
@items includes?: $ spec key
}
def inspect {
"#<Inventory [ " + (@items values map: |stack| { stack inspect } . join: ", ") + " ]>"
}
}
class Crafter {
read_slots: ('inv, 'recipes, 'operations)
def initialize: @inv {
@recipes = []
@operations = Set new
}
def add_recipe: recipe {
@recipes << recipe
}
def run {
@operations each: |operation| {
operation run
}
}
def craft: spec {
craft: 1 of: spec
}
def craft: qty of: spec without_using: blacklist (Set new) {
op = CraftingOperation new: self make: qty of: spec without_using: blacklist
@operations << op
op
}
def inspect {
"#<Crafter [ " + (@recipes map: |recipe| { recipe inspect } . join: ", ") + " ]>"
}
class CraftingOperation {
read_slots: ('crafter, 'spec, 'qty, 'result, 'recipe, 'blacklist)
def is_done? { @is_done }
def initialize: @crafter make: @qty of: @spec without_using: @blacklist {
@is_done = false
}
def complete: result {
@result = result
@is_done = true
@crafter operations remove: self
}
def find_potential_recipes {
@recipe = nil
@dependencies = nil
@potential_recipes = @crafter recipes select: |recipe| {
(@blacklist includes?: recipe) false? &&$ recipe ingredients none?: |ingredient| {
@blacklist includes?: $ ingredient spec
} &&$ recipe makes?: @spec
} . map: |recipe| { (recipe, recipe makes_how_much: @spec) } . sort: |a, b| {
if:(a[1] == (b[1]) ||$ a[1] > @qty &&$ b[1] > @qty) then: {
a_cost = a[0] ingredients map: @{qty} . reduce: |a, b| { a + b }
b_cost = b[0] ingredients map: @{qty} . reduce: |a, b| { a + b }
a_cost <=> b_cost
} else: {
if:(a[1] > @qty) then: {
-1
} else: {
if:(b[1] > @qty) then: {
1
} else: {
b[1] <=>$ a[1]
}
}
}
} . map: |recipe| { recipe[0] }
}
def find_recipe {
if:(@is_done false? &&$ @dependencies == nil &&$ @recipe == nil) then: {
@recipe = @potential_recipes find: @{is_possible?: $ @crafter inv}
if:(@recipe != nil) then: {
Console println: $ "trying to craft: " +$ @recipe inspect
@dependencies = @recipe ingredients map: |ingredient| {
@crafter craft: (ingredient qty) of: (ingredient spec) without_using: $ @blacklist +$ Set[[@spec, @recipe]]
}
}
}
}
def craft {
if:(@is_done false? &&$ @recipe != nil &&$ @dependencies != nil) then: {
if:(@dependencies all?: |dep| { dep.is_done? }) then: {
@recipe ingredients each: |ingredient| {
@crafter inv extract: (ingredient qty) of: (ingredient spec)
}
@recipe results each: |result| {
@crafter inv insert: result
Console println: $ "crafted: #{result inspect} from: [ " + (@recipe ingredients map: |ingredient| { ingredient inspect } . join: ", ") + " ]"
}
@recipe = nil
@dependencies = nil
}
}
}
def run {
if:(@is_done false? &&$ (@potential_recipes == nil ||$ @crafter recipes inspect != @old_recipes)) then: {
find_potential_recipes
@old_recipes = @crafter recipes inspect
}
find_recipe
craft
if:(@crafter inv has: @qty of?: @spec) then: {
complete: $ @crafter inv get: @spec
}
}
def inspect {
"#<CraftingOperation:#{object_id} @spec=#{@spec inspect} @qty=#{@qty} @is_done=#{@is_done inspect} @result=#{@result inspect} @recipe=#{@recipe inspect} @dependencies=#{@dependencies inspect}>"
}
}
}
class Recipe {
read_slots: ('ingredients, 'results)
def initialize: @ingredients makes: @results
def makes?: spec {
@results find: |stack| {
(stack spec key) == (spec key)
} != nil
}
def makes_how_much: spec {
stack = @results find: |stack| {
stack spec key ==$ spec key
}
if:(stack nil?) then: {
0
} else: {
stack qty
}
}
def is_possible?: inv {
@ingredients all?: |ingredient| {
inv has: (ingredient qty) of?: $ ingredient spec
}
}
def inspect {
(@ingredients inspect) + " => " + (@results inspect)
}
}
items = {
items = DynamicSlotObject new
items dirt: $ ItemSpec new: 'dirt
items diamond: $ ItemSpec new: 'diamond
items diamond_block: $ ItemSpec new: 'diamond_block
items object
} call
inv = Inventory new
crafter = Crafter new: inv
crafter add_recipe: $ Recipe new: [items dirt of_qty: 1] makes: [items diamond of_qty: 1]
crafter add_recipe: $ Recipe new: [items diamond_block of_qty: 1] makes: [items diamond of_qty: 9]
crafter add_recipe: $ Recipe new: [items diamond of_qty: 9] makes: [items diamond_block of_qty: 1]
# inv insert: $ items dirt of_qty: 64
# inv insert: $ items diamond_block of_qty: 64
Console println: $ inv inspect
op = crafter craft: 81 of: $ items diamond
Console println: $ op inspect
base_time = Time.now
done1 = false
done2 = false
while: { op is_done? false? } do: {
crafter run
sleep: 0.1
now = Time.now
if:(done1 false? &&$ now >=$ base_time + 10) then: {
inv insert: $ items diamond_block of_qty: 8
done1 = true
}
if:(done2 false? &&$ now >=$ base_time + 20) then: {
inv insert: $ items dirt of_qty: 10
done2 = true
}
}
Console println: $ inv inspect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment