Ludii Forum
The behavior of the nondecision operator (forEach) - Printable Version

+- Ludii Forum (https://ludii.games/forums)
+-- Forum: Questions (https://ludii.games/forums/forumdisplay.php?fid=13)
+--- Forum: About the Ludii Grammar (https://ludii.games/forums/forumdisplay.php?fid=15)
+--- Thread: The behavior of the nondecision operator (forEach) (/showthread.php?tid=193)

Pages: 1 2


The behavior of the nondecision operator (forEach) - Michael - 09-26-2020

I have tried to use (forEach Site) to work around the lack of a ludeme that iterates over groups, but it seems my workaround relies on a misunderstanding of how it works.

The point is to implement a kind of triangular scoring where a group consists of 1-stacks and 2-stacks and its value is based on how many 2-stacks it contains (1p for the first, 2p for the second, and so on).

This is my code:
Code:
(forEach Site
    (forEach
        (sites Occupied by:P1)
        if:(= 2 (size Stack at:(site)))
    )
    (if
        (!= 1 (state at:(site)))
            (and
                (forEach Site
                    (sites Group at:(site) )
                    (set State at:(site) 1)
                )
                (addScore P1
                    (/ (* "n1" (+ 1 "n1") ) 2)
                )
            )
    )
)
And this is the meaning of "n1":
Code:
(count Sites
    in:(intersection
        (forEach
            (sites Occupied by:P1)
            if:(= 2 (size Stack at:(site)))
        )
        (sites Group at:(site))    
    )
)

This is how I thought it worked:
(Choose a white 2-stack whose state is not 1 and do the following: Change the state of its entire group to 1 and add the value of its group to the score of P1.) <== Repeat this until there are no white 2-stacks whose state is not 1.

If it had done this it would have resulted in the score of P1 being equal to the sum of the values of all its groups. What happens instead is that the value of one of the groups is added to the score of P1 once for each white two-stack on the board. Could someone explain to me why this happens?

In short:
It seems to me that the code should
(1) add the value of each group to the score once,
but instead it
(2) adds the value of one group to the score once for each group.
What am I misunderstanding?

I have attached a file that shows it in action. When you add adjacent to no friendly stone you place a 2-stack, otherwise a 1-stack. In this "debug-version" when you pass the score of P1 is calculated.

Edit: A hypothesis that could explain this is that (forEach Site <region> (and <moves1> <moves2>)) is equivalent to (and (forEach Site <region> <moves1>) (forEach Site <region> <moves2>). This seems even to be true in the case where I use (do <moves1> next:<moves2>) in stead of (and <moves1> <moves2>).


RE: The behavior of the nondecision operator (forEach) - Michael - 09-27-2020

In an attempt to implement triangular scoring differently I have come across a simpler case of what I think is the same behavior:
Code:
(forEach Site
    (forEach
        (sites Group at:(last To))
        if:(= 2 (size Stack at:(site)))
    )
    (do
        (set State at:(site) (var))
        next:(set Var (+ 1 (var)))
    )
)


Suppose (var) is 1 before this function is called. I would expect it to go through each site in the group of (last To) to containing a 2-stack and set the state of the first to 1, the second to 2, the third to 3, and so on. But this does not seem to be the logic of (forEach Site). What am I misunderstanding?


RE: The behavior of the nondecision operator (forEach) - Eric Piette - 09-28-2020

Hi Michael,

On this example what you understand is right. I made a simpler example to try with a nested forEach and that works without any problem, the first (site) belongs to the nested (forEach ...) and the second (site) to the outer (forEach ...).

For your previous message I would need time to look at it, that does not need a quick answer. I will look between 2 works ;)

Regards,
Eric


RE: The behavior of the nondecision operator (forEach) - Michael - 09-28-2020

Thank you! That's a clear and simple illustration of nesting. My issue is not about nesting, however, but about updating a variable or state in between iterations.

By the way, it's way too kind of you to spend time on this outside of work! I really appreciate it, but hope you feel that you don't have to. I can wait.


RE: The behavior of the nondecision operator (forEach) - Eric Piette - 10-02-2020

Ok I looked but I am still not sure what is the expected result (Sorry I work on many stuff in the same time and I have a bit forget here).

When a player pass, you want to add to his score a score equals to the number of stacks of size 2 in each group?
Or that's more complex?

I guess I should add a way to iterate each group, that should be easier for you to do it with that ludeme.
But can you explain it once again what is the expected result of the scoring calculation?

Regards,
Eric


RE: The behavior of the nondecision operator (forEach) - Michael - 10-02-2020

(10-02-2020, 09:02 AM)Eric Piette Wrote: Ok I looked but I am still not sure what is the expected result (Sorry I work on many stuff in the same time and I have a bit forget here).

When a player pass, you want to add to his score a score equals to the number of stacks of size 2 in each group?
Or that's more complex?
The score should be the sum of the values of all his groups. The value of a group is based on the number of 2-stacks in it. A group with one 2-stack is worth 1, a group with two is worth 3, a group with three is worth 6. The general formula for n 2-stacks in a group is (n(n+1))/2.

But the more underlying issue is howto change a variable or state in between iterations. Post #2 shows the problem a bit cleaner, I think. And my hypothesis (to repeat) is that
Code:
(forEach Site
    <region>
    (and <moves1> <moves2>)
)
is equivalent to
Code:
(and
    (forEach Site <region> <moves1>)
    (forEach Site <region> <moves2>)
)
This seems even to be true in the case where I use (do <moves1> next:<moves2>) in stead of (and <moves1> <moves2>).

Is this correct? And if it is, does it mean I cannot change a state or variable in between iterations?


RE: The behavior of the nondecision operator (forEach) - Eric Piette - 10-02-2020

Ok I get it.

With your last post, if you use

(and
(forEach Site <region> <moves1>)
(forEach Site <region> <moves2>)
)

The moves will be all computed in a sequence and will modify the state one by one in following this sequence. But the computation of the second forEach will be done before to apply the first forEach
However if you modify a part of the state in the first forEach, that will affect the modification of the state by the second forEach if the same elements are used.



For the other post with the (do <moves1> next:<moves2>) that's better.
because here you are sure at 100% to apply completely the moves1 (and so modifying the state) before to even compute the moves generating by moves2 and then applying them.

So I think yes if you want to modify a part of the state (modifying a variable) before to compute another move, you should use the Do ludeme.

Regards,
Eric


RE: The behavior of the nondecision operator (forEach) - Michael - 10-02-2020

Consider the small file I have attached. The code is as follows:
Code:
(define "Foo"
    (do
        (set Var 1)
        next:(forEach Site
            (sites Board)
            (do
                (add (to (site)) count:(var) stack:true)
                next:(set Var (+ 1 (var)))
            )
        )
    )  
)

(game "IterationTest"
    (equipment
        {
            (board (square 2))
            (piece "Disc" Each)
        }
    )
    (rules
        (play
            (move Select (from (sites Board))
                (then
                    "Foo"
                )
            )
        )
        (end
            (if
                (= 2 (next))
                (result P1 Win)
            )
        )
    )
)
When you select a site Foo is called. 

This is what I expect: Foo will go through all the sites and add a number of discs equal to (var) in each site while increasing (var) by 1 in between each iteration. The result should be that one site has a single disc, one has a 2-stack, one has a 3-stack and one has a 4-stack. 

This is what happens: Foo adds 1 disc to each site.

My question is: Why?


RE: The behavior of the nondecision operator (forEach) - Eric Piette - 10-02-2020

No, if you do that in a consequence (then ...) you will apply the move (set Var 1) before each combination of actions generated by the (forEach Site ...)

Consequently, the variable var would be always equals to 1 between each move generated by the (forEach Site ...).

The ludeme (do ...) generates a set of moves in applying one moves first before to computes the second one.
Consequently the actions of the first move will be at the beginning of each set of actions generated by the second ones

Regards,
Eric


RE: The behavior of the nondecision operator (forEach) - Michael - 10-02-2020

(10-02-2020, 11:46 AM)Eric Piette Wrote: No, if you do that in a consequence (then ...) you will apply the move (set Var 1) before each combination of actions generated by the (forEach Site ...)

Consequently, the variable var would be always equals to 1 between each move generated by the (forEach Site ...).

The ludeme (do ...) generates a set of moves in applying one moves first before to computes the second one.
Consequently the actions of the first move will be at the beginning of each set of actions generated by the second ones

Regards,
Eric

So, it is impossible to change a variable in between the iterations of (for Each Sites) as long as it's inside (then …)?

Then I think it is impossible to work around the lack of iteration over groups. I would be very grateful for its inclusion :) Thanks for your great work!