user3888177
user3888177

Reputation: 115

Clojure: Every frame, read user input if available. input is passed into loop, can be either lazy-seq of (reapeatedly (readline)) or predefined list

I'm stuck on figuring out how to implement this.

The concept is that I want:

  1. to be able to let the game update whether or not the player has entered input, but use the input if it's available
  2. be able to seamlessly swap out the user's input with a predefined sequence for testing purposes.

This is the broken implementation I currently have:

(defn game
    "Runs the simplified version of the main game"
    [world user-input-machine]

    (let [input [first (deref user-input-machine 10 nil)]]
        (if (not= input "QUIT")
            (do (println input) ; do game logic stuff
                    (game world (rest (deref user-input-machine)))) ;repeat
            world)))

The idea being to pass in something like

(future (repeatedly(readline)))

or

(future (["hello", "world", "QUIT"]))

As input. The implementation is wrong for a number of reasons. I'm just getting started with clojure, and this is my first attempt at using futures/delays/promises etc. Can anyone help me out?

I've come across a few related questions that haven't quite answered what im looking for (I'm not even sure how to articulate the query):

Promises vs Futures

Multiple Threads in clojure

Upvotes: 1

Views: 111

Answers (1)

Valentin Waeselynck
Valentin Waeselynck

Reputation: 6061

From what I understand, you are trying to build a machine which listens to a stream of user input events, and updates the 'world' and trigger side-effects for each events.

Based on this assumption, I see several problems here:

  • there are several coordination mechanisms you can choose from to implement the idea of 'listening to a stream of events' (lazy sequences, event streams, core.async channels, etc.) The thing is, you are using both lazy sequences and futures in this case; I would suggest you pick only one, e.g using only a lazy sequence, without futures.
  • you are using recursion for you loop. Because the JVM has no tail call optimizations, this will eventually blow your stack (you'll run out of memory), I recommend you use loop/recur instead.

I would personally go for core.async or manifold, which are more suited to events streams than futures/promises. If your displaying model supports it, I would put the displayed information in an agent or an atom, which would be polled every frame to refresh the display, and updated for each user input event. It's hard to give you more precise directions without more details on how your game works.

Finally, if you have never done this kind of game logic before, I would suggest you figure out how to do it in a language you know, then do it in Clojure :) learning Clojure and asynchronous control flow at the same time may be a bit too much IMHO.

Upvotes: 1

Related Questions