2019-09-16 12:01:53 +03:00

178 lines
3.7 KiB
Crystal

require "./queue"
require "./map"
class Resources
def initialize
@wood = 0
end
def add_wood(x)
@wood += x
end
def wood
@wood
end
end
abstract class Command
abstract def start(world : World) : Int32
abstract def finish(world : World)
end
class BuildWoodMillCommand < Command
BASE_TIME = 30
def initialize(@point : Point)
end
def start(world : World) : Int32
printf " << start build mill at [%d:%d]\n", @point.x, @point.y
return BASE_TIME
end
def finish(world : World)
printf " << finish build mill at [%d,%d]\n", @point.x, @point.y
mill = WoodMillTile.new(@point)
world.map.set(mill)
world.push(GetWoodCommand.new(@point))
end
end
class GetWoodCommand < Command
BASE_TIME = 5
BASE_WOOD = 80
def initialize(@point : Point)
@wood = 0
end
def start(world : World) : Int32
wood_point = world.map.nearest_wood(@point)
if !wood_point.nil?
dist = @point.distance(wood_point)
tile = world.map.get(wood_point)
@wood = tile.withdraw(BASE_WOOD)
printf " << start cut down wood at [%d,%d] -> %d -> %d -> [%d,%d]\n",
@point.x, @point.y,
dist, @wood,
wood_point.x, wood_point.y
return BASE_TIME + 2 * dist
else
printf " << no wood tile\n"
@wood = 0
return BASE_TIME
end
end
def finish(world : World)
printf " << finish cut down wood at [%d,%d]\n", @point.x, @point.y
world.resources.add_wood(@wood)
world.push(GetWoodCommand.new(@point))
end
end
class BuildForesterHouseCommand < Command
BASE_TIME = 50
def initialize(@point : Point)
end
def start(world : World) : Int32
printf " >> start build forester house at [%d:%d]\n", @point.x, @point.y
return BASE_TIME
end
def finish(world : World)
printf " >> finish build forester house at [%d,%d]\n", @point.x, @point.y
tile = ForesterHouseTile.new(@point)
world.map.set(tile)
world.push(GrowWoodCommand.new(@point))
end
end
class GrowWoodCommand < Command
BASE_TIME = 15
BASE_WOOD = 30
@wood_point : Point | Nil
def initialize(@point : Point)
@wood_point = nil
end
def start(world : World) : Int32
wood_point = world.map.nearest_any_wood(@point)
if !wood_point.nil?
dist = @point.distance(wood_point)
@wood_point = wood_point
printf " >> start grow wood at [%d,%d] -> %d -> [%d,%d]\n",
@point.x, @point.y,
dist,
wood_point.x, wood_point.y
return BASE_TIME + 2 * dist
else
printf "no wood tile\n"
@wood = 0
return BASE_TIME
end
end
def finish(world : World)
printf " >> finish grow wood at [%d,%d]\n", @point.x, @point.y
if !@wood_point.nil?
tile = world.map.get(@wood_point.as(Point))
tile.charge(BASE_WOOD)
end
world.push(GrowWoodCommand.new(@point))
end
end
class World
def initialize
@ts = 0
@resources = Resources.new
@map = Map.new
@queue = App::CommandQueue.new
end
private def ts
@ts
end
def resources
@resources
end
def map
@map
end
def push(command : Command)
dur = command.start(self)
done_at = @ts + dur
printf "world : %d : plan `%s` at %d\n", @ts, typeof(command), done_at
@queue.push(done_at, command)
end
def run(ts : Int32)
loop do
item = @queue.pop(ts)
if item.nil?
break
end
cmd_ts, cmd = item[:ts], item[:cmd]
@ts = cmd_ts
printf "world : %d : finish `%s`\n", @ts, typeof(cmd)
cmd.finish(self)
end
end
end
w = World.new
w.map.print
w.push(BuildWoodMillCommand.new(Point.new(0, 0)))
w.push(BuildForesterHouseCommand.new(Point.new(0, 0)))
w.run(120)
printf "Wood: %d\n", w.resources.wood