How to manage 2d array in Smalltalk? - smalltalk

I have a list of point and have to do erosion/dilation operations. I need a kind of 2d-array but can't find how to do in VisualWorks (I know there is a Array2d class in Squeak, but I must use VW).

Many Smalltalk implementation will have some kind of Matrix class, sometimes optimized, that will have methods such as #rowAt:columnAt: (or for brevity #at:at:).
In GNU Smalltalk this is in package DhbNumericalMethods. Right now it is not optimized though.

Use simply a generic way: array of arrays:
(Array new: xSize)
at: 1 put: ((Array new: ySize) at: 1 put: aValue; at: 2 put: aValue; ...);
at: 2 put: ((Array new: ySize) at: 1 put: aValue; at: 2 put: aValue; ...);
...

If you want to the operations to be efficient, study the VisualWorks Image class, protocol "image processing" and "bit processing". Build your own erosion/dilation operations based on primitives there.

Here is another way to deal with a two dimensional array in Squeak (I'm using version 4.2).
test := Matrix new: 3. "this defines a 3 x 3 array"
test at: 1 at: 1 put: 5.
test at: 1 at: 2 put: 6.
test at: 1 at: 3 put: 7.
etc, etc. AFAIK you can only do 2D arrays this way, and they must be a square matrix. This worked well for a project that my son and I are working on to make a Sudoku game, ymmv. CHEERS!

Array subclass: Array2D
instanceVariableNames: 'myRows myColumns'
classVariableNames: ''
poolDictionaries: ''
category: 'Basic Data Structures'
"I am a two-dimensional array of arbitrary objects.
[Privately, I am really a linear (one-dimensional) array.
I locate my elements internally by index arithmetic on their
(two-dimensional) coordinates.]"
Instance creation (class)
-------------------------
new: nRows by: nColumns
"Create a new instance of me with nRows rows and nColumns
columns."
^(super new: (nRows * nColumns))
withRows: nRows withColumns: nColumns
"exampleArray := Array2D new: 10 by: 5"
Initialization
--------------
withRows: nRows withColumns: nColumns
"Set my number of rows and columns to nRows and nColumns,
respectively.
"
myRows := nRows.
myColumns := nColumns
Properties
----------
rows
"My number of rows."
^myRows
columns
"My number of columns."
^myColumns
Element access
--------------
atRow: whichRow atColumn: whichColumn
"My element at row whichRow and column whichColumn."
^super at: (self indexAtRow: whichRow
atColumn: whichColumn)
"exampleValue := exampleArray atRow: 6 atColumn: 4"
atRow: whichRow atColumn: whichColumn put: newValue
"Store value newValue as my element at row whichRow and
column whichColumn."
super at: (self indexAtRow: whichRow
atColumn: whichColumn)
put: newValue
"exampleArray atRow: 6 atColumn: 4 put: exampleValue"
Private
-------
indexAtRow: whichRow atColumn: whichColumn
"The internal index at which I store my element at row
whichRow and column whichColumn.
"
^((whichRow - 1) * myColumns) + whichColumn

Related

Why is assigning many variables seem to mutate my variable?

I'm new to Smalltalk so I don't know if I'm doing something wrong but this seems very weird and buggy.
dict := Dictionary new.
dict at: 1 put: 1.
dict at: 2 put: 2.
dict at: 3 put: 3.
dict at: 4 put: 4.
1 to: 4 do: [:j |
key := j.
value := dict at: key.
value print.
value printNl.
].
This code works fine and correctly print
11
22
33
44
But then, if I add enough assignments to other variables the result of the script change:
dict := Dictionary new.
dict at: 1 put: 1.
dict at: 2 put: 2.
dict at: 3 put: 3.
dict at: 4 put: 4.
1 to: 4 do: [:j |
key := j.
value := dict at: key.
value print.
unrelated := 1.
unrelated2 := 1.
unrelated3 := 1.
unrelated4 := 1.
unrelated5 := 1.
unrelated6 := 1.
unrelated7 := 1.
unrelated8 := 1.
unrelated9 := 1.
unrelated10 := 1.
value printNl.
].
This code now prints
11
21
31
41
If I remove the line assigning unrelated10 it works again... Am I missing something or is GNU Smalltalk buggy ?
I am using GNU Smalltalk version 3.2.5.
I believe that this is a bug in GNU Smalltalk. It appears that the system allows you to reference variables that have not been defined (this "feature" is not standard) and the system's attempt to define the variables and their scope is having problems.
The work-around is to define your own variables and give them as narrow a scope as possible (this is good practice in any language). So, try the following (validated at here):
| dict |
dict := Dictionary new.
dict at: 1 put: 1.
dict at: 2 put: 2.
dict at: 3 put: 3.
dict at: 4 put: 4.
1 to: 4 do: [:j |
"The following is a list of variables used in this code block"
| key value
unrelated unrelated2 unrelated3 unrelated4 unrelated5
unrelated6 unrelated7 unrelated8 unrelated9 unrelated10 |
key := j.
value := dict at: key.
value print.
unrelated := 1.
unrelated2 := 1.
unrelated3 := 1.
unrelated4 := 1.
unrelated5 := 1.
unrelated6 := 1.
unrelated7 := 1.
unrelated8 := 1.
unrelated9 := 1.
unrelated10 := 1.
value printNl.
].

How to use a multiple line input to create my game?

So, i have one method that will create all of the instance variables for my other methods that will create the game, i know how to do them separately but finding how to do it from one method is really hard.
I need to be reading data from a String where each line must be treated separately.
Am using Pharo.
Class Game, everything is within one Game class.
Game: instance variables: 'rol col'. Using instance methods.
readFrom: 'Board 3 4
Dice 2 1 1 1
Players 1'
board
[my actual code that creates a board]
row for loop[
Transcript show: 'creating board'.
col for loop[
Transcript show: 'creating board'.
]
]
dice
[dice code..]
players
[players code]
Your model is not clearly defined yet. However, by helping you with some coding I will try to give you some insights on how to fill the gaps still remaining.
So, let's say you have a class Game. This class defines (at least) 4 instance variables: rows, columns, dice and players.
Now you want to create an instance of Game by reading some String that conforms to a certain format, such in:
'Board 3 4
Dice 2 1 1 1
Players 1'
To do this create a class side method in Game on the lines of
readFrom: aString
^self new readFrom: aString
and then an instance method
readFrom: aString
aString lines do: [:line | | data key |
data := line substrings.
key := data at: 1.
key = 'Board'
ifTrue: [
rows := data at: 2.
columns := data at: 3].
key = 'Dice'
ifTrue: [
dice := data allButFirst collect: [:s | s asInteger]].
key = 'Players'
ifTrue: [
players := (data at: 2) asInteger]]
Again, this won't solve all problems, but should help you get started. Otherwise, ask again.

Get key with largest value from a dictionary in Smalltalk

I am using a Dictionary where the keys are strings and the values are integers. How can I get the key with the largest value out of this Dictionary?
I know there is the associationsDo: method I can use to iterate over both keys and values, but I don't know how to get the maximum value.
| countDict |
countDict := Dictionary new.
...
countDict associationsDo: [ :k :v | ??? ]
Here is a way to do it following your idea:
| max largest |
max := nil.
countDict associationsDo: [:k :v |
(max isNil or: [v > largest])
ifTrue: [
max := k.
largest := v]].
^max
Here is another way, shorter but not very efficient:
countDict isEmpty ifTrue: [^nil].
^countDict keyAtValue: countDict max
Also, if you have a countDict I suspect that it represents the number of occurrences of every key. If that is the case you shouldn't be using a Dictionary but a Bag. Instances of Bag represent collections of objects which may have several occurrences each. Examples:
names := Bag new.
people do: [:person | names add: person firstName].
and you may end up with
2 occurrences of 'John'
1 occurrence of 'Paul'
4 occurrences of 'Ringo'
7 occurrences of 'George'
names occurrencesOf: 'John' ----> 2
The Bag will internally have a countDict sort of Dictionary, but to your model a Bag could reveal better your intention than a Dictionary because you will only need to add: elements without having to count them; the Bag will do it for you.
With a Bag your computation becomes
bag occurrencesOf: bag asSet max
The reason to send asSet is to avoid iterating several times on every value, which would happen if we simply put bag max. This simpler code will also work, but given that max iterates using do: and Bag implements do: by repeating the evaluation of the block for every occurrence of the element, this solution would be less efficient.
A better approach would be to re-implement max (and min) in Bag so that each element is iterated once. This would be similar to the code that we have above which followed your initial idea (associationsDo: [...). But let's leave the details of this as an exercise for the reader.
Anyway, if we re-implemnted max in Bag, the code would become simple and efficient at once:
bag occurrencesOf: bag max
Another nice way to do this:
(countDict associations detectMax: #value) key

Smalltalk How to Fill 2d array with random numbers?

In java, or C# filling of the 2d array is possible with two nested for loop, but in smalltalk I can't seem to find the way to do the same.
Could anyone help me out?
array filling
You can use Matrix and create it as:
| random |
random := Random new.
^ Matrix
rows: rowNumber
columns: columnNumber
tabulate: [ :i :j | random next ]
where i and j are indexes of the element (that I'm not using in the example)
If you really want to do something with 2d arrays I'd suggest you to do something like this:
| random |
random := Random new.
^ (1 to: rowNumber) collect: [ :i |
(1 to: columnNumber) collect: [ :j |
random next ]
You can also traverse a matrix after creation:
| random matrix |
random := Random new.
matrix := Matrix rows: rowNumber columns: columnNumber.
martix indicesCollect: [ :i :j | random next ].
^ matrix

How to create words within a Forth definition

I'm using Gforth, and I want to create a word in a definition. In the cmd line of Gforth I can type:
create foo
ok
Or more specifically, I defined an array function that expects a size on the stack and creates a word with the address to that array:
: array ( n -- ) ( i -- addr)
create cells allot
does> cells + ;
So if I type 10 array foo I can then use foo later.
But if I were to write 10 array foo within another definition it gives me a compilation error. I've tried replacing foo with s" foo" which compiles, but it blows up at run time, saying:
Attempt to use zero-length string as a name
Is there a way to do this?
One way to do it in gforth:
: bar 10 s" foo" ['] array execute-parsing ;
Other implementations do it differently, e.g. http://pfe.sourceforge.net/words/w-header-015.html
It's not easy to do in Standard Forth, but this may be good enough:
: bar 10 s" array foo" evaluate ;
I guess most of what you want to do can be done by defining words, i.e. using create ... does> ... This allows you to define a word with specialized behaviour.
E.g.:
: 2const create , , does> 2# ;
can be used to create double constants like 2 3 2const a-double (that stashes 2 and 3 away in a-double) and then a-double pushes two values (2 3).