Move core logic files to game
This commit is contained in:
149
src/game/command.cr
Normal file
149
src/game/command.cr
Normal file
@@ -0,0 +1,149 @@
|
||||
require "./tile"
|
||||
|
||||
abstract class Command
|
||||
abstract def start(world : World) : Int32
|
||||
abstract def finish(world : World)
|
||||
end
|
||||
|
||||
class BuildCrystalHarvesterCommand < Command
|
||||
BUILD_TIME = 30
|
||||
|
||||
def initialize(@point : Point)
|
||||
end
|
||||
|
||||
def start(world : World) : Int32
|
||||
BUILD_TIME
|
||||
end
|
||||
|
||||
def finish(world : World)
|
||||
world.map.set(CrystalHarvesterTile.new(@point))
|
||||
world.push(HarvestCrystalCommand.new(@point))
|
||||
end
|
||||
end
|
||||
|
||||
class HarvestCrystalCommand < Command
|
||||
HARVEST_VALUE = 80
|
||||
HARVEST_TIME = 10
|
||||
REST_TIME = 5
|
||||
|
||||
def initialize(@point : Point)
|
||||
@value = 0
|
||||
end
|
||||
|
||||
def start(world : World) : Int32
|
||||
deposit_tile = nearest_deposit(world)
|
||||
stock_tile = nearest_stock(world)
|
||||
if deposit_tile && stock_tile
|
||||
wood_dist = @point.distance(deposit_tile.point)
|
||||
stock_dist = @point.distance(stock_tile.point)
|
||||
@value = deposit_tile.withdraw(HARVEST_VALUE)
|
||||
HARVEST_TIME + 2 * wood_dist + 2 * stock_dist
|
||||
else
|
||||
REST_TIME
|
||||
end
|
||||
end
|
||||
|
||||
def finish(world : World)
|
||||
world.resources.inc(ResourceType::Crystal, @value)
|
||||
world.push(HarvestCrystalCommand.new(@point))
|
||||
end
|
||||
|
||||
private def nearest_deposit(world : World)
|
||||
world.map.nearest_tile @point do |tile|
|
||||
tile.has_role(TileRole::CrystalDeposits) && tile.cur > 0
|
||||
end
|
||||
end
|
||||
|
||||
private def nearest_stock(world : World)
|
||||
world.map.nearest_tile @point do |tile|
|
||||
tile.has_role(TileRole::Warehouse)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class BuildCrystalRestorerCommand < Command
|
||||
CRYSTALS_COST = 100
|
||||
BUILD_TIME = 50
|
||||
|
||||
def initialize(@point : Point)
|
||||
end
|
||||
|
||||
def start(world : World) : Int32
|
||||
world.resources.dec(ResourceType::Crystal, CRYSTALS_COST)
|
||||
BUILD_TIME
|
||||
end
|
||||
|
||||
def finish(world : World)
|
||||
world.map.set(CrystalRestorerTile.new(@point))
|
||||
world.push(RestoreCrystalCommand.new(@point))
|
||||
end
|
||||
end
|
||||
|
||||
class RestoreCrystalCommand < Command
|
||||
RESTORE_TIME = 15
|
||||
RESTORE_VALUE = 30
|
||||
REST_TIME = 5
|
||||
|
||||
@target_tile : Tile | Nil = nil
|
||||
|
||||
def initialize(@point : Point)
|
||||
end
|
||||
|
||||
def start(world : World) : Int32
|
||||
@target_tile = nearest_deposit(world)
|
||||
if @target_tile
|
||||
dist = @point.distance(@target_tile.as(Tile).point)
|
||||
RESTORE_TIME + 2 * dist
|
||||
else
|
||||
REST_TIME
|
||||
end
|
||||
end
|
||||
|
||||
def finish(world : World)
|
||||
if @target_tile
|
||||
@target_tile.as(Tile).charge(RESTORE_VALUE)
|
||||
end
|
||||
world.push(RestoreCrystalCommand.new(@point))
|
||||
end
|
||||
|
||||
private def nearest_deposit(world : World)
|
||||
world.map.nearest_tile @point do |tile|
|
||||
tile.has_role(TileRole::CrystalDeposits) && tile.cur < tile.cap
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class BuildTerraformerCommand < Command
|
||||
CRYSTALS_COST = 100
|
||||
BUILD_TIME = 120
|
||||
|
||||
def initialize(@point : Point)
|
||||
end
|
||||
|
||||
def start(world : World) : Int32
|
||||
world.resources.dec(ResourceType::Crystal, CRYSTALS_COST)
|
||||
BUILD_TIME
|
||||
end
|
||||
|
||||
def finish(world : World)
|
||||
world.map.set(TerraformerTile.new(@point))
|
||||
world.push(TerraformCommand.new(@point))
|
||||
end
|
||||
end
|
||||
|
||||
class TerraformCommand < Command
|
||||
PRODUCTION_TIME = 60
|
||||
PRODUCTION_VALUE = 5
|
||||
|
||||
def initialize(@point : Point)
|
||||
end
|
||||
|
||||
def start(world : World) : Int32
|
||||
PRODUCTION_TIME
|
||||
end
|
||||
|
||||
def finish(world : World)
|
||||
world.resources.inc(ResourceType::Terraformation, PRODUCTION_VALUE)
|
||||
world.push(TerraformCommand.new(@point))
|
||||
end
|
||||
end
|
2
src/game/exception.cr
Normal file
2
src/game/exception.cr
Normal file
@@ -0,0 +1,2 @@
|
||||
class NotEnoughtResources < Exception
|
||||
end
|
81
src/game/map.cr
Normal file
81
src/game/map.cr
Normal file
@@ -0,0 +1,81 @@
|
||||
struct Point
|
||||
property x : Int32
|
||||
property y : Int32
|
||||
|
||||
def initialize(@x : Int32, @y : Int32)
|
||||
end
|
||||
|
||||
getter x
|
||||
getter y
|
||||
|
||||
def distance(other) : Int32
|
||||
return (other.x - @x).abs + (other.y - @y).abs
|
||||
end
|
||||
end
|
||||
|
||||
class Map
|
||||
SIZE = 4
|
||||
|
||||
def initialize
|
||||
@data = {} of String => Tile
|
||||
(0...SIZE).each do |x|
|
||||
(0...SIZE).each do |y|
|
||||
self.set(PlateauTile.new(Point.new(x, y)))
|
||||
end
|
||||
end
|
||||
self.set(MainBaseTile.new(Point.new(0, 0)))
|
||||
self.set(CrystalTile.new(Point.new(1, 1), 100))
|
||||
self.set(CrystalTile.new(Point.new(3, 1), 200))
|
||||
self.set(CrystalTile.new(Point.new(2, 2), 100))
|
||||
end
|
||||
|
||||
def get(point : Point) : Tile
|
||||
@data[key(point)]
|
||||
end
|
||||
|
||||
def set(tile : Tile)
|
||||
@data[key(tile.point)] = tile
|
||||
end
|
||||
|
||||
def set(point : Point, tile : Tile)
|
||||
@data[key(point)] = tile
|
||||
end
|
||||
|
||||
def tiles
|
||||
(0...SIZE).each do |x|
|
||||
(0...SIZE).each do |y|
|
||||
point = Point.new(x, y)
|
||||
tile = self.get(point)
|
||||
yield point, tile
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def nearest_tile(point : Point, &block) : Tile | Nil
|
||||
seek_tile = nil
|
||||
min_dist = Int32::MAX
|
||||
tiles do |tile_point, tile|
|
||||
if (yield tile)
|
||||
tile_dist = tile_point.distance(point)
|
||||
if tile_dist < min_dist
|
||||
min_dist = tile_dist
|
||||
seek_tile = tile
|
||||
end
|
||||
end
|
||||
end
|
||||
seek_tile
|
||||
end
|
||||
|
||||
def print
|
||||
(0...SIZE).each do |x|
|
||||
(0...SIZE).each do |y|
|
||||
printf "%c", @data[key(Point.new(x, y))].letter
|
||||
end
|
||||
printf "\n"
|
||||
end
|
||||
end
|
||||
|
||||
private def key(p : Point) : String
|
||||
return sprintf "%d:%d", p.x, p.y
|
||||
end
|
||||
end
|
28
src/game/queue.cr
Normal file
28
src/game/queue.cr
Normal file
@@ -0,0 +1,28 @@
|
||||
class App::Queue
|
||||
struct Item
|
||||
def initialize(@ts : Int32, @command : Command)
|
||||
end
|
||||
|
||||
getter ts
|
||||
getter command
|
||||
end
|
||||
|
||||
def initialize
|
||||
@data = [] of Item
|
||||
end
|
||||
|
||||
def push(ts : Int32, value : Command)
|
||||
# very unoptimal algo
|
||||
@data.push(Item.new(ts, value))
|
||||
@data.sort! do |a, b|
|
||||
b.ts <=> a.ts
|
||||
end
|
||||
end
|
||||
|
||||
def pop(ts : Int32) : Item | Nil
|
||||
if @data.size == 0
|
||||
return nil
|
||||
end
|
||||
@data[-1].ts <= ts ? @data.pop : nil
|
||||
end
|
||||
end
|
31
src/game/resources.cr
Normal file
31
src/game/resources.cr
Normal file
@@ -0,0 +1,31 @@
|
||||
require "./exception"
|
||||
|
||||
enum ResourceType
|
||||
Crystal
|
||||
Terraformation
|
||||
end
|
||||
|
||||
class Resources
|
||||
def initialize
|
||||
@values = {} of ResourceType => Int32
|
||||
ResourceType.each do |t|
|
||||
@values[t] = 0
|
||||
end
|
||||
end
|
||||
|
||||
def [](t : ResourceType)
|
||||
@values[t]
|
||||
end
|
||||
|
||||
def inc(t : ResourceType, value : Int32)
|
||||
new_value = @values[t] + value
|
||||
if new_value < 0
|
||||
raise NotEnoughtResources.new
|
||||
end
|
||||
@values[t] = new_value
|
||||
end
|
||||
|
||||
def dec(t : ResourceType, value : Int32)
|
||||
inc(t, -value)
|
||||
end
|
||||
end
|
104
src/game/tile.cr
Normal file
104
src/game/tile.cr
Normal file
@@ -0,0 +1,104 @@
|
||||
enum TileRole
|
||||
CrystalDeposits
|
||||
CrystalHarvester
|
||||
CrystalRestorer
|
||||
Plateau
|
||||
Terraformer
|
||||
Warehouse
|
||||
end
|
||||
|
||||
abstract class Tile
|
||||
property cap : Int32 = 0
|
||||
property cur : Int32 = 0
|
||||
|
||||
def initialize(@point : Point)
|
||||
end
|
||||
|
||||
getter point
|
||||
getter cap
|
||||
getter cur
|
||||
|
||||
abstract def letter : Char
|
||||
abstract def has_role(role : TileRole) : Bool
|
||||
|
||||
def withdraw(value)
|
||||
if value >= @cur
|
||||
wd = @cur
|
||||
@cur = 0
|
||||
wd
|
||||
else
|
||||
@cur -= value
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
def charge(value)
|
||||
charged = @cur + value
|
||||
@cur = charged <= @cap ? charged : @cap
|
||||
end
|
||||
end
|
||||
|
||||
class PlateauTile < Tile
|
||||
def letter : Char
|
||||
'.'
|
||||
end
|
||||
|
||||
def has_role(role : TileRole) : Bool
|
||||
role == TileRole::Plateau
|
||||
end
|
||||
end
|
||||
|
||||
class MainBaseTile < Tile
|
||||
def letter : Char
|
||||
'H'
|
||||
end
|
||||
|
||||
def has_role(role : TileRole) : Bool
|
||||
role == TileRole::Warehouse
|
||||
end
|
||||
end
|
||||
|
||||
class CrystalTile < Tile
|
||||
def initialize(@point : Point, cap : Int32)
|
||||
@cap = cap
|
||||
@cur = cap
|
||||
end
|
||||
|
||||
def letter : Char
|
||||
'f'
|
||||
end
|
||||
|
||||
def has_role(role : TileRole) : Bool
|
||||
role == TileRole::CrystalDeposits
|
||||
end
|
||||
end
|
||||
|
||||
class CrystalHarvesterTile < Tile
|
||||
def letter : Char
|
||||
'm'
|
||||
end
|
||||
|
||||
def has_role(role : TileRole) : Bool
|
||||
role == TileRole::CrystalHarvester
|
||||
end
|
||||
end
|
||||
|
||||
class CrystalRestorerTile < Tile
|
||||
def letter : Char
|
||||
'h'
|
||||
end
|
||||
|
||||
def has_role(role : TileRole) : Bool
|
||||
role == TileRole::CrystalRestorer
|
||||
end
|
||||
end
|
||||
|
||||
class TerraformerTile < Tile
|
||||
def letter : Char
|
||||
'T'
|
||||
end
|
||||
|
||||
def has_role(role : TileRole) : Bool
|
||||
role == TileRole::Terraformer
|
||||
end
|
||||
end
|
34
src/game/world.cr
Normal file
34
src/game/world.cr
Normal file
@@ -0,0 +1,34 @@
|
||||
require "./resources"
|
||||
|
||||
class World
|
||||
property ts : Int32
|
||||
|
||||
def initialize
|
||||
@ts = 0
|
||||
@map = Map.new
|
||||
@resources = Resources.new
|
||||
@tasks = App::Queue.new
|
||||
end
|
||||
|
||||
getter ts
|
||||
getter resources
|
||||
getter map
|
||||
|
||||
def push(command : Command)
|
||||
dur = command.start(self)
|
||||
done_at = @ts + dur
|
||||
@tasks.push(done_at, command)
|
||||
end
|
||||
|
||||
def run(ts : Int32)
|
||||
loop do
|
||||
item = @tasks.pop(ts)
|
||||
if item.nil?
|
||||
break
|
||||
end
|
||||
command = item.command
|
||||
@ts = item.ts
|
||||
command.finish(self)
|
||||
end
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user