[squeak-dev] The Inbox: TicTacToe-Game-MJK.5.mcz

commits at source.squeak.org commits at source.squeak.org
Wed Jun 12 15:02:02 UTC 2013


A new version of TicTacToe-Game was added to project The Inbox:
http://source.squeak.org/inbox/TicTacToe-Game-MJK.5.mcz

==================== Summary ====================

Name: TicTacToe-Game-MJK.5
Author: MJK
Time: 6 January 2009, 12:30:01 am
UUID: d6b2b9aa-8ea7-c444-a102-eeedf20d219d
Ancestors: TicTacToe-Game-MJK.4

Added window title.

==================== Snapshot ====================

SystemOrganization addCategory: #'TicTacToe-Game'!

BorderedMorph subclass: #TTTBoard
	instanceVariableNames: 'board logic cellWidth cellHeight win'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'TicTacToe-Game'!

!TTTBoard commentStamp: 'MJK 1/5/2009 03:05' prior: 0!
Implements a game board and connects game logic and all pieces of the board together. Use command:

	TTTBoard new openInWindow.

To start the game.!

----- Method: TTTBoard>>initialize (in category 'initialization') -----
initialize

	super initialize.
	
	logic := TTTLogic new.

	cellHeight := 64.	
	cellWidth := 64.
	
	self borderWidth: 2.
	self borderColor: Color black.
	self color: Color darkGray.
	self height: cellHeight * 3 + 4.
	self width: cellWidth * 3 + 4.
	board := Matrix new: 3 tabulate: [:y :x | self setCellAt: y at: x logic: logic].
	logic board: board.
!

----- Method: TTTBoard>>openInWindow (in category 'initialization') -----
openInWindow

	win := SystemWindow new.
	win setLabel: 'Tic Tac Toe'.
	win addMorph: self frame: (0.0 @ 0.0 extent: 1.0 @ 1.0).
	win openInWorld.
	win width: 64 * 3 + 4 + 10.
	win height: 64 * 3 + 4 + 30.
	win removeCornerGrips.
!

----- Method: TTTBoard>>setCellAt:at:logic: (in category 'helper') -----
setCellAt: y at: x logic: gameLogic
	"Creates a new cell object for given location and sends game logic handler to the cell."

	| c |

	logic := gameLogic.
	
	c := TTTCell new.
	c width: cellWidth.
	c height: cellHeight.
	c logic: logic.
	self addMorph: c.
	c position: ((x - 1) * c width + 2) @ ((y - 1) * c height + 2).
	c addMouseUpActionWith: 'logic actionAt:', y printString, ' at: ', x printString.

	^c.
!

BorderedMorph subclass: #TTTCell
	instanceVariableNames: 'cellValue logic'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'TicTacToe-Game'!

!TTTCell commentStamp: 'MJK 10/11/2008 23:08' prior: 0!
Implements a cell component for the game board.!

----- Method: TTTCell>>initialize (in category 'initialization') -----
initialize

	super initialize.
	self borderWidth: 1.
	self borderColor: Color black.
	self color: Color lightGray.
	self value: 0.
!

----- Method: TTTCell>>logic (in category 'accessing') -----
logic

	^logic.
!

----- Method: TTTCell>>logic: (in category 'accessing') -----
logic: gameLogic

	logic := gameLogic.
!

----- Method: TTTCell>>value (in category 'accessing') -----
value

	^cellValue.
!

----- Method: TTTCell>>value: (in category 'accessing') -----
value: value
	"Set value to 0 to clear the cell.
	 Set value to 1 to set human player move.
	 Set value to 10 to set computer player move."
	
	cellValue := value.
	(value = 1) ifTrue: [self color: Color blue].
	(value = 10) ifTrue: [self color: Color red].
	(value = 100) ifTrue: [self color: Color black].
	(value = 0) ifTrue: [self color: Color lightGray].
!

Object subclass: #TTTLogic
	instanceVariableNames: 'board'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'TicTacToe-Game'!

!TTTLogic commentStamp: 'MJK 10/11/2008 23:09' prior: 0!
The game logic. Includes management for moves made by a human and computer player and also takes care of checking the game state and handles computer moves.!

----- Method: TTTLogic>>actionAt:at: (in category 'game logic') -----
actionAt: y at: x
	"Accept user move, check if the game is over, make machine move."

	(self isCellEmptyAt: y at: x) ifFalse: [^false].

	self cellValue: 1 at: y at: x.

	(self checkVictory) ifTrue: [^true].
	
	(self doComputerMove) ifFalse: [self setVinner: 100. ^false].

	(self checkVictory) ifTrue: [^true].
!

----- Method: TTTLogic>>board (in category 'accessing') -----
board

	^board.
!

----- Method: TTTLogic>>board: (in category 'accessing') -----
board: gameBoard

	board := gameBoard.
!

----- Method: TTTLogic>>calculateCellValueAt:at: (in category 'game logic') -----
calculateCellValueAt: y at: x
	"Calculates cell value for a given cell. This value determines, which cell is the best
	 for the next move made by the computer."

	"
	Rules:
	
	Returns...
	4 points: computer will have a full row with this move
	3 points: human will have a full row with this move
	2 points: computer will have a full row in two moves
	1 point: everything else
	0 points: cell not available
	"

	| i |

	"Check if the cell is already taken."
	(self isCellEmptyAt: y at: x) ifFalse: [^0].
	
	((x = 1) & (y = 1)) ifTrue: [
		i := (self pickLargestOf: (self calculateDiagonal: 1) of: (self calculateRow: y) of: (self calculateColumn: x))
	].
	((x = 2) & (y = 1)) ifTrue: [
		i := (self pickLargestOf: (self calculateRow: y) of: (self calculateColumn: x))
	].
	((x = 3) & (y = 1)) ifTrue: [
		i := (self pickLargestOf: (self calculateDiagonal: -1) of: (self calculateRow: y) of: (self calculateColumn: x))
	].
	((x = 1) & (y = 2)) ifTrue: [
		i := (self pickLargestOf: (self calculateRow: y) of: (self calculateColumn: x))
	].
	((x = 2) & (y = 2)) ifTrue: [
		i := (self pickLargestOf: (self calculateRow: y) of: (self calculateColumn: x))
	].
	((x = 3) & (y = 2)) ifTrue: [
		i := (self pickLargestOf: (self calculateRow: y) of: (self calculateColumn: x))
	].
	((x = 1) & (y = 3)) ifTrue: [
		i := (self pickLargestOf: (self calculateDiagonal: -1) of: (self calculateRow: y) of: (self calculateColumn: x))
	].
	((x = 2) & (y = 3)) ifTrue: [
		i := (self pickLargestOf: (self calculateRow: y) of: (self calculateColumn: x))
	].
	((x = 3) & (y = 3)) ifTrue: [
		i := (self pickLargestOf: (self calculateDiagonal: 1) of: (self calculateRow: y) of: (self calculateColumn: x))
	].

	(i = 20) ifTrue: [^4].	"Computer may win at next move!!"
	(i = 2) ifTrue: [^4].	"Human may win at next move!!"
	(i = 10) ifTrue: [^3].	"Computer has one, human has none."
	(i = 1) ifTrue: [^2].	"Human has one at otherwise empty row."
	(i = 11) ifTrue: [^1].	"Human has one, computer has one."

	^1.
!

----- Method: TTTLogic>>calculateColumn: (in category 'helper') -----
calculateColumn: x
	"Adds all cells from the given column and returns the result."

	| result |

	((x < 1) | (x > 3)) ifTrue: [^-1].

	result := (self cellValueAt: 1 at: x) + (self cellValueAt: 2 at: x) + (self cellValueAt: 3 at: x).
	
	^result.
!

----- Method: TTTLogic>>calculateDiagonal: (in category 'helper') -----
calculateDiagonal: i
	"Adds all cells diagonally and returns the result.
	i = 1 --> from top left to lower right
	i = -1 --> from top right to lower left,"

	| result |

	result := -1.

	(i = 1) ifTrue: [result := (self cellValueAt: 1 at: 1) + (self cellValueAt: 2 at: 2) + (self cellValueAt: 3 at: 3)].
	(i = -1) ifTrue: [result := (self cellValueAt: 1 at: 3) + (self cellValueAt: 2 at: 2) + (self cellValueAt: 3 at: 1)].

	^result.
!

----- Method: TTTLogic>>calculateRow: (in category 'helper') -----
calculateRow: y
	"Adds all cells from the given row and returns the result."

	| result |

	((y < 1) | (y > 3)) ifTrue: [^-1].

	result := (self cellValueAt: y at: 1) + (self cellValueAt: y at: 2) + (self cellValueAt: y at: 3).
	
	^result.
!

----- Method: TTTLogic>>cellValue:at:at: (in category 'accessing') -----
cellValue: value at: y at: x

	(board at: y at: x) value: value.
!

----- Method: TTTLogic>>cellValueAt:at: (in category 'accessing') -----
cellValueAt: y at: x

	| retval |
	
	retval := (board at: y at: x) value.
	
	^retval.
!

----- Method: TTTLogic>>checkVictory (in category 'game logic') -----
checkVictory

	| result |
	
	"8 different possibilities for victory:"

	"Rows:"
	
	 1 to: 3 do: [:j |
		result := 0.
		result := self calculateRow: j.
		(result = 3) ifTrue: [self setVinner: 1. ^true].
		(result = 30) ifTrue: [self setVinner: 10. ^true].
	].

	"Columns:"
	1 to: 3 do: [:i |
		result := 0.
		result := self calculateColumn: i.
		(result = 3) ifTrue: [self setVinner: 1. ^true].
		(result = 30) ifTrue: [self setVinner: 10. ^true].
	].

	"Diagonals:"
	result := 0.
	result := self calculateDiagonal: 1.
	(result = 3) ifTrue: [self setVinner: 1. ^true].
	(result = 30) ifTrue: [self setVinner: 10. ^true].
	result := 0.
	result := self calculateDiagonal: -1.
	(result = 3) ifTrue: [self setVinner: 1. ^true].
	(result = 30) ifTrue: [self setVinner: 10. ^true].

	^false
!

----- Method: TTTLogic>>doComputerMove (in category 'game logic') -----
doComputerMove
	"This calculates the best possible move for the computer."

	| x y result pointMatrix |

	pointMatrix := Matrix new: 3 tabulate: [:j :i | self calculateCellValueAt: j at: i].

	result := 0.
	x := -1.
	y := -1.

	1 to: 3 do: [:j |
		1 to: 3 do: [:i |
			((pointMatrix at: j at: i) > result) ifTrue: [
				result := pointMatrix at: j at: i.
				x := i.
				y := j.]
		].
	].

	((x = -1) | (y = -1)) ifTrue: [^false].

	self cellValue: 10 at: y at: x.

	^true.
!

----- Method: TTTLogic>>isCellEmptyAt:at: (in category 'helper') -----
isCellEmptyAt: y at: x

	((board at: y at: x) value == 0) ifTrue: [^true].
	
	^false.
!

----- Method: TTTLogic>>isEmptyCells (in category 'helper') -----
isEmptyCells

	| result |

	result := false.
		
	1 to: 3 do: [:y |
		1 to: 3 do: [:x |
			(self isCellEmptyAt: y at: x) ifTrue: [result := true].
		].
	].

	^result.
!

----- Method: TTTLogic>>pickLargestOf:of: (in category 'helper') -----
pickLargestOf: a of: b
	"Returns the largest value of the given a, b and c."

	"Exception: if human is winning (2 == opponent has two cells in a row) then forget
	strategy and try to stop it."
	((a = 2) | (b = 2)) ifTrue: [^2].

	(a > b) ifTrue: [^a].
	(b > a) ifTrue: [^b].

	^a.
!

----- Method: TTTLogic>>pickLargestOf:of:of: (in category 'helper') -----
pickLargestOf: a of: b of: c
	"Returns the largest value of the given a, b and c."

	"Exception: if human is winning (2 == opponent has two cells in a row) then forget
	strategy and try to stop it."
	((a = 2) | (b = 2) | (c = 2)) ifTrue: [^2].
	
	(a > b) ifTrue: [(a > c) ifTrue: [^a] ifFalse: [^c]] ifFalse: [(b > c) ifTrue: [^b] ifFalse: [^c]].
	(b > c) ifTrue: [(b > a) ifTrue: [^b] ifFalse: [^a]] ifFalse: [(c > a) ifTrue: [^c] ifFalse: [^a]].
	(c > a) ifTrue: [(c > b) ifTrue: [^c] ifFalse: [^b]] ifFalse: [(a > b) ifTrue: [^a] ifFalse: [^b]].
	
	^a.
!

----- Method: TTTLogic>>setVinner: (in category 'helper') -----
setVinner: value

	1 to: 3 do: [:y |
		1 to: 3 do: [:x |
			(board at: y at: x) value: value.
		].
	].
!



More information about the Squeak-dev mailing list