Cannot read property 'kids' of undefined - or how to break a circular dependency of signals in Elm? - elm

While elm-make succeeds, I get the following error in the browser:
Cannot read property 'kids' of undefined
I assume it's because I have a circular dependency of signals:
model -> clicks -> model
Here is the relevant code:
model : Signal Model
model =
Signal.foldp update initialModel clicks
clicks : Signal Action
clicks =
let
clickPosition = Mouse.position
|> Signal.sampleOn Mouse.clicks
tuplesSignal = Signal.map3 (,,) clickPosition Window.dimensions model
in
...
It feels like model is implemented as a common practice in Elm, so I should challenge the clicks -> model dependency.
Here is some context:
I'm building a sliding puzzle game using canvas:
When user clicks a tile that can move, it should move. Otherwise, the click should be ignored.
clicks will produce the following actions: Left, Right, Up, Down
For example, if user clicks on tiles 12, 11, 8, 15 (in this order), clicks should be: Down -> Right -> Up
The problem is, that in order to calculate which tile was clicked, I need to know the board dimensions (e.g. 4 rows and 4 columns in the picture above). But, board dimensions are stored in the model (imagine user interface that allows users to change board dimensions).
How do I get out of this circular dependency?

In this case I think you should go more low-level in what you call an input, and accept click positions as inputs. Then you can compose an update function in your Signal.foldp out of two others:
The first turns the clicks and model into a Maybe Direction (assuming the Left, Right, Up, Down are constructors of type Direction)
The second function that takes a Direction value and the model to calculate the new model. You can use Maybe.map and Maybe.withDefault to handle the Maybe part of the result of the first function.
Separating these two parts, even though you produce and consume Direction immediately, makes your system more self-documenting and shows the conceptual split between the raw input and the restricted "actual" inputs.
P.S. There are conceivable extensions to the Elm language that would allow you to more easily write this input preprocessing in signal-land. But such extensions would make the signal part of the language so much more powerful that it's unclear if it would make "the right way" to structure programs harder to discover.

Related

Player doesn't spawn correctly in procedural generated map

I've followed "Procedural Generation in Godot: Dungeon Generation" by KidsCanCode #https://www.youtube.com/watch?v=o3fwlk1NI-w and find myself unable to debug the current problem.
This specific commit has the code, but I'll try to explain in more detail bellow.
My main scene has a Camera2D node, a generic Node2D calles Rooms and a TileMap, everything is empty.
When the script starts, it runs a
func make_room(_pos, _size):
position = _pos
size = _size
var s = RectangleShape2D.new()
s.custom_solver_bias = 0.5
s.extents = size
$CollisionShape2D.shape = s
A few times and it fills $Rooms using .add_child(r) where r is a instance of the node that has the make_room() function. It will then iterate over $Rooms.get_children() a few times to create a AStar node to link all the rooms:
The magic comes when make_map() is called after afterwards, it fills the map with non-walkable blocks and then it carves the empty spaces, which works fine too:
There is a find_start_room() that is called to find the initial room, it also sets a global variable to the Main script start_room, which is used to write 'Start' on the map using draw_string(font, start_room.position - Vector2(125,0),"start",Color(3,4,8))
When I hit 'esc' it runs this simple code to instance the player:
player = Player.instance()
add_child(player)
player.position = start_room.position + Vector2(start_room.size.x/2, start_room.size.y/2)
play_mode = true
The problem comes when spawning the player. I tried doing some 'blind' fixing, such as adding or subtracting a Vector2(start_room.size.x/2, start_room.size.y/2) to player.position to see if I could make it fall within the room, to no avail.
Turning to the debugger didn't help, as the positions expressed by the variable inspectors don't seem to mean anything.
I tried implementing a simple 'mouse click print location':
print("Mouse Click/Unclick at: ", event.position)
print("Node thing",get_node("/root/Main/TileMap").world_to_map(event.position))
And also a 'start_room' print location:
print(get_node("/root/Main/TileMap").world_to_map(start_room.position))
And a when player moves print location, written directly into the Character script:
print(get_node("/root/Main/TileMap").world_to_map(self.position))
Getting results like the ones bellow:
Mouse Click/Unclick at: (518, 293)
Node thing(16, 9)
(-142, 0)
(-147, -3)
So, the player doesn't spawn on the same position as the start_room and the mouse position information is not the same as anything else.
Why is the player now spawning correctly? How can I debug this situation?
EDIT1: User Theraot mentioned about how the RigidBody2D is doing some weird collisions, and from what I understood, changing their collision behavior should fix the whole thing.
There's a section on the code that -after generating the random rooms- it removes some of the rooms like this:
for room in $Rooms.get_children():
if randf() < cull:
room.queue_free()
else:
room.mode = RigidBody2D.MODE_STATIC
room_positions.append(Vector3(room.position.x, room.position.y, 0))
From what I understand, if the room is randomly selected it will be deleted using queue_free() OR it will be appended to a room_positions for further processing. This means if I shift all the rooms to a different collision layer, the player/character instance would be alone with the TileMap on the same collision layer.
So I just added a simple room.collision_layer = 3 changing this section of the code to
for room in $Rooms.get_children():
if randf() < cull:
room.queue_free()
else:
room.mode = RigidBody2D.MODE_STATIC
room.collision_layer = 3
room_positions.append(Vector3(room.position.x, room.position.y, 0))
It doesn't seem to have changed anything, the player still spawns outside the room.
Do you see the rooms spread outwards?
You didn't write code to move the rooms. Sure, the code gives them a random position. But even if you set their position to Vector2.ZERO they move outwards, avoiding overlaps.
Why? Because these rooms are RigidBody2D, and they do push other physics objects. Such as other rooms or the player character.
That's the problem: These rooms are RigidBody2D, and you put your KinematicBody2D player character on top of one of them. The RigidBody2D pushes it out.
The tutorial you followed is exploiting this behavior of RigidBody2Ds to spread the rooms. However you don't need these RigidBody2D after you are done populating your TileMap.
Instead, you can store the start position in a variable for later placing the player character (you don't need offsets - by the way - the position of the room is the center of the room), and then remove the RigidBody2Ds. If you want to keep the code that writes the text, you would also have to modify it, so it does not fail when the room no longer exists.
Alternatively, you can edit their collision layer and mask so they don't collide with the player character (or anything for that matter, but why would you want these RigidBody2Ds that collide with nothing?).
Addendum post edit: Collision layers and mask don't work as you expect.
First of all, the collision layer and mask are flags. The values of the layers are powers of two (1, 2, 4, 8...). So, when you set it to 3, it is the layer 1 plus the layer 2. So it still collides with a collision mask of 1.
And second, even if you changed the collision layer of the rooms to 2 (so it does not match the collision mask of 1 that the player character has). The player character still has a layer 1 which match the collision mask of the rooms.
See also the proposal Make physics layers and masks logic simple and consistent.
Thus, you would need to change the layer and mask. Both. in such way that they don't collide. For example, you can set layer and mask to 0 (which disable all collisions). The algorithm that populates the TileMap does not use the layer and mask.

How to add a new syntax element in HM (HEVC test Model)

I've been working on the HM reference software for a while, to improve something in the intra prediction part. Now a new intra prediction algorithm is added to the code and I let the encoder choose between my algorithm and the default algorithm of HM (according to the RDCost of course).
What I need now, is to signal a flag for each PU, so that the decoder will be able to perform the same algorithm as the encoder decides in the rate distortion loop.
I want to know what exactly should I do to properly add this one bit flag to the stream, without breaking anything in the code.
Assuming that I want to use a CABAC context model to keep the track of my flag's statistics, what else should I do:
adding a new context model like ContextModel3DBuffer m_cCUIntraAlgorithmSCModel to the TEncSbac.h file.
properly initializing the model (both at encoder and decoder side) by looking at how the HM initialezes other context models.
calling the function m_pcBinIf->encodeBin(myFlag, cCUIntraAlgorithmSCModel) and m_pcTDecBinIfdecodeBin(myFlag, cCUIntraAlgorithmSCModel) at the encoder side and decoder side, respectively.
I take these three steps but apparently it breaks something.
PS: Even an equiprobable signaling (i.e. without using CABAC contexts) will be useful. I just want to send this flag peacefully!
Thanks in advance.
I could solve this problem finally. It was a bug in the CABAC context initialization.
But I want to share this experience as many people may want to do the same thing.
The three steps that I explained are essentially necessary to add a new syntax element, but one might be very careful with the followings:
In the beginning, you need to decide either you want to use a separate context model for your syntax element? Or you want to use an existing one? In case of CABAC separation, you should define a ContextModel3DBuffer and the best way to do that is: finding a similar syntax element in the code; then duplicating its ``ContextModel3DBuffer'' definition and ALL of its occurences in the code. This way assures that you are considering everything.
Encoding of each syntax elements happens in two different places: first, in the RDO loop to make a "decision", and second, during the actual encoding phase and when the decisions are being encoded (e.g. encodeCtu function).
The order of encoding/decoding syntaxt elements should be the same at the encoder/decoder sides. For example if your new syntax element is encoded after splitFlag and before predMode at the encoder side, you should decode it exactly between splitFlag and predMode at the decoder side.
The context model is implemented as a 3D matrix in order to let track the statistics of syntaxt elements separately for different block sizes, componenets etc. This means that when you want to call the function encodeBin, you may make sure that a correct index is being used. I've made stupid mistakes in this part!
Apart from the above remarks, I found a the function getState very useful for debugging. This function returns the state of your CABAC context model in an arbitrary place of the code when you have access to it. It is very useful to compare the state at the same place of the encoder and the decoder when you have a mismatch. For example, it happens a lot that you encode a 1 but you decode a 0. In this case, you need to check the state of your CABAC context before encoding and decoding. They should be the same. If they are not the same, track back the error to find the first place of mismatch.
I hope it was helpful.

Elm Game of life program becomes unresponsive - is there a way to fail gracefully?

I have a basic implementation of Conway's game of life written in elm running at uminokirin.com.
The source is visible here.
The program let users adjust the size of the toroïdal grid, click on cells to change their status, and randomize the world. It works well for small values (less than 50) on my computer.
However when attempting to use the randomize grid function on bigger grids (the threshold value doesn't seem to be always the same), the program becomes unresponsive without any warning and the only way to recover is to reload the app.
There is zero optimization in the GOL algorithm and using a single svg rectangle for every cell is probably horribly inefficient, but it sill doesn't explain why the program behaves in this way instead of say, slowing down.
Is this the elm runtime giving up? Or some kind of browser safeguard?
More importantly is there a way to prevent this behavior other than arbitrarily capping the maximum size of the grid?
The behavior you are observing is due to a Javascript stack overflow. After pressing the "randomize" button, in the browser console you can see the message "Uncaught RangeError: Maximum call stack size exceeded"
This happens because the randomize function allocates several large temporary variables. In particular, the shuffle function (which is called from the randomize function) appears to allocate two temporary lists that each have one element for every cell in the life grid. Elm may be smart about releasing these on a timely basis but this appears to push it too far.
To fix this you can use a simpler randomize function. The version shown below uses Elm Generators to generate a single list of Dead/Alive values and then initializes the randomized array from that list.
randomize2 : Array Cell -> Int -> Int -> Int -> Array Cell
randomize2 grid gs sd n =
let floatGen = Random.float 0.0 1.0
lifeGen = Random.map (\b -> if (b < toFloat n/100) then Alive else Dead) floatGen
listGen = Random.list (gs*gs) lifeGen
in fst (Random.step listGen (initialSeed sd)) |> fromList
Using this randomize function I was able to resize the grid up to 600x600 and randomize successfully. At that point I stopped testing.

Detect object at mouse click location

I have a large number of different image stimuli presented in various locations on screen.
When the participant clicks on a stimulus, I need the name of that stimulus item available for use in the rest of the script.
For example, you can achieve this in E-Prime with the SlideState.HitTest(x, y) method, where x and y are mouse coordinates.
The only similar thing I've been able to see in Psychopy is the mouse.isPressedIn(shape) method. However because you must supply a specific object as an argument, it seems you would need an if clause for each of the stimuli, which seems messy (especially for larger numbers of items)
Is there a better way of doing this? I'm still learning so I might be missing something.
Thanks!
No, I think not. However, if you just add all objects to a list and loop over them, the code will be neat enough.
# List of (pointers to) stimulus objects
shapes = [shape1, shape2, shape3, shape4, shape5]
# Loop over them and check if mouse is pressed on each one of them
for shape in shapes:
if mouse.isPressedIn(shape):
# Set this variable to point to the latest pressed shape
pressed_shape = shape
# Now you can do stuff with this object
pressed_shape.fillColor = 'red'
pressed_shape.draw()
print pressed_shape.name
Note that if the mouse clicks at a location where there are two objects, pressed_shape is the latest in the list for this solution.

Create a Signal from a List

Is it possible to create a Signal from a List? Essentially what I want is something with the signature List a -> Signal a. I know that a Signal represents a time-varying value and so something like this doesn't actually make any sense (i.e. I can't think of a reason to use it in production code).
I could see applications of it for testing though. For example, imagine some function which depended on the past values of a Signal (via foldp for instance) and you wanted to make assertions about the state of the system given the signal had received values x, y, and z.
Note that there wouldn't have to be anything special about the Signal denoting that it only would ever receive a fixed number of values. I'm thinking of it more like: in production you have a Signal of mouse clicks, and you want to test that from a given starting position, after a given set of clicks, the system should be in some other known state. I know you could simulate this by calling the function a fixed number of times and feeding the results back in with new values, I'm just wondering if it is possible.
I guess it's possible. You use a time-based signal, and map the values from the list over it:
import Time
import Graphics.Element exposing (show)
list = [1..10]
signalFromList : List a -> Signal a
signalFromList list =
let
(Just h) =
List.head list
time =
Time.every Time.second
maybeFlatMap =
flip Maybe.andThen
lists =
Signal.foldp (always <| maybeFlatMap List.tail) (Just list) time
in
Signal.filterMap (maybeFlatMap List.head) h lists
main = Signal.map show <| signalFromList list
However!
It shouldn't be hard to do testing without signals. If you have a foldp somewhere, in a test you can use List.foldl over a list [x,y,z] instead. That should give you the ability to look at the state of your program after inputs x, y, z.
I don't think there is any way it can be done synchronously in pure elm (Apanatshka's answer illustrates well how to set up a sequence of events across time and why it's a bad idea). If we look at how most Signals are defined, we'll see they all head down into a native package at some point.
The question then becomes: can we do this natively?
f : List a -> Signal a
I often think of (Signal a) as 'an a that changes over time'. Here we provide a List of as, and want the function to make it change over time for us.
Before we go any further, I recommend a quick look at Native/Signal.js: https://github.com/elm-lang/core/blob/master/src/Native/Signal.js
Let's say we get down to native land with our List of as. We want something a bit like Signal.constant, but with some extra behaviour that 'sends' each a afterwards. When can we do the sending, though? I am guessing we can't do it during the signal construction function, as we're still building the signal graph. This leaves us a couple of other options:
something heinous with setTimeout, scheduling the sending of each 'a' at an appropriate point in the future
engineering a hook into the elm runtime so that we can run an arbitrary callback at the point when the signal graph is fully constructed
To me at least, the former sounds error prone, and I hope the latter doesn't exist (and never does)!
For testing, your suggestion of using a List fold to mimic the behaviour of foldp would be the way I would go.