home *** CD-ROM | disk | FTP | other *** search
/ ftp.ee.pdx.edu / 2014.02.ftp.ee.pdx.edu.tar / ftp.ee.pdx.edu / pub / users / harry / cse509 / TicTacToe.st < prev    next >
Text File  |  2002-02-25  |  14KB  |  441 lines

  1. Morph subclass: #TicTacToeMorph
  2.     instanceVariableNames: 'whoMovesNext winningLine squares selectedSquare highlightedSquare '
  3.     classVariableNames: 'HighlightOForm HighlightXForm OForm XForm '
  4.     poolDictionaries: ''
  5.     category: 'TicTacToe'!
  6. !TicTacToeMorph commentStamp: 'HHP 2/25/2002 11:41' prior: 0!
  7. Each instance of this class is a Morph that can be used to play the Tic-Tac-Toe game.  The Morph shows the Tic-Tac-Toe board, any X's and O's that have been played, a RESET button, and a QUIT button.  The user(s) will place both X's and O's by clicking on board squares; the computer does not participate as a player.
  8.  
  9. Instance Variables:
  10.     squares                an Array of 9 integers giving current board state: 0=empty; 1=X; 2=O
  11.     whoMovesNext        1=X moves next; 2=O moves next
  12.     winningLine        an integer, 1..8, telling which winning line; 0=no winner
  13.     selectedSquare        an integer, 1..11, giving which button has been mouse-down'ed
  14.     highlightedSquare    an integer, 1..11, telling which button should be highlighted
  15.  
  16. Class Variables:
  17.     XForm                a square Form showing the image of an X
  18.     OForm                a square Form showing the image of an O
  19.     HighlightXForm        a square Form showing the highlighted image of an X
  20.     HighlightOForm        a square Form showing the highlighted image of an O
  21.  
  22. Harry Porter - 02/24/02
  23. !
  24.  
  25.  
  26. !TicTacToeMorph methodsFor: 'accessing' stamp: 'HHP 2/23/2002 15:01'!
  27. highlightedSquare
  28.     ^ highlightedSquare! !
  29.  
  30. !TicTacToeMorph methodsFor: 'accessing' stamp: 'HHP 2/23/2002 15:01'!
  31. highlightedSquare: int
  32.     highlightedSquare _ int! !
  33.  
  34. !TicTacToeMorph methodsFor: 'accessing' stamp: 'HHP 2/23/2002 15:01'!
  35. selectedSquare
  36.     ^ selectedSquare! !
  37.  
  38. !TicTacToeMorph methodsFor: 'accessing' stamp: 'HHP 2/23/2002 15:01'!
  39. selectedSquare: int
  40.     selectedSquare _ int! !
  41.  
  42. !TicTacToeMorph methodsFor: 'accessing' stamp: 'HHP 2/23/2002 14:20'!
  43. squares
  44.     ^ squares! !
  45.  
  46. !TicTacToeMorph methodsFor: 'accessing' stamp: 'HHP 2/23/2002 14:20'!
  47. squares: arrayOfInt
  48.     squares _ arrayOfInt! !
  49.  
  50. !TicTacToeMorph methodsFor: 'accessing' stamp: 'HHP 2/23/2002 14:15'!
  51. whoMovesNext
  52.     ^ whoMovesNext! !
  53.  
  54. !TicTacToeMorph methodsFor: 'accessing' stamp: 'HHP 2/23/2002 14:14'!
  55. whoMovesNext: int
  56.     whoMovesNext _ int! !
  57.  
  58. !TicTacToeMorph methodsFor: 'accessing' stamp: 'HHP 2/23/2002 14:15'!
  59. winningLine
  60.     ^ winningLine! !
  61.  
  62. !TicTacToeMorph methodsFor: 'accessing' stamp: 'HHP 2/23/2002 14:14'!
  63. winningLine: int
  64.     winningLine _ int! !
  65.  
  66.  
  67. !TicTacToeMorph methodsFor: 'misc' stamp: 'HHP 2/24/2002 23:25'!
  68. checkGameOver
  69.  
  70. "This method checks to see if the game is over.  If there is a winner, it sets 'winningLine' to 1-8 to indicate which winning line to draw."
  71.  
  72.     | test |
  73.  
  74.     test _ [ :x :y :z :line |
  75.         (((squares at: x) = (squares at: y)) &
  76.         ((squares at: y) = (squares at: z)) &
  77.         ((squares at: x) ~= 0)) ifTrue: [
  78.             winningLine _ line.
  79.         ].
  80.     ].
  81.     test value: 1 value: 4 value: 7 value: 1.
  82.     test value: 2 value: 5 value: 8 value: 2.
  83.     test value: 3 value: 6 value: 9 value: 3.
  84.     test value: 1 value: 2 value: 3 value: 4.
  85.     test value: 4 value: 5 value: 6 value: 5.
  86.     test value: 7 value: 8 value: 9 value: 6.
  87.     test value: 1 value: 5 value: 9 value: 7.
  88.     test value: 3 value: 5 value: 7 value: 8.
  89. ! !
  90.  
  91. !TicTacToeMorph methodsFor: 'misc' stamp: 'HHP 2/24/2002 23:27'!
  92. drawOn: aCanvas
  93.  
  94. "This method draws the board in the current state.  The current state includes
  95.     -- Where there are X's and O's, as given by 'squares'
  96.     -- Whether there is anything highlighted, as given by highlightedSquare
  97.     -- Whose move is next, as given by whoMovesNext"
  98.  
  99.     | top bottom left right x1 x2 x3 y1 y2 y3 posOfSquares rect form |
  100.  
  101.     "Draw the background."
  102.     super extent: 128@188.
  103.     aCanvas
  104.         frameAndFillRectangle: bounds
  105.         fillColor: Color yellow
  106.         borderWidth: 4
  107.         topLeftColor: Color yellow darker 
  108.         bottomRightColor: Color yellow darker darker darker darker darker.
  109.  
  110.     "Draw the board's lines"
  111.     top _ bounds origin y + 14.
  112.     bottom _ bounds origin y + 112.
  113.     left _ bounds origin x + 14.
  114.     right _ bounds origin x + 112.
  115.     x1 _ bounds origin x + 46.
  116.     x2 _ bounds origin x + 81.
  117.     y1 _ bounds origin y + 46.
  118.     y2 _ bounds origin y + 81.
  119.     aCanvas line: x1@top to: x1@bottom width: 3 color: Color black.
  120.     aCanvas line: x2@top to: x2@bottom width: 3 color: Color black.
  121.     aCanvas line: left@y1 to: right@y1 width: 3 color: Color black.
  122.     aCanvas line: left@y2 to: right@y2 width: 3 color: Color black.
  123.  
  124.     "Draw the X's and the O's that have been placed so far."
  125.     posOfSquares _ self positionsOfSquares.
  126.     1 to: 9 do: [ :i |
  127.         ((squares at: i) = 1) ifTrue: [
  128.             aCanvas drawImage: XForm at: ((posOfSquares at: i) origin).
  129.         ] ifFalse: [((squares at: i) = 2) ifTrue: [
  130.             aCanvas drawImage: OForm at: ((posOfSquares at: i) origin).
  131.         ]].
  132.     ].
  133.  
  134.     "If any square is currently highlighted, draw it."
  135.     ((highlightedSquare > 0) & (highlightedSquare <= 9)) ifTrue: [
  136.         (whoMovesNext = 1) ifTrue: [
  137.             form _ HighlightXForm.
  138.         ] ifFalse: [
  139.             form _ HighlightOForm.
  140.         ].
  141.         aCanvas drawImage: form at: ((posOfSquares at: highlightedSquare) origin).
  142.     ].
  143.  
  144.     "Draw the winning line, if any."
  145.     x1 _ bounds origin x + 29.
  146.     x2 _ bounds origin x + 64.
  147.     x3 _ bounds origin x + 99.
  148.     y1 _ bounds origin y + 29.
  149.     y2 _ bounds origin y + 64.
  150.     y3 _ bounds origin y + 99.
  151.     (winningLine = 1) ifTrue: [
  152.         aCanvas line: x1@top to: x1@bottom width: 2 color: Color red.
  153.     ].
  154.     (winningLine = 2) ifTrue: [
  155.         aCanvas line: x2@top to: x2@bottom width: 2 color: Color red.
  156.     ].
  157.     (winningLine = 3) ifTrue: [
  158.         aCanvas line: x3@top to: x3@bottom width: 2 color: Color red.
  159.     ].
  160.     (winningLine = 4) ifTrue: [
  161.         aCanvas line: left@y1 to: right@y1 width: 2 color: Color red.
  162.     ].
  163.     (winningLine = 5) ifTrue: [
  164.         aCanvas line: left@y2 to: right@y2 width: 2 color: Color red.
  165.     ].
  166.     (winningLine = 6) ifTrue: [
  167.         aCanvas line: left@y3 to: right@y3 width: 2 color: Color red.
  168.     ].
  169.     (winningLine = 7) ifTrue: [
  170.         aCanvas line: left@top to: right@bottom width: 2 color: Color red.
  171.     ].
  172.     (winningLine = 8) ifTrue: [
  173.         aCanvas line: left@bottom to: right@top width: 2 color: Color red.
  174.     ].
  175.  
  176.     "Draw the RESET button, either normal or highlighted."
  177.     rect _ (bounds origin + (14@124)) extent: 100@20.
  178.     (highlightedSquare = 10) ifTrue: [
  179.         aCanvas
  180.             frameAndFillRectangle: rect
  181.             fillColor: Color red darker darker
  182.             borderWidth: 3
  183.             topLeftColor: Color red darker darker darker darker darker
  184.             bottomRightColor: Color red lighter.
  185.     ] ifFalse: [
  186.         aCanvas
  187.             frameAndFillRectangle: rect
  188.             fillColor: Color red lighter lighter
  189.             borderWidth: 3
  190.             topLeftColor: Color red lighter lighter lighter
  191.             bottomRightColor: Color red darker darker.
  192.     ].
  193.     aCanvas text: 'Reset' at: (rect origin + (35@4)) font: nil color: Color black.
  194.  
  195.     "Draw the QUIT button, either normal or highlighted."
  196.     rect _ (bounds origin + (14@154)) extent: 100@20.
  197.     (highlightedSquare = 11) ifTrue: [
  198.         aCanvas
  199.             frameAndFillRectangle: rect
  200.             fillColor: Color red darker darker
  201.             borderWidth: 3
  202.             topLeftColor: Color red darker darker darker darker darker
  203.             bottomRightColor: Color red lighter.
  204.     ] ifFalse: [
  205.         aCanvas
  206.             frameAndFillRectangle: rect
  207.             fillColor: Color red lighter lighter
  208.             borderWidth: 3
  209.             topLeftColor: Color red lighter lighter lighter
  210.             bottomRightColor: Color red darker darker.
  211.     ].
  212.     aCanvas text: 'Quit' at: (rect origin + (39@4)) font: nil color: Color black.
  213. ! !
  214.  
  215. !TicTacToeMorph methodsFor: 'misc' stamp: 'HHP 2/24/2002 23:27'!
  216. handlesMouseDown: evt
  217.  
  218. "Return true if the mouse is within one of the button areas.  Otherwise let the user drag the morph around."
  219.  
  220.     | mousePos posOfSquares |
  221.  
  222.     mousePos _ evt cursorPoint.
  223.     posOfSquares _ self positionsOfSquares.
  224.     posOfSquares withIndexDo: [ :rect :i |
  225.         (rect containsPoint: mousePos) ifTrue: [
  226.             ^ true
  227.         ].
  228.     ].
  229.     ^ false! !
  230.  
  231. !TicTacToeMorph methodsFor: 'misc' stamp: 'HHP 2/24/2002 23:16'!
  232. makeMove: i
  233.  
  234. "This method is passed a move to make (1-9).  It checks to see if this is a legal move and, if so, updates the data to make that move.  It also checks to see if the game is over."
  235.  
  236.     squares at: i put: whoMovesNext.
  237.     (whoMovesNext = 1) ifTrue: [
  238.         whoMovesNext _ 2.
  239.     ] ifFalse: [
  240.         whoMovesNext _ 1.
  241.     ].
  242.     self checkGameOver.
  243. ! !
  244.  
  245. !TicTacToeMorph methodsFor: 'misc' stamp: 'HHP 2/24/2002 23:31'!
  246. mouseDown: evt
  247.  
  248. "When the user presses the mouse button, see if it is in a square or one of the buttons.  If in a square, check to see if this would be a legal move, and return if not.  Highlight the square, by setting 'highlightedSquare' to the button number 1..11 and sending 'self changed'.  Also set 'selectedSquare' to this same number, to remember the focus."
  249.  
  250.     | mousePos posOfSquares |
  251.  
  252.     mousePos _ evt cursorPoint.
  253.     posOfSquares _ self positionsOfSquares.
  254.     posOfSquares withIndexDo: [ :rect :i |
  255.         (rect containsPoint: mousePos) ifTrue: [
  256.             (i <= 9) ifTrue: [
  257.                 ((squares at: i) = 0) ifTrue: [
  258.                     (winningLine ~= 0) ifTrue: [^self].
  259.                     selectedSquare _ i.
  260.                     highlightedSquare _ i.
  261.                 ].
  262.             ] ifFalse: [
  263.                 selectedSquare _ i.
  264.                 highlightedSquare _ i.
  265.             ].
  266.         ]
  267.     ].
  268.     self changed.! !
  269.  
  270. !TicTacToeMorph methodsFor: 'misc' stamp: 'HHP 2/24/2002 23:23'!
  271. mouseMove: evt
  272.  
  273. "The mouse has moved.  If the mouse is now in the 'selectedSquare', set 'highlightedSquare' to that same number.  Otherwise, set 'highlightedSquare' to zero."
  274.  
  275.     | mousePos oldHighlighted posOfSquares |
  276.  
  277.     oldHighlighted _ highlightedSquare.
  278.     highlightedSquare _ 0.
  279.     mousePos _ evt cursorPoint.
  280.     posOfSquares _ self positionsOfSquares.
  281.     posOfSquares withIndexDo: [ :rect :i |
  282.         (rect containsPoint: mousePos) ifTrue: [
  283.             (selectedSquare = i) ifTrue: [
  284.                 highlightedSquare _ i.
  285.             ].
  286.         ]
  287.     ].
  288.     (oldHighlighted = highlightedSquare) ifFalse: [
  289.         self changed.
  290.     ].
  291. ! !
  292.  
  293. !TicTacToeMorph methodsFor: 'misc' stamp: 'HHP 2/24/2002 23:24'!
  294. mouseUp: evt
  295.  
  296. "When the user releases the mouse button, see if it is in the 'selectedSquare'.  If so, make a move to that square, or do the button action, whichever is appropriate."
  297.  
  298.     | mousePos posOfSquares |
  299.  
  300.     mousePos _ evt cursorPoint.
  301.     posOfSquares _ self positionsOfSquares.
  302.     posOfSquares withIndexDo: [ :rect :i |
  303.         (rect containsPoint: mousePos) ifTrue: [
  304.             (selectedSquare = i) ifTrue: [
  305.                 (i <= 9) ifTrue: [
  306.                     self makeMove: i.
  307.                 ].
  308.                 (i = 10) ifTrue: [
  309.                     self resetState.
  310.                 ].
  311.                 (i = 11) ifTrue: [
  312.                     self delete.
  313.                 ].
  314.             ].
  315.         ]
  316.     ].
  317.     selectedSquare _ 0.
  318.     highlightedSquare _ 0.
  319.     self changed.! !
  320.  
  321. !TicTacToeMorph methodsFor: 'misc' stamp: 'HHP 2/24/2002 23:32'!
  322. positionsOfSquares
  323.  
  324. "Return an array of 11 rectangles.  Each describes the current position of one of the 9 squares or one of the two buttons."
  325.  
  326.     | a x1 x2 x3 y1 y2 y3 |
  327.  
  328.     x1 _ bounds origin x + 14.
  329.     x2 _ bounds origin x + 49.
  330.     x3 _ bounds origin x + 84.
  331.     y1 _ bounds origin y + 14.
  332.     y2 _ bounds origin y + 49.
  333.     y3 _ bounds origin y + 84.
  334.     a _ Array new: 11.
  335.     a at: 1 put: (x1@y1 extent: 30@30);
  336.         at: 2 put: (x2@y1 extent: 30@30);
  337.         at: 3 put: (x3@y1 extent: 30@30);
  338.         at: 4 put: (x1@y2 extent: 30@30);
  339.         at: 5 put: (x2@y2 extent: 30@30);
  340.         at: 6 put: (x3@y2 extent: 30@30);
  341.         at: 7 put: (x1@y3 extent: 30@30);
  342.         at: 8 put: (x2@y3 extent: 30@30);
  343.         at: 9 put: (x3@y3 extent: 30@30);
  344.         at: 10 put: ((bounds origin + (14@124)) extent: 100@20);        "RESET Button"
  345.         at: 11 put: ((bounds origin + (14@154)) extent: 100@20).        "QUIT Button"
  346.     ^ a
  347. ! !
  348.  
  349. !TicTacToeMorph methodsFor: 'misc' stamp: 'HHP 2/24/2002 23:32'!
  350. resetState
  351.  
  352. "Reset the state to a new game."
  353.  
  354.     whoMovesNext _ 1.                        "1=X; 2=O"
  355.     winningLine _ 0.                        "0=no winner yet; 1..8=various winning lines"
  356.     squares _ #(0 0 0 0 0 0 0 0 0) copy.        "0=empty; 1=X; 2=O"
  357.     highlightedSquare _ 0.                    "1-9=a square; 10=RESET button; 11=QUIT button"
  358.     selectedSquare _ 0.                        "1-9=a square; 10=RESET button; 11=QUIT button"
  359. ! !
  360.  
  361. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  362.  
  363. TicTacToeMorph class
  364.     instanceVariableNames: ''!
  365.  
  366. !TicTacToeMorph class methodsFor: 'misc' stamp: 'HHP 2/24/2002 23:42'!
  367. initialize
  368.  
  369. "Initialize the following class variables to appropriate Forms, in order to make displaying faster:
  370.     XForm
  371.     HighlightXForm
  372.     OForm
  373.     HighlightOForm"
  374.     
  375. "TicTacToeMorph initialize."
  376.  
  377.     | p dot aCircle |
  378.  
  379.     "Create the image of the 'X'."
  380.     XForm _ Form extent: 30@30 depth: 16.
  381.     XForm fill: XForm boundingBox rule: Form over fillColor: Color yellow.
  382.     p _ Pen newOnForm: XForm.
  383.     p color: Color green darker darker darker darker.
  384.     p roundNib: 3.
  385.     p goto: 2@2.
  386.     p down.
  387.     p goto: 26@26.
  388.     p up.
  389.     p goto: 2@26.
  390.     p down.
  391.     p goto: 26@2.
  392.  
  393.     "Create the highlighted image of the 'X'."
  394.     HighlightXForm _ Form extent: 30@30 depth: 16.
  395.     HighlightXForm fill: HighlightXForm boundingBox rule: Form over fillColor: Color yellow.
  396.     p _ Pen newOnForm: HighlightXForm.
  397.     p color: Color yellow darker darker.
  398.     p roundNib: 3.
  399.     p goto: 2@2.
  400.     p down.
  401.     p goto: 26@26.
  402.     p up.
  403.     p goto: 2@26.
  404.     p down.
  405.     p goto: 26@2.
  406.  
  407.     "Create the image of the 'O'."
  408.     OForm _ Form extent: 30@30 depth: 16.
  409.     OForm fill: OForm boundingBox rule: Form over fillColor: Color yellow.
  410.     dot _ Form extent: 3@3 depth: 16.
  411.     dot fill: dot boundingBox rule: Form over fillColor: Color blue darker darker darker darker.
  412.     aCircle _ Circle new.
  413.     aCircle form: dot.
  414.     aCircle radius: 14.
  415.     aCircle center: 13@13.
  416.     aCircle displayOn: OForm.
  417.  
  418.     "Create the highlighted image of the 'O'."
  419.     HighlightOForm _ Form extent: 30@30 depth: 16.
  420.     HighlightOForm fill: HighlightOForm boundingBox rule: Form over fillColor: Color yellow.
  421.     dot _ Form extent: 3@3 depth: 16.
  422.     dot fill: dot boundingBox rule: Form over fillColor: Color yellow darker darker.
  423.     aCircle _ Circle new.
  424.     aCircle form: dot.
  425.     aCircle radius: 14.
  426.     aCircle center: 13@13.
  427.     aCircle displayOn: HighlightOForm.
  428. ! !
  429.  
  430. !TicTacToeMorph class methodsFor: 'misc' stamp: 'HHP 2/24/2002 23:37'!
  431. new
  432.  
  433. "Create a new TicTacToeMorph and initialize it."
  434.  
  435.     | aTicTacToe |
  436.  
  437.     aTicTacToe _ super new.
  438.     aTicTacToe resetState.
  439.     ^ aTicTacToe! !
  440.  
  441. TicTacToeMorph initialize!