Move core logic files to game

This commit is contained in:
Anton Vakhrushev
2019-10-03 17:19:44 +03:00
parent 446b1659de
commit e4035008b8
11 changed files with 10 additions and 11 deletions

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

@@ -0,0 +1,2 @@
class NotEnoughtResources < Exception
end

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

@@ -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

@@ -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

@@ -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

@@ -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