3

我正在 Pharo 中开发一个简单的棋盘游戏,我的棋盘上有一个方法可以将对象添加到单元格中。单元格只是对象上的点字典。

作为该方法的一部分,我想强制 Point 应该大于零,但小于板的宽度和高度,换句话说,它实际上应该在板上。做这个的最好方式是什么?

我目前的尝试如下所示:

at: aPoint put: aCell

((((aPoint x > self numberOfRows) 
    or: [aPoint x <= 0]) 
    or: [aPoint y > self numberOfColumns ]) 
    or: [aPoint y <= 0]) 
    ifTrue: [ self error:'The point must be inside the grid.' ].

self cells at: aPoint put: aCell .

所有这些括号有点口齿不清!or:但是我不能在不关闭每个表达式的情况下使用短路,因此它的计算结果是布尔值而不是块(或or:or:or:or:消息)。我可以改用二元运算符|并进行短路,但这似乎不对。

那么处理这个问题的正确的 Smalltalk 方式是什么?

4

3 回答 3

6

通常or:嵌套如下:

(aPoint x > self numberOfRows 
    or: [ aPoint x <= 0  
    or: [ aPoint y > self numberOfColumns
    or: [ aPoint y <= 0 ] ] ])
        ifTrue: [ self error: 'The point must be inside the grid.' ].

由于第一个参数的重复测试,您的嵌套是短循环但效率较低(检查字节码以查看差异)。

您可以使用assert:assert:description:在以下位置定义的替代方案Object

self
    assert: (aPoint x > self numberOfRows 
        or: [ aPoint x <= 0  
        or: [ aPoint y > self numberOfColumns
        or: [ aPoint y <= 0 ] ] ])
    description: 'The point must be inside the grid.'
于 2010-12-10T23:10:13.563 回答
4

任何时候事情的嵌套程度如此之深,是时候调用另一个方法了。

isValidPoint: aPoint
  aPoint x > self numberOfRows ifTrue: [^ false].
  aPoint x <= 0 ifTrue: [^ false].
  aPoint y > self numberOfColumns ifTrue: [^ false].
  aPoint y <= 0 ifTrue: [^ false].
  ^ true.

一般来说,你的方法应该是相对平坦的。如果没有,是时候重构了。

于 2010-12-11T22:23:29.170 回答
3

您可以简单地用范围内有效的所有点预填充“单元格”字典,即在初始化的某个位置放置:

1 to: numberOfRows do: [:y |
  1 to: numberOfCols do: [:x |
     cells at: x@y put: dummy "or nil " ] ]

那么您在给定点添加单元格的方法看起来很简单:

at: aPoint put: aCell

   self cells at: aPoint ifAbsent: [ self error: 'The point must be inside the grid.' ].
   self cells at: aPoint put: aCell .

还有一个辅助方法 #between:and: ,您可以使用它来最大程度地减少代码混乱:

((aPoint x between: 1 and: self numCols) and: [
 aPoint y between: 1 and: self numRows ]) ifFalse: [ ... bummer ... ]
于 2010-12-11T00:02:42.917 回答