swarm-game / swarm Goto Github PK
View Code? Open in Web Editor NEWResource gathering + programming game
License: Other
Resource gathering + programming game
License: Other
Right now, the base can build infinitely many robots with basic devices: a detonator, grabber, solar panel, and treads. However, it is a bit unrealistic that we can make infinitely many of these. Well, not that the game is realistic, but you know what I mean. It might be worth considering instead:
when i do stack run i get the error
Executable named git not found on path: [".","C:\Program Files\Common Files\Oracle\Java\javapath","C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common","C:\Windows\system32","C:\Windows","C:\Windows\System32\Wbem","C:\Windows\System32\WindowsPowerShell\v1.0\","C:\Windows\System32\OpenSSH\","C:\Program Files\dotnet\","C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\","C:\Users\user\AppData\Roaming\local\bin","C:\Users\user\AppData\Local\Microsoft\WindowsApps","F:\vs\Microsoft VS Code\bin","C:\Users\user\.dotnet\tools"]
Right now the ticks per second and ticks per frame are displayed centered at the top of the world view, and the ticks per frame value is updated every frame. I have in mind several ways this could be improved:
UIState
to count frames (we already have one to count ticks).frameTickHist
list, the frameTickHistSize
, and the rememberFrameTicks
function.TimeSpec
corresponding to the last time we updated the info in the UI.updateUI
function, check if the last time we updated the info in the UI was at least one second ago. If so, reset the time, compute ticks per frame and frames per second, and reset both counters to zero.f
?) to let the user toggle the display of TPF + FPS on and off.[Note, I no longer think this original issue description is a good idea, but leaving it here for context. Read all the way through the comments below to see how my thinking has changed.]
Right now a World
is specified by a WorldFun
, defined as
type WorldFun t e = Coords -> (t, Maybe e)
This is just a function that specifies a terrain value and possible entity for every cell. However, this has several limitations. For one thing, it is difficult to specify things that should be coherent across multiple cells (i.e. structures). For another, if we want the world to contain creatures that move around (implemented as system robots), there is no good way to specify when they should spawn.
The implementation of World
s already uses a notion of tiles for efficiency, and we can build on this to solve the limitations above. Instead of specifying a world cell by cell, we specify it tile by tile. That is, a WorldFun
will now be something like
type WorldFun t e = TileCoords -> (TerrainTile t, EntityTile e, [Robot])
which says that the world function takes as input the coordinates of a tile and generates an entire tile's worth of terrain and entities all at once, in addition to some robots which should spawn when this tile is loaded. When calling the function, it will build tiles first by filling in initial values based on a Coords -> (t, Maybe e)
function as before, but then has the opportunity to further modify them, e.g. by deciding where to draw in certain structures.
This is an idea to make the interpreter a bit more efficient, especially if there are lots of "dead" robots lying around.
robotMap
, add activeRobots :: [Text]
to the GameState
, representing the names of robots which are actively running code.addRobot
function should add a robot to both the robotMap
and the activeRobots
list.activeRobots
(instead of over every robot in the robotMap
), filter out any which are inactive, tick the rest, and rebuild the list.This way we only spend time iterating over the robots which will actually do some computation.
The grab
command should have type cmd string
and return the name of the thing that was grabbed. That way instead of e.g.
grab; ... ; give "base" "tree" -- give this thing that I already have to know is called a "tree"
you could write
thing <- grab; ... ; give "base" thing -- give whatever the heck it is I just grabbed
This makes things more discoverable. Note that we should also edit the tutorial to explain this.
I kind of threw the pretty-printer together without much regard for how the layout and indentation works. The prettyprinter
library has lots of nice tools for specifying this kind of thing; someone just needs to sit down and figure out how they work and how to apply them to the Swarm language to get good results.
This is very related to #7 , which will depend on this to get nice-looking save files that users can actually edit without tearing their hair out. Another semi-related issue is #644 .
At the moment, we use pretty-printing quite a bit for types, but we only pretty-print terms in certain error messages (e.g. when a command throws an exception).
I can already tell I am going to be annoyed having to push Tab an unknown number of times when I want to type something at the REPL. It would be nice to offer some shortcuts for jumping directly to a specific panel. For example, Ctrl-I for info panel, Ctrl-R for REPL, and Ctrl-W for world.
Right now, if you paste something into the REPL, it gets sent one keypress event at a time, which in particular means the parser and typechecker get re-run between every single key event. It's not too slow, but the lag is noticeable.
According to the brick user manual, however, the vty
library supports a "bracketed paste mode"---if the terminal does---which sends the entire paste as a ByteString
in a single paste event. We should definitely look into enabling this. I'm not yet sure whether we would need to update the REPL event handler; it passes most events on to the input form event handler (provided by brick
), so it depends on whether the input form event handler knows how to handle paste events. If it does, this might be as simple as just turning on vty
bracketed paste support.
It's easy to move the map around, but I couldn't tell what features were interesting or how to interact with them. The tutorial explains trees, which is fine, and I guessed the yellowish C was copper, but to do anything with copper I need a furnace, which needs stone. Where does that come from? I can't point at a tile on the map and ask "is this stone?", and there are multiple grey glyphs which plausibly could be.
Right now we store the world as a triple: a collection of immutable terrain tiles, a collection of immutable entity tiles, and a map specifying which cells have been updated from their original entity values. However, there is no good reason that we can't just use mutable arrays for entity tiles. Running the game already takes place in a monad; we just have to make sure that it supports the mutable array operations. This should hopefully make the implementation simpler and speed up the game as well.
A few pure operations (comparison on certain types, e.g. function types; division by zero; exponentiation by a negative number) typecheck but have undefined semantics. Making them not typecheck would require adding too much complexity to the type system; and we don't want them to throw exceptions since right now only commands can throw exceptions (giving pure expressions the ability to throw exceptions would make a lot of things more complicated too).
Instead, right now, these operations return a certain magic constant (False
in the case of comparison; 42
in the case of division and exponentiation). However, it would be more fun if they returned a random result of the appropriate type. This would entail figuring out how to thread the capability to generate randomness through the interpreter (right now it is done using IO
for the random
command but I'd like to get rid of that if we can).
It would be nice to be able to annotate arbitrary expressions with type annotations, as in (3 : int) + 5
. It's not clear how necessary this is at the moment --- type inference, plus giving type annotations to top-level definitions, usually seems to be able to do the job. But as we add more polymorphic things it may become increasingly helpful. And in any event it can be helpful as a form of documentation.
Adding this would require
check
function.While the base is actively running a computation, the [Enter] execute
hint in the key menu should be replaced by [^c] cancel
. This feature already exists but it is not advertised anywhere.
Once we implement #15 , I think it would be nice to have a simple tutorial that advances through a series of simple challenges, guiding the user through doing a few of the kinds of things they will need to do at the start of the game (build some robots, make some definitions, craft some devices, etc.)
Values generated by the random
command should actually be deterministically based on the world seed. We could have some kind of PRNG that gets stored in the GameState
. Right now the random values are just generated in the IO
monad.
At the moment, Swarm is susceptible to the "spiral of death" described at https://gafferongames.com/post/fix_your_timestep/ : when the amount of computation we have to do for a frame takes longer than the amount of time allotted for the frame, it starts getting further and further behind. This could in theory be triggered either by a lot of robots doing a lot of computation, or by the user pushing the ticks/second rate too high. If this happens, each frame will take longer than the previous frame and the game will essentially grind to a halt as it tries futilely to catch up but only gets further and further behind.
There is a simple way to avoid this, which is simply to cap the maximum number of ticks per frame (based on my own experience so far, a cap of around 25 seems reasonable). When it hits the cap, the game will slow down: it will essentially be running at a slower ticks/second rate than requested. Perhaps we could signal this by e.g. drawing the ticks per second rate in red, or something like that.
Describe the bug
swarm
runs at 100% CPU
To Reproduce
Run swarm
. In another terminal, run top
:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
388509 f 20 0 1024.3g 32808 14516 R 100.0 1.1 0:06.59 swarm
(alternative: listen to your PC’s fan)
Expected behavior
Use less CPU cycles.
Screenshots
N/A
Additional context
N/A
Entities which have the growable
property, when harvested via the grab
command, spawn a system robot representing a "seed", which takes a while to grow through two phases and then replaces itself with another copy of the originally harvested entity. However, the length of time that it takes to grow is hard-coded into the program for the seed robot. This should be configurable, by specifying some data in entities.yaml
.
There are a lot more details yet to work out here; just putting this issue here as a placeholder for now.
There are quite a few capabilities that are missing; see the comments in Swarm.Language.Capability. This will require some creative thinking and careful planning and testing.
Here is a list of commands and related issues (TODO):
Here is the list of capabilities that are missing devices:
Here is a list of devices that provide a capability but are missing a recipe (see also #361):
In addition, the following commands require god capability and are currently only intended for scenario development and not available to players (except for creative mode):
Since #373 the exception users will see if there are no devices to provide required capability looks like this:
Missing the random capability for:
'random'
but no device yet provides it. See
https://github.com/swarm-game/swarm/issues/26
Restricted commands give different message:
Thee shalt not utter such blasphemy:
'as'
If't be true thee wanteth to playeth god, then tryeth Creative game.
Right now, a description of the highlighted inventory entity is shown in the bottom portion of the info panel whenever the info panel is focused. However, this disappears as soon as you switch away from the info panel. This feels annoying, though, because an item description might contain something you want to refer to while typing a command at the REPL: some examples of a language feature, for example, or a list of recipes.
The thing that replaces the entity description when not focused on the info panel is the global message log. Perhaps the answer is to make message logs per-robot, and to associate them with a logger device: see #39 . Then the bottom part of the info panel will always show info about the currently selected inventory item, and if you want to see the message log, you can just select that device in your inventory.
There is a widget which can be shown floating on top of the rest of the UI. Right now it is only ever used for showing language processing errors (e.g. parsing or type checking errors). However, there are probably other reasons we might want a pop-up dialog. At the very least we should change the name from uiError
; probably there are other things that should be generalized as well, but I'm not sure off the top of my head.
There ought to be a way to retrieve all the inventory and devices from a "dead" robot. I'm imagining something like salvage : string -> cmd ()
, where salvage x
will try to salvage a robot named x
. If successful, all of x
's inventory and installed devices go into the inventory of the robot that executed salvage
, and x
itself disappears.
Some issues to work out:
salvage
command? I'm thinking probably you have to be in the very same cell.salvage
, but it's still worth thinking about them together.salvage
capability. What device should confer this capability, and what should its recipe be? How difficult should it be to construct?We should add a new kind of device (a logger
, recipe: 1 log) which allows logging messages via a log
command (i.e. there will be a log
capability, provided by a logger
, and required to execute the log
command). This will also be the mechanism by which uncaught exceptions are reported; on any robot without a logger, such uncaught exceptions will just be silently discarded. See this comment in Swarm.Game.Step
.
This will require adding a message queue field to the Robot
record type. We should also get rid of the global message queue in the GameState
.
We'll have to rethink what the say
command does---perhaps it should broadcast a message that will be added to the log of nearby robots?
Implement a Challenge mode where users try to complete preset challenges. A challenge consists of
cmd bool
) which runs to completion on every tick to see whether the challenge has been successfully completed.It should be possible to describe challenges in a .yaml
file of some to-be-determined format.
Right now, in Swarm.Game.WorldGen
, some seed values are simply hardcoded. Instead, especially once we implement #4 , when the user starts a new game they should be able to specify a seed value or have one randomly generated. Then the seed value should in turn deterministically generate a unique world.
It should be possible for a user to learn the type of an expression without executing it. There are a couple ways I could imagine this working.
:type
command, so the user can enter something like :type foo
at the prompt, hit Enter, and have it print out the type, like GHCi does. This is maybe the simplest to implement in some ways, although it does mean adding a special parser for things entered at the REPL to see whether they start with a colon command or are just an expression. This parser would be used not just when the user hits Enter but also every time the REPL updates to check it for validity.:type
command, we could simply display the type in some way any time the current input is valid. The hardest part here would just be figuring out how to display this information. For example, it could be shown in grey with a colon just beyond the input, or it could be shown on the line below.def forever = \c : cmd (). c ; forever c end
produces the error Unbound variable forever
. The problem really is that currently, definitions can only be recursive if they include a top-level type signature, like
def forever : cmd () -> cmd () = \c. c ; forever c end
We should either (1) explicitly check for this scenario and give a better error message suggesting how to fix it, or (2) modify type inference so that it can successfully infer the types of unannotated recursive definitions. (After all, Haskell can do it!)
It seems to make the most sense within the logic of the game that your base has only a limited view of the surroundings, and the only way to see anything farther away is to send a robot there which can broadcast its view back to you.
As a start, we should simply disable the ability to scroll the world view at all when in Classic mode (and also remove the related hint in the key menu display below the world).
We often have cause to write down Swarm types and terms in the Haskell source, but right now this is very tedious and hard to read, due to the need to encode them as ASTs. It would be really nice to create some quasiquoters so that we could write them in Swarm syntax but still have them checked at compile time.
Right now there is very limited and non-renewable copper available on the surface, but it's going to be an important ingredient in many recipes. The description for copper says you can get more by drilling, but that needs to be implemented. My ideas are:
drill
command, with a corresponding capability provided by a drill entity. At first drill
won't take any parameters, though perhaps later it will take a direction as an argument (to allow for drilling through boulders and mountains etc.)drill
on a copper seam cell has a small percentage chance of adding copper to the robot's inventory.NOTE: this issue was originally about being able to zoom in and out, but perhaps that is too complicated and what we really want is just the ability to see some sort of zoomed-out world map, perhaps in a toggleable dialog or panel. See discussion below.
It would be cool to be able to zoom in and out on the world view. There are a lot of details to work out here, but I am imagining something like the following:
Tried the game out today, and I couldn't do anything with copper until I read the source, because recipes do not fit in the recipe pane, even if I make my terminal much wider than I usually would. Recipes like the one for copper wire are too long to fit into the pane, and are just clipped at the end, so I knew I could craft "co[something]", but had no way to find out more.
This issue used to be about adding an antenna
entity to enable view
, but see comments below for some reasons why I no longer think we should do that.
I'm thinking there can be an "Antenna" entity.
broadcast
capability, with a corresponding broadcast
command.base
) which have executed broadcast
can be viewed with the view
command.Describe the bug
If you have typed some input at the REPL but not yet hit Enter, and then scroll through the REPL history, your input will be lost.
To Reproduce
1
and hit Enter
).Enter
.Expected behavior
The partially entered input should be restored when you scroll back to the end of the history. Instead, it is blank.
I'm imagining a more general version that can display labels in any and all of six places (top/bottom left/center/right). Take a look at the way the brick
border functions are implemented for inspiration: https://hackage.haskell.org/package/brick-0.64.1/docs/src/Brick.Widgets.Border.html#borderWithLabel
That is, a way to display the current state of the CEK machine for the focused robot. This would require first overhauling CEK machine pretty-printing. I am imagining showing the continuation stack as nested frames rather than a sequence of frames. For example given the program let x = 3 + 2 in x * 4
, when we are currently focused on evaluating the 3
, we could imagine something like
[let x = [[3] + 2] in x * 4]
or maybe even without all the brackets except the ones around the 3. This would probably require some creativity in certain cases but I think it could be done in a nice, compact way.
The second part of this would be devising ways both (1) for the user to possibly choose whether they want to see this, and (2) figuring out a good place for it in the UI.
It should be possible to save the current state of your game, and then later to load from a saved game. There is nothing theoretically difficult about this, but it will take a good deal of engineering. Off the top of my head, a save would need to include.
old_entities.yaml
file) so that we can load them.GameState
and/or UIState
.For loading entities and recipes, we use .yaml
files, so that they can be easily human-editable. However, for saving the entire game state we definitely don't want to do that. Instead we should use some kind of binary serialization framework so save files will be as compact as possible. Since we can already load scenarios from .yaml
files, it makes sense at this point to just double down on that and make save files use the same format.
Once we enable this feature, we'll have to be very careful about versioning things such as entities and recipes, world generation, etc., and keep around old versions of things (as much as is reasonable) so that we can correctly load save files produced by older versions of the game.
Note, a related issue is #7 .
Right now, water is a terrain type, with an entity for waves so that water can have a checkerboard of waves. But robots can walk right across it, and there's no way for robots to obtain any water. This should be handled in a different way.
Here are my current ideas:
drown
is a new property that means any robot walking on it will drown (i.e. instantly disappear).boat
device (constructible out of boards?) that conveys a float
capability. Robots with the float
capability do not die when walking on top of an entity with the drown
property. The logic about drown
and float
will need to be added to the interpretation of the Move
command in Swarm.Game.Step
.Currently, when displaying the message queue, very simple logic is used to decide how to display the messages and how many to display. This often leads to messages being unreadable, especially in a smaller terminal. Also, we choose a static number of messages to display based on the height of the panel, but this is wrong if any of the messages are more than one line high; this leads to messages being cut off the bottom of the panel.
txtWrap
to display the actual messages, so they wrap to whatever width the info panel happens to be.brick
Viewport
. As a bonus, we should provide some sort of mechanism to allow the user to scroll it. Note, this kind of scrolling ability will also be needed for entity descriptions, which can be cut off at the bottom if they are too long and/or the window is too small.Somehow I added product types but haven't gotten around to adding sum types yet!
Right now we don't have any tests at all, which is kind of embarrassing. I don't even know what a good test suite would look like. Probably we should have several. For example, on one level there are probably many individual functions we could test with QuickCheck and so on. We can also test things at the level of the simulation: e.g. fuzz testing to make sure the game never crashes, and so on. We could also construct some unit tests for each programming language constant or feature, to make sure that programs using those features do what is expected. This would be very valuable as a regression test suite, to make sure that future updates to the language don't break anything.
program : string -> cmd () -> cmd ()
is like build
, except it operates on an existing robot in the same cell instead of creating a new robot. The robot being programmed must (1) be idle and (2) have the necessary capabilities to execute the program.
What entity should provide this ability?
I think we ought to get rid of the run
command and just make some kind of REPL commands for saving and loading the current set of definitions. For example,
> def x = 3 end
> x + 2
5
> def m2 = move; move end
> :save myDefs.sw
might create a file myDefs.sw
which contains the code defining x
and m2
. Similarly :load myDefs.sw
might load the definitions (replacing any currently in scope --- perhaps with some kind of warning and opportunity to cancel).
This seems rather critical to actual gameplay since people will develop various useful definitions and want to edit them, reuse them in later sessions, and so on.
I don't think this should be too hard once #8 (and any other pretty printing bugs) is addressed. To save, just get the robotEnv
from the base
robot, and pretty-print the definitions it contains (possibly adding some type annotations from the robotCtx
). It may be necessary to add something to keep track of the order of the definitions (something the robotEnv
does not care about) so that we can pretty-print them to a file in the same order the user entered them.
Right now the pretty-printer for Value
s is even more hacked together than the rest; it doesn't even use the same framework. It ought to be rewritten in a more principled way.
Right now, the only way for a robot to wait for a certain amount of time is to execute a program like repeat 500 wait
, but this means the robot is doing a bunch of computation steps every tick (evaluating the recursive repeat
command, subtracting one from a number, checking whether it is zero...). Instead, there should be a way for a robot to register its intent to sleep for a certain amount of time, and have the game engine wake it up later. This will save a lot of work --- for example, I have noticed that the game slows down noticeably when harvesting a large forest, generating a large number of system seed robots which are all busily waiting for a long time to grow.
The idea is as follows. Note that #19 needs to be implemented first.
wait
command to take an int
argument, denoting the duration of waiting.wait
command requires no capabilities, but perhaps with this change it should. I propose adding a time
capability, which can be provided by a new clock
entity (recipe: some gears + some springs (in turn made from copper wire)?).
getTime : cmd int
, also requiring the time
capability.GameState
which tracks the number of ticks since the game started.GameState
, keyed by the tick at which the robot should wake up.wait
command, remove it from the activeRobots
queue and place it in the priority queue (after calculating the time at which it should be woken).When the game initially starts there should be a menu screen giving you options to start a new game in Classic or Creative modes, and eventually offer other choices such as a tutorial, challenge moves, loading a saved game, etc.
Infix operators do not print correctly at the moment; they print as if they were prefix operations, like + 2 3
.
Fixing this will be critical to being able to round-trip pretty-printing and parsing, which in turn is needed to be able to support #7 .
i am trying to use the command stack run but i get the error:
In the dependencies for brick-0.64:
unix needed, but the stack configuration has no specified version (latest matching version is 2.7.2.2)
needed due to swarm-0.1.0.0 -> brick-0.64
In the dependencies for vty-5.33:
unix needed, but the stack configuration has no specified version (latest matching version is 2.7.2.2)
needed due to swarm-0.1.0.0 -> vty-5.33
how can i fix this
The current game mode (Classic, Creative, etc.) probably ought to be displayed somewhere in the UI. Not sure where the best place would be... somewhere in the world border, perhaps? (Related: #37 ) Or on the far right of the strip showing available key commands?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.