From 302ac37756bb374cdb41be0436f9886779274936 Mon Sep 17 00:00:00 2001 From: Jane Shimmer Date: Sun, 29 Oct 2023 22:50:29 -0400 Subject: [PATCH] aaaaaaaaaaaaaaaaa??! --- .gitignore | 11 ++ packages.dhall | 109 +++++++++++++++++++ spago.dhall | 35 ++++++ src/Main.purs | 58 ++++++++++ src/Screeps/Const.js | 117 ++++++++++++++++++++ src/Screeps/Const.purs | 118 +++++++++++++++++++++ src/Screeps/Creep.js | 4 + src/Screeps/Creep.purs | 133 +++++++++++++++++++++++ src/Screeps/FFI.js | 166 +++++++++++++++++++++++++++++ src/Screeps/FFI.purs | 37 +++++++ src/Screeps/Game.js | 32 ++++++ src/Screeps/Game.purs | 65 ++++++++++++ src/Screeps/Memory.js | 21 ++++ src/Screeps/Memory.purs | 22 ++++ src/Screeps/Room.js | 5 + src/Screeps/Room.purs | 36 +++++++ src/Screeps/Spawn.js | 12 +++ src/Screeps/Spawn.purs | 13 +++ src/Screeps/Storage.purs | 19 ++++ src/Screeps/Structure.purs | 8 ++ src/Screeps/Types.purs | 211 +++++++++++++++++++++++++++++++++++++ src/Shimmy/Creep.purs | 20 ++++ src/Shimmy/Spawning.purs | 74 +++++++++++++ test/Main.purs | 11 ++ 24 files changed, 1337 insertions(+) create mode 100644 .gitignore create mode 100644 packages.dhall create mode 100644 spago.dhall create mode 100644 src/Main.purs create mode 100644 src/Screeps/Const.js create mode 100644 src/Screeps/Const.purs create mode 100644 src/Screeps/Creep.js create mode 100644 src/Screeps/Creep.purs create mode 100644 src/Screeps/FFI.js create mode 100644 src/Screeps/FFI.purs create mode 100644 src/Screeps/Game.js create mode 100644 src/Screeps/Game.purs create mode 100644 src/Screeps/Memory.js create mode 100644 src/Screeps/Memory.purs create mode 100644 src/Screeps/Room.js create mode 100644 src/Screeps/Room.purs create mode 100644 src/Screeps/Spawn.js create mode 100644 src/Screeps/Spawn.purs create mode 100644 src/Screeps/Storage.purs create mode 100644 src/Screeps/Structure.purs create mode 100644 src/Screeps/Types.purs create mode 100644 src/Shimmy/Creep.purs create mode 100644 src/Shimmy/Spawning.purs create mode 100644 test/Main.purs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5d985d8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +/bower_components/ +/node_modules/ +/.pulp-cache/ +/output/ +/generated-docs/ +/.psc-package/ +/.psc* +/.purs* +/.psa* +/.spago +index.js \ No newline at end of file diff --git a/packages.dhall b/packages.dhall new file mode 100644 index 0000000..f95505b --- /dev/null +++ b/packages.dhall @@ -0,0 +1,109 @@ +{- +Welcome to your new Dhall package-set! + +Below are instructions for how to edit this file for most use +cases, so that you don't need to know Dhall to use it. + +## Use Cases + +Most will want to do one or both of these options: +1. Override/Patch a package's dependency +2. Add a package not already in the default package set + +This file will continue to work whether you use one or both options. +Instructions for each option are explained below. + +### Overriding/Patching a package + +Purpose: +- Change a package's dependency to a newer/older release than the + default package set's release +- Use your own modified version of some dependency that may + include new API, changed API, removed API by + using your custom git repo of the library rather than + the package set's repo + +Syntax: +where `entityName` is one of the following: +- dependencies +- repo +- version +------------------------------- +let upstream = -- +in upstream + with packageName.entityName = "new value" +------------------------------- + +Example: +------------------------------- +let upstream = -- +in upstream + with halogen.version = "master" + with halogen.repo = "https://example.com/path/to/git/repo.git" + + with halogen-vdom.version = "v4.0.0" + with halogen-vdom.dependencies = [ "extra-dependency" ] # halogen-vdom.dependencies +------------------------------- + +### Additions + +Purpose: +- Add packages that aren't already included in the default package set + +Syntax: +where `` is: +- a tag (i.e. "v4.0.0") +- a branch (i.e. "master") +- commit hash (i.e. "701f3e44aafb1a6459281714858fadf2c4c2a977") +------------------------------- +let upstream = -- +in upstream + with new-package-name = + { dependencies = + [ "dependency1" + , "dependency2" + ] + , repo = + "https://example.com/path/to/git/repo.git" + , version = + "" + } +------------------------------- + +Example: +------------------------------- +let upstream = -- +in upstream + with benchotron = + { dependencies = + [ "arrays" + , "exists" + , "profunctor" + , "strings" + , "quickcheck" + , "lcg" + , "transformers" + , "foldable-traversable" + , "exceptions" + , "node-fs" + , "node-buffer" + , "node-readline" + , "datetime" + , "now" + ] + , repo = + "https://github.com/hdgarrood/purescript-benchotron.git" + , version = + "v7.0.0" + } +------------------------------- +-} +let upstream = + https://github.com/purescript/package-sets/releases/download/psc-0.15.12-20231024/packages.dhall + sha256:8aa63621af6a0e6d8d4611279b454a1a69364be9f1151530aca72432160fa439 + +let overrides = {=} + +let additions = {=} + +in upstream // overrides // additions diff --git a/spago.dhall b/spago.dhall new file mode 100644 index 0000000..225a38a --- /dev/null +++ b/spago.dhall @@ -0,0 +1,35 @@ +{- +Welcome to a Spago project! +You can edit this file as you like. + +Need help? See the following resources: +- Spago documentation: https://github.com/purescript/spago +- Dhall language tour: https://docs.dhall-lang.org/tutorials/Language-Tour.html + +When creating a new Spago project, you can use +`spago init --no-comments` or `spago init -C` +to generate this file without the comments in this block. +-} +{ name = "ps-screeps-bot" +, dependencies = + [ "argonaut-codecs" + , "argonaut-core" + , "argonaut-generic" + , "arrays" + , "console" + , "effect" + , "either" + , "foldable-traversable" + , "foreign-object" + , "functions" + , "integers" + , "lists" + , "maybe" + , "ordered-collections" + , "partial" + , "prelude" + , "tuples" + ] +, packages = ./packages.dhall +, sources = [ "src/**/*.purs", "test/**/*.purs" ] +} diff --git a/src/Main.purs b/src/Main.purs new file mode 100644 index 0000000..ca5437e --- /dev/null +++ b/src/Main.purs @@ -0,0 +1,58 @@ +module Main where + +import Prelude +import Screeps.Types + +import Data.Argonaut.Decode (printJsonDecodeError) +import Data.Either (Either(..)) +import Data.Int (decimal, toStringAs) +import Data.Maybe (Maybe(..)) +import Effect (Effect) +import Effect.Console (log) +import Screeps.Game as Game +import Screeps.Memory as Memory +import Shimmy.Creep (manageCreeps) +import Shimmy.Spawning (initSpawn) + +main :: Effect Unit +main = do + game <- Game.getGameGlobal + memory <- Memory.getMemoryGlobal + status <- isInitialized memory + case status of + Nothing -> do + initLoop game memory LoopGo + Just s -> do + runLoop game memory s + +-- | is initialized +isInitialized :: Memory.MemoryGlobal -> Effect (Maybe LoopStatus) +isInitialized memory = do + status <- Memory.get memory "loopStatus" + case status of + Left err -> do + log $ printJsonDecodeError err + pure Nothing + Right s -> case s of + Nothing -> pure $ Just LoopGo + Just s1 -> pure s1 + +-- | init loop +initLoop :: GameGlobal -> Memory.MemoryGlobal -> LoopStatus -> Effect Unit +initLoop game memory status = do + log "init loop" + Memory.set memory "loopStatus" $ Just status + Memory.set memory "utility" 0 + let creeps = Game.creeps game + initSpawn creeps game memory + manageCreeps creeps game memory + -- + + +-- | run loop +runLoop :: GameGlobal -> Memory.MemoryGlobal -> LoopStatus -> Effect Unit +runLoop game memory status = do + let creeps = Game.creeps game + time = Game.time game + log $ toStringAs decimal time + manageCreeps creeps game memory \ No newline at end of file diff --git a/src/Screeps/Const.js b/src/Screeps/Const.js new file mode 100644 index 0000000..d15c21a --- /dev/null +++ b/src/Screeps/Const.js @@ -0,0 +1,117 @@ +"use_strict"; + +export const ok = OK; +export const err_not_owner = ERR_NOT_OWNER; +export const err_no_path = ERR_NO_PATH; +export const err_name_exists = ERR_NAME_EXISTS; +export const err_busy = ERR_BUSY; +export const err_not_found = ERR_NOT_FOUND; +export const err_not_enough_energy = ERR_NOT_ENOUGH_ENERGY; +export const err_not_enough_resources = ERR_NOT_ENOUGH_RESOURCES; +export const err_invalid_target = ERR_INVALID_TARGET; +export const err_full = ERR_FULL; +export const err_not_in_range = ERR_NOT_IN_RANGE; +export const err_invalid_args = ERR_INVALID_ARGS; +export const err_tired = ERR_TIRED; +export const err_no_bodypart = ERR_NO_BODYPART; +export const err_not_enough_extensions = ERR_NOT_ENOUGH_EXTENSIONS; +export const err_rcl_not_enough = ERR_RCL_NOT_ENOUGH; +export const err_gcl_not_enough = ERR_GCL_NOT_ENOUGH; + +export const find_exit_top = FIND_EXIT_TOP; +export const find_exit_right = FIND_EXIT_RIGHT; +export const find_exit_bottom = FIND_EXIT_BOTTOM; +export const find_exit_left = FIND_EXIT_LEFT; +export const find_exit = FIND_EXIT; +export const find_creeps = FIND_CREEPS; +export const find_my_creeps = FIND_MY_CREEPS; +export const find_hostile_creeps = FIND_HOSTILE_CREEPS; +export const find_sources_active = FIND_SOURCES_ACTIVE; +export const find_sources = FIND_SOURCES; +export const find_dropped_energy = FIND_DROPPED_ENERGY; +export const find_dropped_resources = FIND_DROPPED_RESOURCES; +export const find_structures = FIND_STRUCTURES; +export const find_structures0 = FIND_STRUCTURES; +export const find_my_structures = FIND_MY_STRUCTURES; +export const find_hostile_structures = FIND_HOSTILE_STRUCTURES; +export const find_flags = FIND_FLAGS; +export const find_construction_sites = FIND_CONSTRUCTION_SITES; +export const find_my_spawns = FIND_MY_SPAWNS; +export const find_hostile_spawns = FIND_HOSTILE_SPAWNS; +export const find_my_construction_sites = FIND_MY_CONSTRUCTION_SITES; +export const find_hostile_construction_sites = FIND_HOSTILE_CONSTRUCTION_SITES; +export const find_minerals = FIND_MINERALS; +export const find_nukes = FIND_NUKES; + +export const structure_spawn = STRUCTURE_SPAWN; +export const structure_extension = STRUCTURE_EXTENSION; +export const structure_road = STRUCTURE_ROAD; +export const structure_wall = STRUCTURE_WALL; +export const structure_rampart = STRUCTURE_RAMPART; +export const structure_keeper_lair = STRUCTURE_KEEPER_LAIR; +export const structure_portal = STRUCTURE_PORTAL; +export const structure_controller = STRUCTURE_CONTROLLER; +export const structure_link = STRUCTURE_LINK; +export const structure_storage = STRUCTURE_STORAGE; +export const structure_tower = STRUCTURE_TOWER; +export const structure_observer = STRUCTURE_OBSERVER; +export const structure_power_bank = STRUCTURE_POWER_BANK; +export const structure_power_spawn = STRUCTURE_POWER_SPAWN; +export const structure_extractor = STRUCTURE_EXTRACTOR; +export const structure_lab = STRUCTURE_LAB; +export const structure_terminal = STRUCTURE_TERMINAL; +export const structure_container = STRUCTURE_CONTAINER; +export const structure_nuker = STRUCTURE_NUKER; + +export const pMove = MOVE; +export const pWork = WORK; +export const pCarry = CARRY; + +export const resource_energy = RESOURCE_ENERGY; +export const resource_power = RESOURCE_POWER; + +export const resource_hydrogen = RESOURCE_HYDROGEN; +export const resource_oxygen = RESOURCE_OXYGEN; +export const resource_utrium = RESOURCE_UTRIUM; +export const resource_lemergium = RESOURCE_LEMERGIUM; +export const resource_keanium = RESOURCE_KEANIUM; +export const resource_zynthium = RESOURCE_ZYNTHIUM; +export const resource_catalyst = RESOURCE_CATALYST; +export const resource_ghodium = RESOURCE_GHODIUM; + +export const resource_hydroxide = RESOURCE_HYDROXIDE; +export const resource_zynthium_keanite = RESOURCE_ZYNTHIUM_KEANITE; +export const resource_utrium_lemergite = RESOURCE_UTRIUM_LEMERGITE; + +export const resource_utrium_hydride = RESOURCE_UTRIUM_HYDRIDE; +export const resource_utrium_oxide = RESOURCE_UTRIUM_OXIDE; +export const resource_keanium_hydride = RESOURCE_KEANIUM_HYDRIDE; +export const resource_keanium_oxide = RESOURCE_KEANIUM_OXIDE; +export const resource_lemergium_hydride = RESOURCE_LEMERGIUM_HYDRIDE; +export const resource_lemergium_oxide = RESOURCE_LEMERGIUM_OXIDE; +export const resource_zynthium_hydride = RESOURCE_ZYNTHIUM_HYDRIDE; +export const resource_zynthium_oxide = RESOURCE_ZYNTHIUM_OXIDE; +export const resource_ghodium_hydride = RESOURCE_GHODIUM_HYDRIDE; +export const resource_ghodium_oxide = RESOURCE_GHODIUM_OXIDE; + +export const resource_utrium_acid = RESOURCE_UTRIUM_ACID; +export const resource_utrium_alkalide = RESOURCE_UTRIUM_ALKALIDE; +export const resource_keanium_acid = RESOURCE_KEANIUM_ACID; +export const resource_keanium_alkalide = RESOURCE_KEANIUM_ALKALIDE; +export const resource_lemergium_acid = RESOURCE_LEMERGIUM_ACID; +export const resource_lemergium_alkalide = RESOURCE_LEMERGIUM_ALKALIDE; +export const resource_zynthium_acid = RESOURCE_ZYNTHIUM_ACID; +export const resource_zynthium_alkalide = RESOURCE_ZYNTHIUM_ALKALIDE; +export const resource_ghodium_acid = RESOURCE_GHODIUM_ACID; +export const resource_ghodium_alkalide = RESOURCE_GHODIUM_ALKALIDE; + +export const resource_catalyzed_utrium_acid = RESOURCE_CATALYZED_UTRIUM_ACID; +export const resource_catalyzed_utrium_alkalide = RESOURCE_CATALYZED_UTRIUM_ALKALIDE; +export const resource_catalyzed_keanium_acid = RESOURCE_CATALYZED_KEANIUM_ACID; +export const resource_catalyzed_keanium_alkalide = RESOURCE_CATALYZED_KEANIUM_ALKALIDE; +export const resource_catalyzed_lemergium_acid = RESOURCE_CATALYZED_LEMERGIUM_ACID; +export const resource_catalyzed_lemergium_alkalide = RESOURCE_CATALYZED_LEMERGIUM_ALKALIDE; +export const resource_catalyzed_zynthium_acid = RESOURCE_CATALYZED_ZYNTHIUM_ACID; +export const resource_catalyzed_zynthium_alkalide = RESOURCE_CATALYZED_ZYNTHIUM_ALKALIDE; +export const resource_catalyzed_ghodium_acid = RESOURCE_CATALYZED_GHODIUM_ACID; +export const resource_catalyzed_ghodium_alkalide = RESOURCE_CATALYZED_GHODIUM_ALKALIDE; \ No newline at end of file diff --git a/src/Screeps/Const.purs b/src/Screeps/Const.purs new file mode 100644 index 0000000..d32168a --- /dev/null +++ b/src/Screeps/Const.purs @@ -0,0 +1,118 @@ +module Screeps.Const where +import Prelude +import Screeps.Types + + +foreign import ok :: ReturnCode +foreign import err_not_owner :: ReturnCode +foreign import err_no_path :: ReturnCode +foreign import err_name_exists :: ReturnCode +foreign import err_busy :: ReturnCode +foreign import err_not_found :: ReturnCode +foreign import err_not_enough_energy :: ReturnCode +foreign import err_not_enough_resources :: ReturnCode +foreign import err_invalid_target :: ReturnCode +foreign import err_full :: ReturnCode +foreign import err_not_in_range :: ReturnCode +foreign import err_invalid_args :: ReturnCode +foreign import err_tired :: ReturnCode +foreign import err_no_bodypart :: ReturnCode +foreign import err_not_enough_extensions :: ReturnCode +foreign import err_rcl_not_enough :: ReturnCode +foreign import err_gcl_not_enough :: ReturnCode + +foreign import pMove :: BodyPartType +foreign import pWork :: BodyPartType +foreign import pCarry :: BodyPartType + +foreign import find_exit_top :: FindType RoomPosition +foreign import find_exit_right :: FindType RoomPosition +foreign import find_exit_bottom :: FindType RoomPosition +foreign import find_exit_left :: FindType RoomPosition +foreign import find_exit :: FindType RoomPosition +foreign import find_creeps :: FindType Creep +foreign import find_my_creeps :: FindType Creep +foreign import find_hostile_creeps :: FindType Creep +foreign import find_sources_active :: FindType Source +foreign import find_sources :: FindType Source +foreign import find_dropped_energy :: FindType Resource +foreign import find_dropped_resources :: FindType Resource +foreign import find_structures :: FindType (Structure Unit) +foreign import find_my_structures :: forall a. FindType (Structure a) +foreign import find_hostile_structures :: FindType (Structure Unit) +foreign import find_flags :: FindType Flag +foreign import find_construction_sites :: FindType ConstructionSite +foreign import find_my_spawns :: FindType Spawn +foreign import find_hostile_spawns :: FindType Spawn +foreign import find_my_construction_sites :: FindType ConstructionSite +foreign import find_hostile_construction_sites :: FindType ConstructionSite +foreign import find_minerals :: FindType Mineral +foreign import find_nukes :: FindType Nuke + +foreign import structure_spawn :: StructureType +foreign import structure_extension :: StructureType +foreign import structure_road :: StructureType +foreign import structure_wall :: StructureType +foreign import structure_rampart :: StructureType +foreign import structure_keeper_lair :: StructureType +foreign import structure_portal :: StructureType +foreign import structure_controller :: StructureType +foreign import structure_link :: StructureType +foreign import structure_storage :: StructureType +foreign import structure_tower :: StructureType +foreign import structure_observer :: StructureType +foreign import structure_power_bank :: StructureType +foreign import structure_power_spawn :: StructureType +foreign import structure_extractor :: StructureType +foreign import structure_lab :: StructureType +foreign import structure_terminal :: StructureType +foreign import structure_container :: StructureType +foreign import structure_nuker :: StructureType +foreign import resource_energy :: ResourceType +foreign import resource_power :: ResourceType + +foreign import resource_hydrogen :: ResourceType +foreign import resource_oxygen :: ResourceType +foreign import resource_utrium :: ResourceType +foreign import resource_lemergium :: ResourceType +foreign import resource_keanium :: ResourceType +foreign import resource_zynthium :: ResourceType +foreign import resource_catalyst :: ResourceType +foreign import resource_ghodium :: ResourceType + +foreign import resource_hydroxide :: ResourceType +foreign import resource_zynthium_keanite :: ResourceType +foreign import resource_utrium_lemergite :: ResourceType + +foreign import resource_utrium_hydride :: ResourceType +foreign import resource_utrium_oxide :: ResourceType +foreign import resource_keanium_hydride :: ResourceType +foreign import resource_keanium_oxide :: ResourceType +foreign import resource_lemergium_hydride :: ResourceType +foreign import resource_lemergium_oxide :: ResourceType +foreign import resource_zynthium_hydride :: ResourceType +foreign import resource_zynthium_oxide :: ResourceType +foreign import resource_ghodium_hydride :: ResourceType +foreign import resource_ghodium_oxide :: ResourceType + +foreign import resource_utrium_acid :: ResourceType +foreign import resource_utrium_alkalide :: ResourceType +foreign import resource_keanium_acid :: ResourceType +foreign import resource_keanium_alkalide :: ResourceType +foreign import resource_lemergium_acid :: ResourceType +foreign import resource_lemergium_alkalide :: ResourceType +foreign import resource_zynthium_acid :: ResourceType +foreign import resource_zynthium_alkalide :: ResourceType +foreign import resource_ghodium_acid :: ResourceType +foreign import resource_ghodium_alkalide :: ResourceType + +foreign import resource_catalyzed_utrium_acid :: ResourceType +foreign import resource_catalyzed_utrium_alkalide :: ResourceType +foreign import resource_catalyzed_keanium_acid :: ResourceType +foreign import resource_catalyzed_keanium_alkalide :: ResourceType +foreign import resource_catalyzed_lemergium_acid :: ResourceType +foreign import resource_catalyzed_lemergium_alkalide :: ResourceType +foreign import resource_catalyzed_zynthium_acid :: ResourceType +foreign import resource_catalyzed_zynthium_alkalide :: ResourceType +foreign import resource_catalyzed_ghodium_acid :: ResourceType +foreign import resource_catalyzed_ghodium_alkalide :: ResourceType diff --git a/src/Screeps/Creep.js b/src/Screeps/Creep.js new file mode 100644 index 0000000..5298958 --- /dev/null +++ b/src/Screeps/Creep.js @@ -0,0 +1,4 @@ +"use strict"; +export function totalAmtCarrying(creep){ + return _.sum(creep.carry); + } \ No newline at end of file diff --git a/src/Screeps/Creep.purs b/src/Screeps/Creep.purs new file mode 100644 index 0000000..4c12f09 --- /dev/null +++ b/src/Screeps/Creep.purs @@ -0,0 +1,133 @@ +module Screeps.Creep where + +import Prelude +import Effect (Effect) +import Data.Maybe (Maybe) +import Data.Either (Either) +import Data.Argonaut.Decode (class DecodeJson, decodeJson, JsonDecodeError) +import Data.Argonaut.Encode (class EncodeJson, encodeJson) +import Screeps.FFI (unsafeGetCreepEff) +import Screeps.Types +import Screeps.FFI ( unsafeField, runThisFn1 + , runThisEffFn1, runThisEffFn2 + , runThisEffFn3, toMaybe + , unsafeGetCreepEff, unsafeSetCreepEff + , unsafeGetAllCreepEff ) +foreign import data CreepCargo :: Type +foreign import totalAmtCarrying :: Creep -> Int + +body :: Creep -> Array BodyPart +body creep = unsafeField "body" creep + +carry :: Creep -> CreepCargo +carry = unsafeField "carry" + +amtCarrying :: Creep -> ResourceType -> Int +amtCarrying creep res = unsafeField (show res) $ carry creep + +carryCapacity :: Creep -> Int +carryCapacity = unsafeField "carryCapacity" + +fatigue :: Creep -> Int +fatigue = unsafeField "fatigue" + +hits :: Creep -> Int +hits = unsafeField "hits" + +hitsMax :: Creep -> Int +hitsMax = unsafeField "hitsMax" + +getId :: Creep -> Id Creep +getId = unsafeField "id" + +getIdAsStr :: Creep -> String +getIdAsStr = unsafeField "id" + +my :: Creep -> Boolean +my = unsafeField "my" + +name :: Creep -> String +name = unsafeField "name" + +owner :: Creep -> { username :: String } +owner = unsafeField "owner" + +saying :: Creep -> Maybe String +saying c = toMaybe $ unsafeField "saying" c + +spawning :: Creep -> Boolean +spawning = unsafeField "spawning" + +ticksToLive :: Creep -> Int +ticksToLive = unsafeField "ticksToLive" + +attackCreep :: Creep -> Creep -> Effect ReturnCode +attackCreep = runThisEffFn1 "attack" + +attackStructure :: forall a. Creep → Structure a -> Effect ReturnCode +attackStructure = runThisEffFn1 "attack" + +attackController :: forall a. Creep -> Structure a -> Effect ReturnCode +attackController = runThisEffFn1 "attackController" + +build :: Creep -> ConstructionSite -> Effect ReturnCode +build = runThisEffFn1 "build" + +cancelOrder :: Creep -> String -> Effect ReturnCode +cancelOrder = runThisEffFn1 "cancelOrder" + +claimController :: forall a. Creep -> Structure a -> Effect ReturnCode +claimController = runThisEffFn1 "claimController" + +dismantle :: forall a. Creep -> Structure a -> Effect ReturnCode +dismantle = runThisEffFn1 "dismantle" + +drop :: Creep -> ResourceType -> Effect ReturnCode +drop = runThisEffFn1 "drop" + +dropAmt :: Creep -> ResourceType -> Int -> Effect ReturnCode +dropAmt = runThisEffFn2 "drop" + +getActiveBodyparts :: Creep -> BodyPartType -> Int +getActiveBodyparts = runThisFn1 "getActiveBodyparts" + +harvestSource :: Creep -> Source -> Effect ReturnCode +harvestSource = runThisEffFn1 "harvest" + +harvestMineral :: Creep -> Mineral -> Effect ReturnCode +harvestMineral = runThisEffFn1 "harvest" + +heal :: Creep -> Creep -> Effect ReturnCode +heal = runThisEffFn1 "heal" + +move :: Creep -> Direction -> Effect ReturnCode +move = runThisEffFn1 "move" + +moveByPath :: Creep -> Path -> Effect ReturnCode +moveByPath = runThisEffFn1 "moveByPath" + +moveTo :: forall a. Creep -> TargetPosition a -> Effect ReturnCode +moveTo creep (TargetPt x y) = runThisEffFn2 "moveTo" creep x y +moveTo creep (TargetPos pos) = runThisEffFn1 "moveTo" creep pos +moveTo creep (TargetObj obj) = runThisEffFn1 "moveTo" creep obj + +transferToCreep :: Creep -> Creep -> ResourceType -> Int -> Effect ReturnCode +transferToCreep = runThisEffFn3 "transfer" + +transferToStructure :: forall a. Creep -> Structure a -> ResourceType -> Effect ReturnCode +transferToStructure = runThisEffFn2 "transfer" + +transferAmtToStructure :: forall a. Creep -> Structure a -> ResourceType -> Int -> Effect ReturnCode +transferAmtToStructure = runThisEffFn3 "transfer" + +creepStore ∷ Creep → Store +creepStore = unsafeField "store" + +getAllCreepMem ∷ ∀ a. (DecodeJson a) ⇒ String → Effect (Either JsonDecodeError a) +getAllCreepMem creep = decodeJson <$> unsafeGetAllCreepEff creep + +getCreepMem ∷ ∀ a. (DecodeJson a) ⇒ String → String → Effect (Either JsonDecodeError a) +getCreepMem creep key = decodeJson <$> unsafeGetCreepEff creep key + +setCreepMem ∷ ∀ a. (EncodeJson a) ⇒ String → String → a → Effect Unit +setCreepMem creep key val = unsafeSetCreepEff creep key $ encodeJson val diff --git a/src/Screeps/FFI.js b/src/Screeps/FFI.js new file mode 100644 index 0000000..8f70b3e --- /dev/null +++ b/src/Screeps/FFI.js @@ -0,0 +1,166 @@ +"use strict"; + +// module Screeps.FFI + +export function unsafeField(key){ + return function(obj){ + return obj[key]; + } +} +export function unsafeGetFieldEff(key){ + return function(obj){ + return function(){ + return obj[key]; + } + } +} +export function unsafeSetFieldEff(key){ + return function(obj){ + return function(val){ + return function(){ + obj[key] = val; + } + } + } +} +export function unsafeDeleteFieldEff(key){ + return function(obj){ + return function(){ + delete obj[key]; + } + } +} +export function runThisEffFn0(key){ + return function(self){ + return function(){ + return self[key](); + } + } +} +export function runThisEffFn1(key){ + return function(self){ + return function(a){ + return function(){ + return self[key](a); + } + } + } +} +export function runThisEffFn2(key){ + return function(self){ + return function(a){ + return function(b){ + return function(){ + return self[key](a, b); + } + } + } + } +} +export function runThisEffFn3(key){ + return function(self){ + return function(a){ + return function(b){ + return function(c){ + return function(){ + return self[key](a, b, c); + } + } + } + } + } +} +export function runThisEffFn4(key){ + return function(self){ + return function(a){ + return function(b){ + return function(c){ + return function(d){ + return function(){ + return self[key](a, b, c, d); + } + } + } + } + } + } +} +export function runThisFn0(key){ + return function(self){ + return self[key](); + } +} +export function runThisFn1(key){ + return function(self){ + return function(a){ + return self[key](a); + } + } +} +export function runThisFn2(key){ + return function(self){ + return function(a){ + return function(b){ + return self[key](a,b); + } + } + } +} +export function runThisFn3(key){ + return function(self){ + return function(a){ + return function(b){ + return function(c){ + return self[key](a,b,c); + } + } + } + } +} +export const _null = null; +export const _undefined = undefined +export function notNullOrUndefined(x){ + return x; +} +export function isNull(x){ + return x === null; +} +export function isUndefined(x){ + return x === undefined; +} +export function toMaybeImpl (val, nothing, just){ + if(val === null || val === undefined){ + return nothing; + } else { + return just(val); + } +} +export function unsafeGetAllCreepEff(creep){ + return function(){ + return Memory.creeps[creep]; + } +} +export function unsafeGetCreepEff(creep,key){ + return function(){ + return Memory.creeps[creep][key]; + } +} +export function unsafeSetCreepEff(creep,key){ + return function(val){ + return Memory.creeps[creep][key] = val; + } +} +// export function rawSpawnCreep(){ +// return function (self){ +// return function(spawn){ +// return function(parts){ +// return function(name){ +// return function(r){ +// console.log("spawning creep..."); +// return self.spawns[spawn].spawnCreep(parts,name,{memory: {role: r, utility: 1}}); +// } +// } +// } +// } +// } +// } \ No newline at end of file diff --git a/src/Screeps/FFI.purs b/src/Screeps/FFI.purs new file mode 100644 index 0000000..4142a77 --- /dev/null +++ b/src/Screeps/FFI.purs @@ -0,0 +1,37 @@ +module Screeps.FFI where +import Prelude +import Effect (Effect) +import Data.Maybe (Maybe(Just, Nothing), isJust, fromJust, maybe) +import Data.Function.Uncurried ( Fn3, runFn3 ) +import Screeps.Types + +foreign import unsafeField :: forall obj val. String -> obj -> val +foreign import unsafeGetFieldEff :: forall obj val. String -> obj -> Effect val +foreign import unsafeSetFieldEff :: forall obj val. String -> obj -> val -> Effect Unit +foreign import unsafeDeleteFieldEff :: forall obj. String -> obj -> Effect Unit +foreign import runThisEffFn0 :: forall this a. String -> this -> Effect a +foreign import runThisEffFn1 :: forall this a b. String -> this -> a -> Effect b +foreign import runThisEffFn2 :: forall this a b c. String -> this -> a -> b -> Effect c +foreign import runThisEffFn3 :: forall this a b c d. String + -> this -> a -> b -> c -> Effect d +foreign import runThisEffFn4 :: forall this a b c d e. String + -> this -> a -> b -> c -> d -> Effect e +foreign import runThisFn0 :: forall this a. String -> this -> a +foreign import runThisFn1 :: forall this a b. String -> this -> a -> b +foreign import runThisFn2 :: forall this a b c. String -> this -> a -> b → c +foreign import runThisFn3 :: forall this a b c d. String -> this -> a -> b → c → d + +foreign import data NullOrUndefined :: Type -> Type +foreign import _null :: forall a. NullOrUndefined a +foreign import _undefined :: forall a. NullOrUndefined a +foreign import notNullOrUndefined :: forall a. a -> NullOrUndefined a +foreign import isNull :: forall a. NullOrUndefined a -> Boolean +foreign import isUndefined :: forall a. NullOrUndefined a -> Boolean +foreign import toMaybeImpl :: forall a m. Fn3 (NullOrUndefined a) m (a -> m) m + +foreign import unsafeGetAllCreepEff :: ∀ val. String → Effect val +foreign import unsafeGetCreepEff :: ∀ val. String → String → Effect val +foreign import unsafeSetCreepEff :: ∀ val. String → String → val → Effect Unit + +toMaybe :: forall a. NullOrUndefined a -> Maybe a +toMaybe n = runFn3 toMaybeImpl n Nothing Just diff --git a/src/Screeps/Game.js b/src/Screeps/Game.js new file mode 100644 index 0000000..d74fc91 --- /dev/null +++ b/src/Screeps/Game.js @@ -0,0 +1,32 @@ +"use strict"; + +export function getGameGlobal(){ return Game; } +export function createCreepImpl(structure){ + return function(parts){ + return function(role){ + return function(left){ + return function(right){ + return function(){ + var result = structure.createCreep(parts,{utility: 1, role: role}); + if (typeof result === "string"){ + return right(result); + } else { + return left(result); + } + } + } + } + } + } +} +export function rawGetUtility(key){ + return function(obj){ + return obj.creeps[key].utility; + } +} + +export function rawGetRole(key){ + return function(obj){ + return obj.creeps[key].role; + } +} \ No newline at end of file diff --git a/src/Screeps/Game.purs b/src/Screeps/Game.purs new file mode 100644 index 0000000..c551b17 --- /dev/null +++ b/src/Screeps/Game.purs @@ -0,0 +1,65 @@ +module Screeps.Game where +import Prelude +import Foreign.Object as F +import Effect (Effect) +import Screeps.Types +import Screeps.Memory as Memory +import Screeps.FFI ( runThisEffFn0, runThisFn1 + , unsafeField, toMaybe ) +import Data.Maybe ( Maybe ) +import Data.Either ( Either(..) ) +import Data.Argonaut.Core ( Json ) +import Data.Argonaut.Encode ( encodeJson ) +import Data.Map as Map + +foreign import getGameGlobal ∷ Effect GameGlobal +foreign import createCreepImpl ∷ Spawn → Array BodyPartType → Json + → (ReturnCode → Either ReturnCode String) + → (String → Either ReturnCode String) + → Effect (Either ReturnCode String) +foreign import rawGetUtility ∷ String → Memory.MemoryGlobal → Int +foreign import rawGetRole ∷ String → Memory.MemoryGlobal → Role + +type Cpu = { limit ∷ Int + , tickLimit ∷ Int + , bucket ∷ Int } + +cpu ∷ GameGlobal → Cpu +cpu = unsafeField "cpu" +spawns ∷ GameGlobal → F.Object Spawn +spawns = unsafeField "spawns" + +creeps ∷ GameGlobal → F.Object Creep +creeps = unsafeField "creeps" + +getUsed ∷ GameGlobal → Effect Number +getUsed game = runThisEffFn0 "getUsed" (cpu game) + +getObjectById ∷ ∀ a. GameGlobal → Id a → Maybe a +getObjectById game id + = toMaybe (runThisFn1 "getObjectById" game id) + +getUtility ∷ Memory.MemoryGlobal → String → Int +getUtility mem key = rawGetUtility key mem + +getRole ∷ Memory.MemoryGlobal → String → Role +getRole mem key = rawGetRole key mem + +rawSpawnCreep ∷ Spawn → Array BodyPartType → String + → Role → Effect (Either ReturnCode String) +rawSpawnCreep spawn parts name role + = createCreepImpl spawn parts role' Left Right + where role' = encodeJson role + +rawSpawnCreepAs ∷ Spawn + → Array BodyPartType → String → Role + → Effect (Either ReturnCode String) +rawSpawnCreepAs spawn parts name role + = createCreepImpl spawn parts role' Left Right + where role' = encodeJson role + +time ∷ GameGlobal → Int +time = unsafeField "time" + +map ∷ GameGlobal → WorldMap +map = unsafeField "map" diff --git a/src/Screeps/Memory.js b/src/Screeps/Memory.js new file mode 100644 index 0000000..10345f2 --- /dev/null +++ b/src/Screeps/Memory.js @@ -0,0 +1,21 @@ +"use strict"; + +export function getMemoryGlobal(){ return Memory; } +export function getRawMemoryGlobal(){ return RawMemory; } +export function getCreepsUtl(){ + var res = [] + for (var c in Memory.creeps) { + res = res.concat(Memory.creeps[c]["utility"]) + } + return res +} +export function getCreepsNames(){ + var res = [] + for (var c in Memory.creeps) { + res += c + } + return res +} +export function setCreepsUtl(key,n){ + return Memory.creeps[key] = n +} \ No newline at end of file diff --git a/src/Screeps/Memory.purs b/src/Screeps/Memory.purs new file mode 100644 index 0000000..0dd28c4 --- /dev/null +++ b/src/Screeps/Memory.purs @@ -0,0 +1,22 @@ +module Screeps.Memory where +import Prelude +import Effect (Effect) +import Screeps.FFI (unsafeGetFieldEff, unsafeSetFieldEff) +import Data.Tuple (Tuple) +import Data.Argonaut.Core ( Json ) +import Data.Argonaut.Decode (class DecodeJson, decodeJson, JsonDecodeError) +import Data.Argonaut.Encode (class EncodeJson, encodeJson) +import Data.Either (Either) +import Foreign.Object as F + +foreign import data MemoryGlobal :: Type +foreign import getMemoryGlobal :: Effect MemoryGlobal +foreign import data RawMemoryGlobal :: Type +foreign import getRawMemoryGlobal :: Effect RawMemoryGlobal +foreign import setCreepsUtl :: String -> Int -> Effect Unit +foreign import getCreepsUtl :: Effect (Array Int) + +set :: forall a. (EncodeJson a) => MemoryGlobal -> String -> a -> Effect Unit +set memoryGlobal key val = unsafeSetFieldEff key memoryGlobal $ encodeJson val +get :: forall a. (DecodeJson a) => MemoryGlobal -> String -> Effect (Either JsonDecodeError a) +get memoryGlobal key = decodeJson <$> unsafeGetFieldEff key memoryGlobal diff --git a/src/Screeps/Room.js b/src/Screeps/Room.js new file mode 100644 index 0000000..6b29271 --- /dev/null +++ b/src/Screeps/Room.js @@ -0,0 +1,5 @@ +"use strict"; + +export function setRoomMem(room,nharvs,maxnharvs){ + return room.memory = { "nharvs" : nharvs, "maxnharvs" : maxnharvs }; +} \ No newline at end of file diff --git a/src/Screeps/Room.purs b/src/Screeps/Room.purs new file mode 100644 index 0000000..b97c14b --- /dev/null +++ b/src/Screeps/Room.purs @@ -0,0 +1,36 @@ +module Screeps.Room where +import Prelude +import Effect (Effect) +import Data.Maybe ( Maybe ) +import Screeps.Structure ( structureType ) +import Screeps.Game as Game +import Screeps.Types +import Screeps.FFI ( runThisFn0, runThisFn1 + , runThisFn2, runThisFn3 + , unsafeField, toMaybe ) +import Foreign.Object as F + +-- | returns a list of sources given a room +--findSources ∷ ∀ a. Room → Array (RoomObject a) +--findSources room = find' room find_structures (\s → isSource s) +foreign import setRoomMem :: Room → Int → Int → Effect Unit + +find ∷ ∀ a. Room → FindType a → Array a +find = runThisFn1 "find" +-- | returns find when we want to use optional filter +find' ∷ ∀ a. Room → FindType a → FilterFn a → Array a +find' room findType filter = runThisFn2 "find" room findType { filter } + +room ∷ ∀ a. RoomObject a → Room +room = unsafeField "room" + +storage ∷ Room → Storage +storage = unsafeField "storage" + +getTerrain ∷ Room → Terrain +getTerrain = runThisFn0 "getTerrain" + +getTerrainAt ∷ ∀ a. TargetPosition a → String → Terrain +getTerrainAt (TargetPt x y) roomName = runThisFn3 "getTerrainAt" Game.map x y roomName +getTerrainAt (TargetPos pos) roomName = runThisFn2 "getTerrainAt" Game.map pos roomName +getTerrainAt (TargetObj obj) roomName = runThisFn2 "getTerrainAt" Game.map obj roomName diff --git a/src/Screeps/Spawn.js b/src/Screeps/Spawn.js new file mode 100644 index 0000000..1acee22 --- /dev/null +++ b/src/Screeps/Spawn.js @@ -0,0 +1,12 @@ +"use strict"; + +export function spawnStoreCapacity(obj){ + var ret = obj.store; + if (typeof ret !== 'undefined') + return ret.getFreeCapacity(RESOURCE_ENERGY); +} +export function spawnStoreEnergy(obj){ + var ret = obj.store; + if (typeof ret !== 'undefined') + return ret[RESOURCE_ENERGY]; +} \ No newline at end of file diff --git a/src/Screeps/Spawn.purs b/src/Screeps/Spawn.purs new file mode 100644 index 0000000..3c58ed7 --- /dev/null +++ b/src/Screeps/Spawn.purs @@ -0,0 +1,13 @@ +module Screeps.Spawn where + +import Prelude +import Effect (Effect) +import Screeps.Types +import Screeps.FFI ( unsafeField, toMaybe ) +import Data.Maybe (Maybe) + +foreign import spawnStoreCapacity ∷ ∀ obj. obj → Int +foreign import spawnStoreEnergy ∷ ∀ obj. obj → Int + +spawnStore ∷ ∀ a. Structure a → Store +spawnStore = unsafeField "store" diff --git a/src/Screeps/Storage.purs b/src/Screeps/Storage.purs new file mode 100644 index 0000000..59f000d --- /dev/null +++ b/src/Screeps/Storage.purs @@ -0,0 +1,19 @@ +module Screeps.Storage where +import Prelude +import Screeps.Types +import Screeps.FFI (unsafeField,runThisFn0) + +storeFreeCapacity ∷ Store → Int +storeFreeCapacity = runThisFn0 "getFreeCapacity" + +storeCapacity ∷ Store → Int +storeCapacity = unsafeField "storeCapacity" + +store ∷ Storage → Store +store = unsafeField "store" + +storageGet ∷ Storage → ResourceType → Int +storageGet s (ResourceType res) = unsafeField res (store s) + +storeGet ∷ Store → ResourceType → Int +storeGet s (ResourceType res) = unsafeField res s diff --git a/src/Screeps/Structure.purs b/src/Screeps/Structure.purs new file mode 100644 index 0000000..d42d1f5 --- /dev/null +++ b/src/Screeps/Structure.purs @@ -0,0 +1,8 @@ +module Screeps.Structure where +import Prelude +import Effect (Effect) +import Screeps.Types +import Screeps.FFI ( unsafeField ) + +structureType ∷ ∀ a. Structure a → StructureType +structureType = unsafeField "structureType" diff --git a/src/Screeps/Types.purs b/src/Screeps/Types.purs new file mode 100644 index 0000000..5b1f0f8 --- /dev/null +++ b/src/Screeps/Types.purs @@ -0,0 +1,211 @@ +module Screeps.Types where +import Prelude +import Data.Eq +import Data.Maybe (Maybe(..)) +import Data.Either (note) +import Data.Generic.Rep ( class Generic ) +import Data.Eq.Generic ( genericEq ) +import Data.Show ( class Show ) +import Data.Show.Generic ( genericShow ) +import Data.Argonaut.Decode (class DecodeJson, decodeJson, JsonDecodeError(..), getField) +import Data.Argonaut.Encode (class EncodeJson, encodeJson) +import Data.Argonaut.Encode.Generic (genericEncodeJson) +import Data.Argonaut.Decode.Generic (genericDecodeJson) + +foreign import data GameGlobal :: Type +foreign import data RawRoomObject :: Type -> Type +foreign import data Room :: Type +foreign import data WorldMap :: Type +foreign import data RawStructure :: Type -> Type +foreign import data RawOwnedStructure :: Type -> Type +foreign import data RawConstructionSite :: Type +foreign import data RawSpawn :: Type +foreign import data RawTower :: Type +foreign import data RawCreep :: Type +foreign import data RawMineral :: Type +foreign import data RawResource :: Type +foreign import data RawSource :: Type +foreign import data RawStorage :: Type +foreign import data RawFlag :: Type +foreign import data RawNuke :: Type +foreign import data RoomPosition :: Type +foreign import data Store ∷ Type + +type RoomObject a = RawRoomObject a +type Structure a = RoomObject (RawStructure a) +type OwnedStructure a = Structure (RawOwnedStructure a) +type ConstructionSite = RoomObject RawConstructionSite +type Storage = OwnedStructure RawStorage +type Spawn = OwnedStructure RawSpawn +type Tower = OwnedStructure RawTower +type Creep = RoomObject RawCreep +type Mineral = RoomObject RawMineral +type Resource = RoomObject RawResource +type Source = RoomObject RawSource +type Flag = RoomObject RawFlag +type Nuke = RoomObject RawNuke + +type Path = Array PathStep + +type PathStep = + { x :: Int + , y :: Int + , dx :: Number + , dy :: Number + , direction :: Direction } + +newtype Id a = Id String +derive instance genericId :: Generic (Id a) _ +instance eqId :: Eq (Id a) where eq = genericEq +instance showId :: Show (Id a) where show = genericShow +instance decodeJsonId :: DecodeJson (Id a) where decodeJson = genericDecodeJson +instance encodeJsonId :: EncodeJson (Id a) where encodeJson = genericEncodeJson + +type BodyPart = + { boost :: Maybe String + , type :: BodyPartType + , hits :: Int } + +type MoveOptions = PathOptions + ( reusePath :: Maybe Int + , serializeMemory :: Maybe Boolean + , noPathFinding :: Maybe Boolean ) + +type PathOptions o = + { ignoreCreeps :: Maybe Boolean + , ignoreDestructibleStructures :: Maybe Boolean + , ignoreRoads :: Maybe Boolean + , ignore :: Maybe (Array RoomPosition) + , avoid :: Maybe (Array RoomPosition) + , maxOps :: Maybe Int + , heuristicWeight :: Maybe Number + , serialize :: Maybe Boolean + , maxRooms :: Maybe Int + | o } + +moveOpts :: MoveOptions +moveOpts = + { ignoreCreeps: Nothing + , ignoreDestructibleStructures: Nothing + , ignoreRoads: Nothing + , ignore: Nothing + , avoid: Nothing + , maxOps: Nothing + , heuristicWeight: Nothing + , serialize: Nothing + , maxRooms: Nothing + , reusePath: Nothing + , serializeMemory: Nothing + , noPathFinding: Nothing } + +pathOpts :: PathOptions () +pathOpts = + { ignoreCreeps: Nothing + , ignoreDestructibleStructures: Nothing + , ignoreRoads: Nothing + , ignore: Nothing + , avoid: Nothing + , maxOps: Nothing + , heuristicWeight: Nothing + , serialize: Nothing + , maxRooms: Nothing } + +newtype BodyPartType = BodyPartType String +derive instance genericBodyPartType :: Generic BodyPartType _ +instance eqBodyPartType :: Eq BodyPartType where eq = genericEq +instance showBodyPartType :: Show BodyPartType where show = genericShow + +newtype ResourceType = ResourceType String +derive instance genericResourceType :: Generic ResourceType _ +instance eqResourceType :: Eq ResourceType where eq = genericEq +instance showResourceType :: Show ResourceType where + show (ResourceType s) = s + +newtype ReturnCode = ReturnCode Int +derive instance genericReturnCode :: Generic ReturnCode _ +instance eqReturnCode :: Eq ReturnCode where eq = genericEq +instance showReturnCode :: Show ReturnCode where + show (ReturnCode n) = show n + +newtype StructureType = StructureType String +derive instance genericStructureType :: Generic StructureType _ +instance eqStructureType :: Eq StructureType where eq = genericEq +instance showStructureType :: Show StructureType where show = genericShow + +newtype Direction = Direction Int +derive instance genericDirection :: Generic Direction _ +instance eqDirection :: Eq Direction where eq = genericEq +instance showDirection :: Show Direction where show = genericShow + +newtype TerrainMask = TerrainMask Int +derive instance genericTerrainMask :: Generic TerrainMask _ +instance eqTerrainMask :: Eq TerrainMask where eq = genericEq +instance showTerrainMask :: Show TerrainMask where show = genericShow + +newtype Terrain = Terrain String +derive instance genericTerrain :: Generic Terrain _ +instance eqTerrain :: Eq Terrain where eq = genericEq +instance showTerrain :: Show Terrain + where show (Terrain s) = s + +data TargetPosition a = + TargetPt Int Int | + TargetObj (RoomObject a) | + TargetPos RoomPosition +type FilterFn a = a -> Boolean +newtype FindType a = FindType Int + +-- | creep types are generic, irrelevant of job or role +data CreepType = CreepDrone | CreepNULL +-- | creeps can take on many roles, depending on what type they are +data Role = RoleIdle + | RoleHarvester + | RoleBuilder + | RoleNULL +instance showRole ∷ Show Role where + show RoleHarvester = "RoleHarvester" + show RoleBuilder = "RoleBuilder" + show RoleIdle = "RoleIdle" + show RoleNULL = "RoleNULL" +instance eqRoles ∷ Eq Role where + eq RoleNULL RoleNULL = true + eq RoleIdle RoleIdle = true + eq RoleHarvester RoleHarvester = true + eq RoleBuilder RoleBuilder = true + eq _ RoleNULL = false + eq RoleNULL _ = false + eq _ _ = false +roleList = [RoleIdle, RoleHarvester, RoleBuilder, RoleNULL] ∷ Array Role +instance encodeRole :: EncodeJson Role where + encodeJson RoleIdle = encodeJson "RoleIdle" + encodeJson RoleHarvester = encodeJson "RoleHarvester" + encodeJson RoleBuilder = encodeJson "RoleBuilder" + encodeJson RoleNULL = encodeJson "RoleNULL" +instance decodeRole :: DecodeJson Role where + decodeJson json = do + string <- decodeJson json + note (TypeMismatch "Role:") (roleFromStr string) +roleFromStr :: String -> Maybe Role +roleFromStr "RoleHarvester" = Just RoleHarvester +roleFromStr "RoleBuilder" = Just RoleBuilder +roleFromStr "RoleIdle" = Just RoleIdle +roleFromStr "RoleNULL" = Just RoleNULL +roleFromStr _ = Nothing +-- | jobs are like temporary roles +data Job = JobBuild | JobNULL +-- | the main loop control variable allow some control over state +-- encoded straight into the json memory so we write some instances +data LoopStatus = LoopGo | LoopStop | LoopNULL +instance encodeLoopStatus :: EncodeJson LoopStatus where + encodeJson LoopGo = encodeJson "loopGo" + encodeJson LoopStop = encodeJson "loopStop" + encodeJson LoopNULL = encodeJson "loopNULL" +instance decodeLoopStatus :: DecodeJson LoopStatus where + decodeJson json = do + string <- decodeJson json + note (TypeMismatch "LoopStatus:") (lsFromStr string) +lsFromStr :: String -> Maybe LoopStatus +lsFromStr "loopGo" = Just LoopGo +lsFromStr "loopStop" = Just LoopStop +lsFromStr "loopNULL" = Just LoopNULL +lsFromStr _ = Nothing diff --git a/src/Shimmy/Creep.purs b/src/Shimmy/Creep.purs new file mode 100644 index 0000000..ba64ad4 --- /dev/null +++ b/src/Shimmy/Creep.purs @@ -0,0 +1,20 @@ +module Shimmy.Creep where + +import Prelude +import Screeps.Types + +import Data.Maybe (Maybe(..)) +import Effect (Effect) +import Foreign.Object as F +import Screeps.Game as Game +import Screeps.Memory as Memory +import Shimmy.Spawning (doSpawnCheck) + +manageCreeps :: F.Object Creep -> GameGlobal -> Memory.MemoryGlobal -> Effect Unit +manageCreeps hash game mem = do + let spawns = Game.spawns game + -- TODO: iterate over all spawns? + spawn1 = F.lookup "Spawn1" spawns + case spawn1 of + Nothing -> pure unit + Just s1 -> doSpawnCheck s1 (F.size hash) mem \ No newline at end of file diff --git a/src/Shimmy/Spawning.purs b/src/Shimmy/Spawning.purs new file mode 100644 index 0000000..8cc0026 --- /dev/null +++ b/src/Shimmy/Spawning.purs @@ -0,0 +1,74 @@ +module Shimmy.Spawning where + +import Prelude + +import Data.Either (Either(..), hush) +import Data.Int (decimal, fromString, toStringAs) +import Data.Maybe (Maybe(..), fromMaybe) +import Effect (Effect) +import Effect.Console (log) +import Foreign.Object as F +import Screeps.Const (pCarry, pMove, pWork) +import Screeps.Game as Game +import Screeps.Memory as Memory +import Screeps.Room (room, setRoomMem) +import Screeps.Spawn (spawnStoreEnergy) +import Screeps.Types (BodyPartType(..), Creep, GameGlobal, Role(..), Spawn) + +getLastId :: Memory.MemoryGlobal -> Effect (Maybe String) +getLastId memory = do + res <- Memory.get memory "last_id" + pure (join $ hush res) + +decodeId :: Maybe String -> Effect Int +decodeId str = do + case str of + Nothing -> pure 0 + Just int -> pure (fromMaybe 0 (fromString int)) + +encodeId :: Effect Int -> Effect String +encodeId int = do + int <#> (toStringAs decimal) + +incrementId :: Int -> Effect Int +incrementId int = pure $ int + 1 + +namify :: Effect Int -> Effect String +namify int = do + (pure "shimmy") <> encodeId int + +getCreepName :: Memory.MemoryGlobal -> Effect String +getCreepName memory = do + currentMin <- getLastId memory + nextMin <- decodeId currentMin >>= incrementId + creepName <- namify $ pure nextMin + (encodeId $ pure nextMin) >>= Memory.set memory "last_id" + pure creepName + +spawnCreep :: Spawn -> Array BodyPartType -> String -> Role -> Effect Unit +spawnCreep spawn parts name role = do + res <- Game.rawSpawnCreep spawn parts name role + case res of + Left err -> log $ show err + Right str -> log $ str <> " spawned" + +createIdleCreep :: Spawn -> Memory.MemoryGlobal -> Array BodyPartType -> Effect Unit +createIdleCreep spawn memory body = do + name <- getCreepName memory + spawnCreep spawn body name RoleIdle + +doSpawnCheck :: Spawn -> Int -> Memory.MemoryGlobal -> Effect Unit +doSpawnCheck spawn numCreeps memory = if availableEnergy > 250 && numCreeps < 3 then do + createIdleCreep spawn memory [pWork, pCarry, pMove, pMove] + else pure unit + where availableEnergy = spawnStoreEnergy spawn + +initSpawn :: F.Object Creep -> GameGlobal -> Memory.MemoryGlobal -> Effect Unit +initSpawn hash game mem = do + let spawns = Game.spawns game + spawn1 = F.lookup "Spawn1" spawns + case spawn1 of + Nothing -> pure unit + Just s1 -> do + let r = room s1 + setRoomMem r 0 0 \ No newline at end of file diff --git a/test/Main.purs b/test/Main.purs new file mode 100644 index 0000000..f91f98c --- /dev/null +++ b/test/Main.purs @@ -0,0 +1,11 @@ +module Test.Main where + +import Prelude + +import Effect (Effect) +import Effect.Class.Console (log) + +main :: Effect Unit +main = do + log "🍝" + log "You should add some tests."