How to declare a do:[] loop for a matrix to read and acces its elements?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

How to declare a do:[] loop for a matrix to read and acces its elements?

Photon
This post was updated on .
Hello folks,

I am trying since yesterday to make a game of life implemenation work. It looks all ok so far but in can`t figure out the final steps. I think I get the logic I have to use and if I imagine the code in C++ for example it would be pretty much straight forward. But with pharo I got trouble telling the machine what I want.

In short I`m trying to make this method work:

countNeighbours
	" [x-1 y+1] [x    y+1] [x+1 y+1]
 ----- [x-1 y    ] [  x   y   ] [  x+1 y   ]
 ----- [x-1 y-1 ] [ x   y-1 ] [  x+1 y-1]"

	"Should check the surounding cells if they are alive. If so adds a neighbour 
to the selected cells neighbour count"

	self cells
		do: [ :x :y | 
			(self at: x + 1 at: y) isAlive
				ifTrue: [ (self at: x at: y) addNeighbour ] ]

I wrote a test wich looks like this:
testCountNeighbours
	| sampleGame |
	sampleGame := GameOfLife new.
	(sampleGame cells at: 2 at: 1) turnAlive.
	sampleGame countNeighbours.
	self assert: (sampleGame cells at: 1 at: 1) neighbours equals:  1


I want to go trough each element of the matrix(cells), check its surounding cells if they are alive, and set its counter if there are any living neighbours. It should move like this through the whole matrix to set the neighbour counter for each element.

In this method I just tried to implement right side check yet but I think you get the idea. You can look at the comment  in the top section it shows where the neighbour indexes are.

I tried so many things by now, did research read methods of the superclasses but I can`t make it work.
I woud be really glad if someone gave me a little hint. What is wrong here?


Reply | Threaded
Open this post in threaded view
|

Re: How to declare a do:[] loop for a matrix to read and acces its elements?

Nicolai Hess-3-2


2018-01-15 15:29 GMT+01:00 Photon <[hidden email]>:
Hello folks,

I am trying since yesterday to make a game of life implemenation work. It
looks all ok so far but in can`t figure out the final steps. I think I get
the logic I have to use and if I imagine the code in C++ for example it
would be pretty much straight forward. But with pharo I got trouble telling
the machine what I want.

In short I`m trying to make this method work:



I wrote a test wich looks like this:



I want to go trough each element of the matrix(cells), check its surounding
cells if they are alive, and set its counter if there are any living
neighbours. It should move like this through the whole matrix to set the
neighbour counter for each element.

In this method i just tried the implement the topLeft check yet but I think
you get the idea. You can look at the comment  in the top section it shows
where the neighbour indexes are.

I tried so many things by now, did research read methods of the superclasses
but I can`t make it work.
I woud be really glad if someone gave me a little hint. What is wrong here?

I Photon, what exaclty get wrong ? Do you have an error message or is just the result not what you expected?

Iterating over a matrix with do: would iterate over the whole contents of the matrix and the do block gets only called
with a single value (the actual element).

If you want to iterate over the indices (x/y) you can take a look at the method Matrix>>indicesDo: .
Or if it does not match what you are looking for, check out the other methods in Matrix 'enumeration' protocol.

nicolai
 



--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html


Reply | Threaded
Open this post in threaded view
|

Re: How to declare a do:[] loop for a matrix to read and acces its elements?

Photon
when I call the countNeighbours method i get an error: the block wants two
arguments but I pass only one.
This is probally because i want to pass x y but only really pass x wich ends
up being a cell and not the index.

I still have trouble thinking it trough. The indicieDo: method seems to make
the matrix bigger?! I  don`t quite understand it.

There must be an easy way to to figure out if the suroundings are alive or
not. I mean its all there what I need and in my mind its so easy to discribe
it with normal words. But to tell the machine witth syntax is another thing
really :/

what if i selected only one element with do:[] and let its tell me its
idices. I store them in a temp object and then I check outside the block the
neighbours and add to the counter. Once this is done I repeat as many times
as their elements in the matrix?

Greetings






--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html





--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: How to declare a do:[] loop for a matrix to read and acces its elements?

Nicolai Hess-3-2


2018-01-15 18:04 GMT+01:00 Photon <[hidden email]>:
when I call the countNeighbours method i get an error: the block wants two
arguments but I pass only one.
This is probally because i want to pass x y but only really pass x wich ends
up being a cell and not the index.

I still have trouble thinking it trough. The indicieDo: method seems to make
the matrix bigger?! I  don`t quite understand it.

It should not, and looking at the implementation, it just iterates with two
loops 1 to number of rows times 1 to number of columns and calls your
block argument with the pair of indexes.
 

There must be an easy way to to figure out if the suroundings are alive or
not. I mean its all there what I need and in my mind its so easy to discribe
it with normal words. But to tell the machine witth syntax is another thing
really :/

About the surroundings, there is a nice method in Point
Point>>eightNeighbors, that gives you the coordinates of the eight surrounding fields
for example:
(5@7) eightNeighbors  "{(6@7). (6@8). (5@8). (4@8). (4@7). (4@6). (5@6). (6@6)}"

with this method and if you iterate through all pairs of indices of the matrix, you can
do your computation for every point, but you have to take care about the points that don't
have valid matrix indices for some of their neighbours (like 0@0, the left and top neighbours
may actually "on the other side of the matrix"). But you can take a look at
SequenceableCollection>>atWrap: how it deals with "wrapping around".


 

what if i selected only one element with do:[] and let its tell me its
idices. I store them in a temp object and then I check outside the block the
neighbours and add to the counter. Once this is done I repeat as many times
as their elements in the matrix?

Greetings







Reply | Threaded
Open this post in threaded view
|

Re: How to declare a do:[] loop for a matrix to read and acces its elements?

Ben Coman
On 16 January 2018 at 05:47, Nicolai Hess <[hidden email]> wrote:

>
>
> 2018-01-15 18:04 GMT+01:00 Photon <[hidden email]>:
>>
>> when I call the countNeighbours method i get an error: the block wants two
>> arguments but I pass only one.
>> This is probally because i want to pass x y but only really pass x wich
>> ends
>> up being a cell and not the index.
>>
>> I still have trouble thinking it trough. The indicieDo: method seems to
>> make
>> the matrix bigger?! I  don`t quite understand it.
>
>
> It should not, and looking at the implementation, it just iterates with two
> loops 1 to number of rows times 1 to number of columns and calls your
> block argument with the pair of indexes.
>
>>
>>
>> There must be an easy way to to figure out if the suroundings are alive or
>> not. I mean its all there what I need and in my mind its so easy to
>> discribe
>> it with normal words. But to tell the machine witth syntax is another
>> thing
>> really :/
>
>
> About the surroundings, there is a nice method in Point
> Point>>eightNeighbors, that gives you the coordinates of the eight
> surrounding fields
> for example:
> (5@7) eightNeighbors  "{(6@7). (6@8). (5@8). (4@8). (4@7). (4@6). (5@6).
> (6@6)}"


@all, side-question...
I remember from Squeak Lasergame tutorial that it represented a grid
as a Dictionary rather than an Array of Arrays.
http://squeak.preeminent.org/tut2007/html/032.html
  #initializeCells

Anyone have an opinion of the suitability of that approach in relation
to grid sizing?

cheers -ben

>
> with this method and if you iterate through all pairs of indices of the
> matrix, you can
> do your computation for every point, but you have to take care about the
> points that don't
> have valid matrix indices for some of their neighbours (like 0@0, the left
> and top neighbours
> may actually "on the other side of the matrix"). But you can take a look at
> SequenceableCollection>>atWrap: how it deals with "wrapping around".
>
>
>
>>
>>
>> what if i selected only one element with do:[] and let its tell me its
>> idices. I store them in a temp object and then I check outside the block
>> the
>> neighbours and add to the counter. Once this is done I repeat as many
>> times
>> as their elements in the matrix?
>>
>> Greetings

Reply | Threaded
Open this post in threaded view
|

Re: How to declare a do:[] loop for a matrix to read and acces its elements?

Photon
This post was updated on .
In reply to this post by Photon
So for those of you who are interested or maybe is struggeling himself.
I did it now in a more C fashion if i can call it like that. I don`t know if its even legit :P

I managed to make the game work based on this method, the rest was easy. At least enough for tonight. Tomorrow I try to add a nice U.I.
still here is how I did it :

countNeighbours
	| x y size |
	size := self gridSize.
	x := 1.
	y := 1.


	size
		timesRepeat: [ size
				timesRepeat: [ x > 1
						ifTrue: [ (cells at: x - 1 at: y) isAlive
								ifTrue: [ (cells at: x at: y) addNeighbour ] ].	"left"
					x < size
						ifTrue: [ (cells at: x + 1 at: y) isAlive
								ifTrue: [ (cells at: x at: y) addNeighbour ] ].	"right"
					y > 1
						ifTrue: [ (self cells at: x at: y - 1) isAlive
								ifTrue: [ (cells at: x at: y) addNeighbour ] ].	"top"
					y < size
						ifTrue: [ (self cells at: x at: y + 1) isAlive
								ifTrue: [ (cells at: x at: y) addNeighbour ] ].	"bottom"
					x < size
						ifTrue: [ y < size
								ifTrue: [ (cells at: x + 1 at: y + 1) isAlive
										ifTrue: [ (cells at: x at: y) addNeighbour ] ] ].	"bottom right"
					x < size
						ifTrue: [ y > 1
								ifTrue: [ (cells at: x + 1 at: y - 1) isAlive
										ifTrue: [ (cells at: x at: y) addNeighbour ] ] ].	"top right"
					x > 1
						ifTrue: [ y > 1
								ifTrue: [ (cells at: x - 1 at: y - 1) isAlive
										ifTrue: [ (cells at: x at: y) addNeighbour ] ] ].	"top left"
					x > 1
						ifTrue: [ y < size
								ifTrue: [ (cells at: x - 1 at: y + 1) isAlive
										ifTrue: [ (cells at: x at: y) addNeighbour ] ] ].	"bottom left"
					x := x + 1 ].
			x := 1.
			y := y + 1 ]

I also wrote two tests. The first one is the test for the method itself and the second one is just to test an algorythm construction because the one I used before was an endless loop I quess.

testCountNeighbours
	| sampleGame |
	sampleGame := GameOfLife new.
	sampleGame cells do: [ :c | c turnAlive ].
	(sampleGame cells at: 2 at: 1) turnDead.
	(sampleGame cells at: 3 at: 3) turnDead.
	sampleGame countNeighbours.
	self assert: (sampleGame cells at: 2 at: 2) neighbours equals: 6

And :

testLoop
	| x y size myCounter |
	size := 5.
	x := 1.
	y := 1.
	myCounter := 0.
	size
		timesRepeat: [ size
				timesRepeat: [ myCounter := myCounter + 1.
					x := x + 1 ].
			x := 1.
			y := y + 1 ].
	self assert: x equals: 1.
	self assert: y equals: 6.
	self assert: myCounter equals: 25
Reply | Threaded
Open this post in threaded view
|

Re: How to declare a do:[] loop for a matrix to read and acces its elements?

Richard O'Keefe
In reply to this post by Photon
I'm reading this in gmail.  After "this method work:" I see a gap with nothing visible.
After "wich looks like this" there is again a gap with nothing visible. 

Recalling that the Life universe is an *infinite* two-dimensional space, you want a data
structure that naturally grows to be as big as it needs to be and no bigger.  I ran across
a similar problem last year.  A Dictionary[Integer->Dictionary[Integer->State]] turned
out to work very well.  You could also use a Dictionary[Point[Integer,Integer] -> State]
which would be logically  simpler.  The key idea is that you don't want to iterate over
all the cells, only the cells which are live.  Now the states in Life are very simple,
so the data structure you want is actually a Set[Point[Integer,Integer]].  The only
cells that can change state are the live cells and the dead (not present in the set) that
are king-wise adjacent to a live cell.   So you will be doing something like
    candidates := Bag new.
    dyingCells := Set new.
    liveCells do: [:each |
        n := 0.
        each kingwiseNeighboursDo: [:neighbour |
          (liveCells includes: neighbour)
             ifTrue: [n := n + 1]
             ifFalse: [candidates add: Bag]]
        (n between: 2 and: 3) ifFalse: [dyingCells add: each].
    liveCells removeAll: dyingCells.
    candidates valuesAndCounts keysAndValuesDo: [:each :count |
        count = 3 ifTrue: [liveCells add: each]].
WARNING: This code has not been tested.

On 16 January 2018 at 03:29, Photon <[hidden email]> wrote:
Hello folks,

I am trying since yesterday to make a game of life implemenation work. It
looks all ok so far but in can`t figure out the final steps. I think I get
the logic I have to use and if I imagine the code in C++ for example it
would be pretty much straight forward. But with pharo I got trouble telling
the machine what I want.

In short I`m trying to make this method work:



I wrote a test wich looks like this:



I want to go trough each element of the matrix(cells), check its surounding
cells if they are alive, and set its counter if there are any living
neighbours. It should move like this through the whole matrix to set the
neighbour counter for each element.

In this method i just tried the implement the topLeft check yet but I think
you get the idea. You can look at the comment  in the top section it shows
where the neighbour indexes are.

I tried so many things by now, did research read methods of the superclasses
but I can`t make it work.
I woud be really glad if someone gave me a little hint. What is wrong here?



--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html


Reply | Threaded
Open this post in threaded view
|

Re: How to declare a do:[] loop for a matrix to read and acces its elements?

Richard O'Keefe
PS: note that a matrix representation of the Life world (a) wastes a ton of space,
(b) wastes a ton of time if you iterate over all the cells (because most of them are
irrelevant), (c) is awkward to grow, and (d) has problems at the edges (which
should not exist).  In C or C++ I would not dream of using a rectangular matrix
for Life.  I might possibly use a quad  tree, but I'd probably stick with a set of points.


On 16 January 2018 at 19:41, Richard O'Keefe <[hidden email]> wrote:
I'm reading this in gmail.  After "this method work:" I see a gap with nothing visible.
After "wich looks like this" there is again a gap with nothing visible. 

Recalling that the Life universe is an *infinite* two-dimensional space, you want a data
structure that naturally grows to be as big as it needs to be and no bigger.  I ran across
a similar problem last year.  A Dictionary[Integer->Dictionary[Integer->State]] turned
out to work very well.  You could also use a Dictionary[Point[Integer,Integer] -> State]
which would be logically  simpler.  The key idea is that you don't want to iterate over
all the cells, only the cells which are live.  Now the states in Life are very simple,
so the data structure you want is actually a Set[Point[Integer,Integer]].  The only
cells that can change state are the live cells and the dead (not present in the set) that
are king-wise adjacent to a live cell.   So you will be doing something like
    candidates := Bag new.
    dyingCells := Set new.
    liveCells do: [:each |
        n := 0.
        each kingwiseNeighboursDo: [:neighbour |
          (liveCells includes: neighbour)
             ifTrue: [n := n + 1]
             ifFalse: [candidates add: Bag]]
        (n between: 2 and: 3) ifFalse: [dyingCells add: each].
    liveCells removeAll: dyingCells.
    candidates valuesAndCounts keysAndValuesDo: [:each :count |
        count = 3 ifTrue: [liveCells add: each]].
WARNING: This code has not been tested.

On 16 January 2018 at 03:29, Photon <[hidden email]> wrote:
Hello folks,

I am trying since yesterday to make a game of life implemenation work. It
looks all ok so far but in can`t figure out the final steps. I think I get
the logic I have to use and if I imagine the code in C++ for example it
would be pretty much straight forward. But with pharo I got trouble telling
the machine what I want.

In short I`m trying to make this method work:



I wrote a test wich looks like this:



I want to go trough each element of the matrix(cells), check its surounding
cells if they are alive, and set its counter if there are any living
neighbours. It should move like this through the whole matrix to set the
neighbour counter for each element.

In this method i just tried the implement the topLeft check yet but I think
you get the idea. You can look at the comment  in the top section it shows
where the neighbour indexes are.

I tried so many things by now, did research read methods of the superclasses
but I can`t make it work.
I woud be really glad if someone gave me a little hint. What is wrong here?



--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html



Reply | Threaded
Open this post in threaded view
|

Re: How to declare a do:[] loop for a matrix to read and acces its elements?

Photon
This post was updated on .
Thank for your answer. Those are awesome tips :)

If you read my posts in the forum you should be able to read what I wrote.
Its because whenever I insert raw text it gets deletet right away and I have
to edit the post and put it back in.
Anyways in my last post you see how i did it. I think you are also refering
to that.

I know using 2d matrix/ array is a a waste. Maybe when I start to refactory
this game I try to focus on your aproach. Sounds good. One could even use a
1d container like a list.

Im not sure is the gameworld should grow inifitly. In the ruleset on
wikipedia there is a fixed board size. The smallest one is 3*3 but I could
implement is as one possible size to select from.

To the part that I would only need to check certain cells I think I have to
check all of them because they could get born in the next generation even
tho they were never alive nor dead.
The thing I wanted to improve here was that I do not need to check all the 8
neighbours. As soon as neighboars equals 4 the cell is dead for sure and
there is no need to check further. Couls save at max half the time beauce
only half the checks are made.



--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: How to declare a do:[] loop for a matrix to read and acces its elements?

Ben Coman
In reply to this post by Nicolai Hess-3-2
@nicolai, Thx for the cool tip.  #eightNeighbors is new to me and I
was curious to try it.  So below is one way to have Life with it.

For conciseness of this post, please excuse that I've roughly used
booleans directly as grid elements rather a nicely encapsulated Cell
object.

  Object subclass: #LifeGrid
      instanceVariableNames: 'size cellsAlive'

  LifeGrid >> initialize
     size := 4.
     cellsAlive := Dictionary new.
     1 to: size do: [:x|
          1 to: size do: [:y|
               cellsAlive at: (x@y) put: false ] ]

  LifeGrid >> turnAliveAt: location
      cellsAlive at: location put: true

  LifeGrid >> aliveAt: location
      ^ cellsAlive at: location ifPresent: [ :isAlive | isAlive ]
ifAbsent: [ false ]

  LifeGrid >> countNeighboursAt: location
      ^ (location eightNeighbors select: [ :neighbour | self aliveAt:
neighbour ]) size

Testing from Playground...
grid := LifeGrid new.
grid countNeighboursAt: 2@2. "==>0"
grid turnAliveAt: 1@1.
grid countNeighboursAt: 2@2. "==>1"
grid turnAliveAt: 3@3.
grid countNeighboursAt: 2@2. "==>2"
grid countNeighboursAt: 1@2. "==>1"

cheers -ben


On 16 January 2018 at 05:47, Nicolai Hess <[hidden email]> wrote:

>
>
> 2018-01-15 18:04 GMT+01:00 Photon <[hidden email]>:
>>
>> when I call the countNeighbours method i get an error: the block wants two
>> arguments but I pass only one.
>> This is probally because i want to pass x y but only really pass x wich
>> ends
>> up being a cell and not the index.
>>
>> I still have trouble thinking it trough. The indicieDo: method seems to
>> make
>> the matrix bigger?! I  don`t quite understand it.
>
>
> It should not, and looking at the implementation, it just iterates with two
> loops 1 to number of rows times 1 to number of columns and calls your
> block argument with the pair of indexes.
>
>>
>>
>> There must be an easy way to to figure out if the suroundings are alive or
>> not. I mean its all there what I need and in my mind its so easy to
>> discribe
>> it with normal words. But to tell the machine witth syntax is another
>> thing
>> really :/
>
>
> About the surroundings, there is a nice method in Point
> Point>>eightNeighbors, that gives you the coordinates of the eight
> surrounding fields
> for example:
> (5@7) eightNeighbors  "{(6@7). (6@8). (5@8). (4@8). (4@7). (4@6). (5@6).
> (6@6)}"
>
> with this method and if you iterate through all pairs of indices of the
> matrix, you can
> do your computation for every point, but you have to take care about the
> points that don't
> have valid matrix indices for some of their neighbours (like 0@0, the left
> and top neighbours
> may actually "on the other side of the matrix"). But you can take a look at
> SequenceableCollection>>atWrap: how it deals with "wrapping around".
>
>
>
>>
>>
>> what if i selected only one element with do:[] and let its tell me its
>> idices. I store them in a temp object and then I check outside the block
>> the
>> neighbours and add to the counter. Once this is done I repeat as many
>> times
>> as their elements in the matrix?

Reply | Threaded
Open this post in threaded view
|

Re: How to declare a do:[] loop for a matrix to read and acces its elements?

Photon
That looks ideed cool thanx Nicolai for the hint.

@Ben du you have an idea how to store the prevoius generations? I case
something cool happens and you want to rewind to have a closer look



--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: How to declare a do:[] loop for a matrix to read and acces its elements?

Ben Coman
On 16 January 2018 at 22:05, Photon <[hidden email]> wrote:
> That looks ideed cool thanx Nicolai for the hint.
>
> @Ben du you have an idea how to store the prevoius generations? I case
> something cool happens and you want to rewind to have a closer look

In a well designed app, you'd have "grid" instance variable instead of
"cellsAlive"
so then it could be something like...
  LifeGrid >> storeGeneration
       generations ifNil: [generations := OrderedCollection new].
       generations add: grid copy.

but perhaps manipulating a single grid in-place causes complications
and you are better off
replacing the whole grid each generation.  Then you don't need the #copy.

cheers -ben

Reply | Threaded
Open this post in threaded view
|

Re: How to declare a do:[] loop for a matrix to read and acces its elements?

Photon
yes I worked with a grid all the time. Thanks for showig me the code. I did
it all the time without copy and was wondering big time xD



--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: How to declare a do:[] loop for a matrix to read and acces its elements?

Richard O'Keefe
In reply to this post by Photon
Sorry about the late reply, but I've been away on holiday.
You wrote "Im not sure is the gameworld should grow inifitly. In the ruleset on
wikipedia there is a fixed board size. The smallest one is 3*3 but I could
implement is as one possible size to select from."

It's not your decision.  Conway's Life simply *is* defined for an infinite world.
Without that, it wouldn't be Turing-universal, as it is.  The first sentence in
the Rules section begins "The universe of the Game of Life is an infinite two-dimensional orthogonal grid".
The ruleset on the Wikipedia page does NOT have a fixed size.  The examples are shown just big enough
to contain all the live cells, but that is another matter.

There are four things you can do when emulating a game on a grid:
(1) STOP when you hit the edge, deliberately or by crashing.
(2) ERR by pretending everything outside is dead. The program does
not stop, it just stops giving right answers.
(3) REDEFINE the world to be a toroidal space instead of an infinite one.
Again, this changes the rules enough to count as a different game.
(4) GROW the world.  Allocate a new bigger world and copy the old one
across.
But the best way to deal with limitations is to avoid building them into the
program in the first place.

It's a bit like concurrency.  It took a while before I realised that "how do I
add concurrency to my programs" was the wrong question and that I
should have been asking "how do I learn to stop adding sequentiality to
my programs?"