0

So, I'm trying to program an AI for the game Screeps, whose docs are found here.

I'm trying to write my AI in OCaml, which I'm then compiling to Javascript via Bucklescript, whose docs are found here.

Anywho, within Screeps' API is the method Game.spawns.SPAWN_NAME.createCreep, in which SPAWN_NAME corresponds to the name of the 'spawn' object in question. It takes in a string array corresponding to the various body parts of the 'Creep' it is helping to spawn, and given a correct function call (with enough energy reserves), your Creep will spawn in game.

An example call (in JS) would be Game.spawns['Spawn1'].createCreep(["body","move"]);

I already have code which gives me a string array of all the spawns in OCaml. That code is:

let spawns : string array = [%bs.raw{|Object.keys(Game.spawns)|}]
let spawnsArray : string array = spawns

Lets say that I have one spawn called Spawn1, and that I also have a string array for the body composition in OCaml:

let spawnName : string = "Spawn1" 
let body : string array = [|"body","move|]

I then iterate over each string within that array, using a for loop like the one below:

for i=0 to Array.length spawns - 1 do
  // I WANT TO CALL SOMETHING ANALOGOUS TO MY FUNCTION HERE
done

I just can't, for the life of me, figure out how to format the Bucklescript bindings so that I can dynamically call the createCreep function with body : string array and spawnName : string. Any help would be amazing. I know there are the bs.get and bs.set methods described briefly within the Bucklescript docs, but I don't know how to use them.

Thanks in advance for the help.


EDIT:

I managed to 'work around' the issue by writing my own 'interfacing' functions in a Javascript module which I can then call via the bs.module Bucklescript binding.

IE I wrote a function

function spawnCreepHelper(spawnName, body) {
  Game.spawns[spawnName].createCreep(body);
}

which I'm then able to call via

external spawnCreepHelper : string -> string array -> unit = "" 
[@@bs.module "./supplemental", "Supplement"]

Seems kind of hacked together to me, so if anyone has another way of approaching it that doesn't involve rewriting their API myself, please let me know.

glennsl
  • 28,186
  • 12
  • 57
  • 75
lacoperon
  • 3
  • 6

1 Answers1

0

You probably want the bs.get_index attribute:

type spawn
type spawns
external spawns : spawns = "" [@@bs.val] [@@bs.scope "Game"]
external getSpawn : spawns -> string -> spawn = "" [@@bs.get_index]
external createCreep : spawn -> string array -> unit = "" [@@bs.send]

let _ =
  let spawn = getSpawn spawns "spawn1" in
  createCreep spawn [|"body"; "move"|]

compiles to

var spawn = Game.spawns["spawn1"];

spawn.createCreep(/* array */[
      "body",
      "move"
    ]);

You can then get the keys by providing your own typed external to Object.keys:

 external keys : spawns -> string array = "" [@@bs.val] [@@bs.scope "Object"]

 let _ =
   spawns |> keys
          |> Js.Array.forEach Js.log

which will compile to

Object.keys(Game.spawns).forEach((function (prim) {
        console.log(prim);
        return /* () */0;
      }));   

Alternatively, you could type spawns as a spawn Js.Dict and use the functions already provided by BuckleScript to access and manipulate it: https://bucklescript.github.io/bucklescript/api/Js.Dict.html

glennsl
  • 28,186
  • 12
  • 57
  • 75