Add restore command

This commit is contained in:
Anton Vakhrushev 2019-10-13 16:54:33 +03:00
parent 6cf4759e5e
commit 45d0042a29
7 changed files with 163 additions and 29 deletions

View File

@ -18,13 +18,26 @@ module Game::TestCommand
)
map.set DepositTile.new(
Point.new(1, 1),
Deposit.new(Resource::Type::Crystals, 100)
Deposit.new(Resource::Type::Crystals, 1000, 500)
)
map.set DepositTile.new(
Point.new(1, 0),
Deposit.new(Resource::Type::Crystals, 1000, 0)
)
map.set BuildingTile.new(
Point.new(0, 1),
Building.new(
Building::Type::CrystalMiner,
mining: Mining.new(20, Resource.new(Resource::Type::Crystals, 40))
mining: Mining.new(
ts: 20,
resource: Resource.new(Resource::Type::Crystals, 40),
input: ResourceBag.new
),
restoration: Mining.new(
ts: 20,
resource: Resource.new(Resource::Type::Crystals, 40),
input: ResourceBag.new({Resource::Type::Crystals => 5})
)
)
)
map
@ -65,10 +78,27 @@ module Game::TestCommand
it "should complete mining command" do
world = World.new create_map_with_resource
command = MineCommand.new Point.new(0, 1)
command = MineCommand.new Point.new(0, 1), once: true
world.push command
world.run 20
# Check world resources
world.resources[Resource::Type::Crystals].should eq 40
# Check tile deposit
tile = world.map.get(1, 1).as(DepositTile)
tile.dep.cur.should eq 460
end
it "should complete restore command" do
world = World.new create_map_with_resource
world.resources.inc(Resource::Type::Crystals, 20)
command = RestoreCommand.new Point.new(0, 1), once: true
world.push command
world.run 20
# Check world resources
world.resources[Resource::Type::Crystals].should eq 15
# Check tile deposit
tile = world.map.get(1, 0).as(DepositTile)
tile.dep.cur.should eq 40
end
end
end

View File

@ -25,5 +25,29 @@ module Game::TestResourceBag
res = Res.new
res.has({ResType::Crystals => 50}).should be_false
end
it "should inc single value" do
res = Res.new ({ResType::Crystals => 10})
res.inc ResType::Crystals, 5
res[ResType::Crystals].should eq 15
end
it "should inc resource" do
res = Res.new ({ResType::Crystals => 10})
res.inc Resource.new(ResType::Crystals, 5)
res[ResType::Crystals].should eq 15
end
it "should inc hash" do
res = Res.new ({ResType::Crystals => 10})
res.inc ({ResType::Crystals => 5})
res[ResType::Crystals].should eq 15
end
it "should inc other bag" do
res = Res.new ({ResType::Crystals => 10})
res.inc Res.new({ResType::Crystals => 5})
res[ResType::Crystals].should eq 15
end
end
end

View File

@ -9,11 +9,12 @@ module Game
end
class Mining
def initialize(@ts : TimeSpan, @resource : Resource)
def initialize(@ts : TimeSpan, @resource : Resource, @input : ResourceBag)
end
getter ts
getter resource
getter input
end
class Construction

View File

@ -11,7 +11,8 @@ module Game
Building.new Building::Type::CrystalMiner, **{
mining: Mining.new(
ts: 20,
resource: Resource.new(Resource::Type::Crystals, 40)
resource: Resource.new(Resource::Type::Crystals, 40),
input: ResourceBag.new
),
}
)
@ -27,7 +28,8 @@ module Game
),
restoration: Mining.new(
ts: 30,
resource: Resource.new(Resource::Type::Crystals, 20)
resource: Resource.new(Resource::Type::Crystals, 20),
input: ResourceBag.new
),
}
)

View File

@ -36,7 +36,7 @@ module Game
class MineCommand < Command
@holded : Resource? = nil
def initialize(@point : Point)
def initialize(@point : Point, *, @once = false)
end
def desc : String
@ -63,8 +63,10 @@ module Game
holded = @holded.as(Resource)
world.resources.inc(holded)
end
if !@once
world.push(MineCommand.new(@point))
end
end
private def nearest_deposit(world : World, res_type : Resource::Type) : DepositTile?
tile = world.map.nearest_tile @point do |tile|
@ -74,6 +76,53 @@ module Game
end
end
class RestoreCommand < Command
@holded : Resource? = nil
@deposit_tile : DepositTile? = nil
def initialize(@point : Point, *, @once = false)
end
def desc : String
if @holded
sprintf "Restore %s from %d,%d", @holded.type, @point.x, @point.y
else
sprintf "Wait for resources at %d,%d", @point.x, @point.y
end
end
def start(world : World) : TimeSpan
tile = world.map.get(@point).as(BuildingTile)
building = tile.building
restoration = building.restoration.as(Mining)
if !world.resources.has(restoration.input)
return restoration.ts
end
@deposit_tile = nearest_deposit(world, restoration.resource.type)
if @deposit_tile
world.resources.dec restoration.input
@holded = restoration.resource
end
restoration.ts
end
def finish(world : World)
if @deposit_tile && @holded
@deposit_tile.as(DepositTile).dep.inc(@holded.as(Resource))
end
if !@once
world.push(RestoreCommand.new(@point))
end
end
private def nearest_deposit(world : World, res_type : Resource::Type) : DepositTile?
tile = world.map.nearest_tile @point do |tile|
tile.is_a?(DepositTile) && tile.dep.type == res_type && tile.dep.cur == 0
end
tile.as?(DepositTile)
end
end
# class BuildCrystalHarvesterCommand < Command
# BUILD_TIME = 30

View File

@ -1,4 +1,5 @@
class Game::Deposit
@cap : Capacity = 0
@cur : Capacity = 0
def initialize(@type : Resource::Type, @cap : Capacity)

View File

@ -26,15 +26,12 @@ class Game::ResourceBag
@values = ResourceHash.new
Resource::Type.each { |t, v| @values[t] = 0 }
if vals.is_a?(ResourceHash)
vals.each do |i|
t, v = i
@values[t] = v
end
add_amounts vals
end
end
def [](res_type : Resource::Type)
@values.fetch(res_type, 0)
@values[res_type]
end
def has(res_type : Resource::Type, value : Capacity) : Bool
@ -42,38 +39,68 @@ class Game::ResourceBag
end
def has(res : Resource) : Bool
has(res.type, res.amount)
has res.type, res.amount
end
def has(vs : ResourceHash) : Bool
vs.reduce true do |acc, entry|
t = entry[0]
v = entry[1]
acc && @values[t] >= v
end
has_amounts vs
end
def has(vs : self) : Bool
has vs.to_hash
has_amounts vs.@values
end
def inc(res_type : Resource::Type, value : Capacity)
new_value = @values[res_type] + value
if new_value < 0
raise NotEnoughtResources.new
end
@values[res_type] = new_value
validate_add_amounts ({res_type => value})
@values[res_type] += value
end
def inc(res : Resource)
inc(res.type, res.amount)
inc res.type, res.amount
end
def inc(vs : ResourceHash)
validate_add_amounts vs
add_amounts vs
end
def inc(other : self)
inc other.@values
end
def dec(res_type : Resource::Type, value : Capacity)
inc(res_type, -value)
inc res_type, -value
end
def to_hash : ResourceHash
@values.clone
def dec(other : self)
inverted = other.@values.transform_values { |v| -v }
inc inverted
end
private def can_add_amounts(vs : ResourceHash)
vs.reduce true do |acc, entry|
res_type, amount = entry
acc && @values[res_type] + amount >= 0
end
end
private def validate_add_amounts(vs : ResourceHash)
if !can_add_amounts(vs)
raise NotEnoughtResources.new
end
end
private def add_amounts(vs : ResourceHash)
vs.each do |entry|
res_type, amount = entry
@values[res_type] += amount
end
end
private def has_amounts(vs : ResourceHash)
vs.reduce true do |acc, entry|
res_type, amount = entry
acc && @values[res_type] >= amount
end
end
end