From 87df204791f0a52463551bcc633c0ddfb1bc7ac3 Mon Sep 17 00:00:00 2001 From: HossamSaberr Date: Tue, 10 Mar 2026 09:11:03 +0200 Subject: [PATCH 1/3] Add wrap and neighbor access methods for grid logic --- .../CTArray2DTest.class.st | 55 +++++++++++++++++++ src/Containers-Array2D/CTArray2D.class.st | 36 ++++++++++++ 2 files changed, 91 insertions(+) diff --git a/src/Containers-Array2D-Tests/CTArray2DTest.class.st b/src/Containers-Array2D-Tests/CTArray2DTest.class.st index b7752ee..0e4c59f 100644 --- a/src/Containers-Array2D-Tests/CTArray2DTest.class.st +++ b/src/Containers-Array2D-Tests/CTArray2DTest.class.st @@ -87,6 +87,34 @@ CTArray2DTest >> testAtColumnPut [ 1 to: foo height do: [ :y | self assert: (foo atColumn: 2 atRow: y) equals: 1 ] ] +{ #category : 'tests-accessing' } +CTArray2DTest >> testAtColumnWrapAtRowWrap [ + + | array | + array := self arrayClass width2Height3. + + self assert: (array atColumnWrap: 1 atRowWrap: 1) equals: 1. + + self assert: (array atColumnWrap: 3 atRowWrap: 1) equals: 1. + + self assert: (array atColumnWrap: 2 atRowWrap: 4) equals: 2. + + self assert: (array atColumnWrap: 0 atRowWrap: 0) equals: 6. +] + +{ #category : 'tests-accessing' } +CTArray2DTest >> testAtColumnWrapAtRowWrapPut [ + + | array | + array := self arrayClass width2Height3. + + array atColumnWrap: 3 atRowWrap: 2 put: 99. + self assert: (array atColumn: 1 atRow: 2) equals: 99. + + array atColumnWrap: 0 atRowWrap: 0 put: 88. + self assert: (array atColumn: 2 atRow: 3) equals: 88. +] + { #category : 'tests-accessing' } CTArray2DTest >> testAtPut [ @@ -236,6 +264,33 @@ CTArray2DTest >> testLeftToRightFromBottomToTopDo [ ] +{ #category : 'tests-accessing' } +CTArray2DTest >> testNeighborsAtColumnAtRow [ + + | array neighbors topCornerNeighbors | + array := self arrayClass width2Height3. + + neighbors := array neighborsAtColumn: 1 atRow: 2. + self assert: neighbors size equals: 5. + self assert: (neighbors includesAll: #(1 2 4 5 6)). + + topCornerNeighbors := array neighborsAtColumn: 1 atRow: 1. + self assert: topCornerNeighbors size equals: 3. + self assert: (topCornerNeighbors includesAll: #(2 3 4)). +] + +{ #category : 'tests-accessing' } +CTArray2DTest >> testNeighborsEight [ + + | array neighbors | + array := self arrayClass fromArray: #(1 2 3 4 5 6 7 8 9) width: 3. + + neighbors := array neighborsAtColumn: 2 atRow: 2. + + self assert: neighbors size equals: 8. + self assert: (neighbors includesAll: #(1 2 3 4 6 7 8 9)). +] + { #category : 'tests-printing' } CTArray2DTest >> testPrinting [ diff --git a/src/Containers-Array2D/CTArray2D.class.st b/src/Containers-Array2D/CTArray2D.class.st index f81d77c..44212fb 100644 --- a/src/Containers-Array2D/CTArray2D.class.st +++ b/src/Containers-Array2D/CTArray2D.class.st @@ -193,6 +193,26 @@ CTArray2D >> atColumn: x put: aCollection [ ^ aCollection ] +{ #category : 'accessing' } +CTArray2D >> atColumnWrap: col atRowWrap: row [ + + | wrappedCol wrappedRow | + wrappedCol := ((col - 1) \\ self width) + 1. + wrappedRow := ((row - 1) \\ self height) + 1. + + ^ self atColumn: wrappedCol atRow: wrappedRow +] + +{ #category : 'accessing' } +CTArray2D >> atColumnWrap: col atRowWrap: row put: aValue [ + + | wrappedCol wrappedRow | + wrappedCol := ((col - 1) \\ self width) + 1. + wrappedRow := ((row - 1) \\ self height) + 1. + + ^ self atColumn: wrappedCol atRow: wrappedRow put: aValue +] + { #category : 'accessing rows/columns' } CTArray2D >> atRow: y [ "Answer the content of the whole column at y" @@ -301,6 +321,22 @@ CTArray2D >> leftToRightFromBottomToTopDo: aBlock [ aBlock value: (self atColumn: col atRow: row)]] ] +{ #category : 'enumerating' } +CTArray2D >> neighborsAtColumn: col atRow: row [ + + | neighbors | + neighbors := OrderedCollection new. + + row - 1 to: row + 1 do: [ :r | + col - 1 to: col + 1 do: [ :c | + (r = row and: [ c = col ]) ifFalse: [ + (r between: 1 and: self height) ifTrue: [ + (c between: 1 and: self width) ifTrue: [ + neighbors add: (self atColumn: c atRow: r) ] ] ] ] ]. + + ^ neighbors +] + { #category : 'accessing - compatibility' } CTArray2D >> numberOfColumns [ "Answer the receiver's width, i.e., its number of x" From 115bf2cdab0fc3930580e741c3ae1139238e3399 Mon Sep 17 00:00:00 2001 From: HossamSaberr Date: Thu, 26 Mar 2026 10:23:37 +0200 Subject: [PATCH 2/3] Add wrapped neighbors and enforce bounds checking for neighbor --- .../CTArray2DTest.class.st | 32 +++++++++++++++++++ src/Containers-Array2D/CTArray2D.class.st | 28 ++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/Containers-Array2D-Tests/CTArray2DTest.class.st b/src/Containers-Array2D-Tests/CTArray2DTest.class.st index 0e4c59f..52c26b2 100644 --- a/src/Containers-Array2D-Tests/CTArray2DTest.class.st +++ b/src/Containers-Array2D-Tests/CTArray2DTest.class.st @@ -279,6 +279,38 @@ CTArray2DTest >> testNeighborsAtColumnAtRow [ self assert: (topCornerNeighbors includesAll: #(2 3 4)). ] +{ #category : 'tests' } +CTArray2DTest >> testNeighborsAtColumnAtRowOutOfBounds [ + + | array | + + array := self arrayClass width2Height3. + + self should: [ array neighborsAtColumn: 99 atRow: 99 ] raise: Error. +] + +{ #category : 'tests' } +CTArray2DTest >> testNeighborsAtColumnWrapAtRowWrap [ + + | array neighbors | + + array := self arrayClass fromArray: #(1 2 3 4 5 6 7 8 9) width: 3. + + neighbors := array neighborsAtColumnWrap: 1 atRowWrap: 1. + + self assert: neighbors size equals: 8. + self assert: (neighbors includesAll: #(2 3 4 5 6 7 8 9)). +] + +{ #category : 'tests' } +CTArray2DTest >> testNeighborsAtColumnWrapAtRowWrapOutOfBounds [ + | array | + + array := self arrayClass width2Height3. + + self should: [ array neighborsAtColumnWrap: 99 atRowWrap: 99 ] raise: Error. +] + { #category : 'tests-accessing' } CTArray2DTest >> testNeighborsEight [ diff --git a/src/Containers-Array2D/CTArray2D.class.st b/src/Containers-Array2D/CTArray2D.class.st index 44212fb..0528e98 100644 --- a/src/Containers-Array2D/CTArray2D.class.st +++ b/src/Containers-Array2D/CTArray2D.class.st @@ -323,17 +323,39 @@ CTArray2D >> leftToRightFromBottomToTopDo: aBlock [ { #category : 'enumerating' } CTArray2D >> neighborsAtColumn: col atRow: row [ - + | neighbors | + + (col between: 1 and: self width) ifFalse: [ self error: 'Column out of bounds' ]. + (row between: 1 and: self height) ifFalse: [ self error: 'Row out of bounds' ]. + neighbors := OrderedCollection new. - + row - 1 to: row + 1 do: [ :r | col - 1 to: col + 1 do: [ :c | (r = row and: [ c = col ]) ifFalse: [ (r between: 1 and: self height) ifTrue: [ (c between: 1 and: self width) ifTrue: [ neighbors add: (self atColumn: c atRow: r) ] ] ] ] ]. - + + ^ neighbors +] + +{ #category : 'enumerating' } +CTArray2D >> neighborsAtColumnWrap: col atRowWrap: row [ + + | neighbors | + + (col between: 1 and: self width) ifFalse: [ self error: 'Column out of bounds' ]. + (row between: 1 and: self height) ifFalse: [ self error: 'Row out of bounds' ]. + + neighbors := OrderedCollection new. + + row - 1 to: row + 1 do: [ :r | + col - 1 to: col + 1 do: [ :c | + (r = row and: [ c = col ]) ifFalse: [ + neighbors add: (self atColumnWrap: c atRowWrap: r) ] ] ]. + ^ neighbors ] From b97ed1484c9a5ac354b160807948d613ac439e9b Mon Sep 17 00:00:00 2001 From: HossamSaberr Date: Thu, 16 Apr 2026 20:24:30 +0200 Subject: [PATCH 3/3] Docs: Add method comments to grid wrapping and neighbor logic --- src/Containers-Array2D/CTArray2D.class.st | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Containers-Array2D/CTArray2D.class.st b/src/Containers-Array2D/CTArray2D.class.st index f0d1e2c..ee1832e 100644 --- a/src/Containers-Array2D/CTArray2D.class.st +++ b/src/Containers-Array2D/CTArray2D.class.st @@ -195,6 +195,7 @@ CTArray2D >> atColumn: x put: aCollection [ { #category : 'accessing' } CTArray2D >> atColumnWrap: col atRowWrap: row [ + "Answer the element at the given coordinates. If the coordinates are outside the grid bounds, they wrap around using 1-based indexing logic to ensure seamless boundary traversal." | wrappedCol wrappedRow | wrappedCol := ((col - 1) \\ self width) + 1. @@ -205,7 +206,8 @@ CTArray2D >> atColumnWrap: col atRowWrap: row [ { #category : 'accessing' } CTArray2D >> atColumnWrap: col atRowWrap: row put: aValue [ - + "Store the given value at the specified coordinates. If the coordinates are outside the grid bounds, they wrap around using 1-based indexing logic (e.g., in a grid of width 3, column 4 wraps to 1, and column 0 wraps to 3)." + | wrappedCol wrappedRow | wrappedCol := ((col - 1) \\ self width) + 1. wrappedRow := ((row - 1) \\ self height) + 1. @@ -375,7 +377,8 @@ CTArray2D >> isSelfEvaluating [ { #category : 'enumerating' } CTArray2D >> neighborsAtColumn: col atRow: row [ - + "Answer a collection of up to 8 valid elements surrounding the given origin. This method does not wrap; neighbors that would fall outside the grid are ignored. Throws an error if the starting origin coordinates are out of bounds." + | neighbors | (col between: 1 and: self width) ifFalse: [ self error: 'Column out of bounds' ]. @@ -395,7 +398,8 @@ CTArray2D >> neighborsAtColumn: col atRow: row [ { #category : 'enumerating' } CTArray2D >> neighborsAtColumnWrap: col atRowWrap: row [ - + "Answer a collection of exactly 8 elements surrounding the given origin, wrapping across grid boundaries where necessary. Throws an error if the starting origin coordinates are out of bounds." + | neighbors | (col between: 1 and: self width) ifFalse: [ self error: 'Column out of bounds' ].