summaryrefslogtreecommitdiffstats
path: root/qtruby/rubylib/examples/qt-examples/tictac/tictac.rb
diff options
context:
space:
mode:
Diffstat (limited to 'qtruby/rubylib/examples/qt-examples/tictac/tictac.rb')
-rw-r--r--qtruby/rubylib/examples/qt-examples/tictac/tictac.rb311
1 files changed, 311 insertions, 0 deletions
diff --git a/qtruby/rubylib/examples/qt-examples/tictac/tictac.rb b/qtruby/rubylib/examples/qt-examples/tictac/tictac.rb
new file mode 100644
index 00000000..04ab8b9d
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/tictac/tictac.rb
@@ -0,0 +1,311 @@
+require 'Qt'
+
+class TicTacButton < Qt::PushButton
+
+ attr_accessor :btype
+
+ Blank, Circle, Cross = 0, 1, 2
+
+ def initialize(p)
+ super(p)
+ @btype = Blank
+ end
+
+ def drawButtonLabel(p)
+ r = rect()
+ p.setPen( Qt::Pen.new( Qt::white,2 ) ) # set fat pen
+ if (@btype == Circle)
+ p.drawEllipse( r.left()+4, r.top()+4, r.width()-8, r.height()-8 )
+ elsif (@btype == Cross) # draw cross
+ p.drawLine( r.topLeft() +Qt::Point.new(4,4), r.bottomRight()-Qt::Point.new(4,4))
+ p.drawLine( r.bottomLeft()+Qt::Point.new(4,-4),r.topRight() -Qt::Point.new(4,-4))
+ end
+ super(p)
+ end
+end
+
+class TicTacGameBoard < Qt::Widget
+ signals 'finished()'
+ slots 'buttonClicked()'
+
+ Init, HumansTurn, HumanWon, ComputerWon, NobodyWon = 0, 1, 2, 3, 4
+
+ attr_accessor :state, :computer_starts
+
+ def initialize (n, parent)
+ super(parent)
+ @state = Init
+ @nBoard = n
+ n = n*n
+ @computer_starts = false
+ @buttons = Array.new(n)
+ @btArray = Array.new(n)
+
+ grid = Qt::GridLayout.new(self, n, n, 4)
+ p = Qt::Palette.new(Qt::blue)
+
+ for i in (0..n-1)
+ ttb = TicTacButton.new(self)
+ ttb.setPalette(p)
+ ttb.setEnabled(false)
+ connect(ttb, SIGNAL('clicked()'), self, SLOT('buttonClicked()'))
+ grid.addWidget(ttb, i % @nBoard, i / @nBoard)
+ @buttons[i] = ttb
+ @btArray[i] = TicTacButton::Blank
+ end
+ end
+
+ def newGame
+ @state = HumansTurn
+ for i in 0..(@nBoard*@nBoard)-1
+ @btArray[i] = TicTacButton::Blank
+ end
+ if @computer_starts == true
+ computerMove
+ else
+ updateButtons
+ end
+ end
+
+ def updateButtons
+ for i in 0..(@nBoard*@nBoard)-1
+ if @buttons[i].btype != @btArray[i]
+ @buttons[i].btype = @btArray[i]
+ end
+ if @buttons[i].btype == TicTacButton::Blank
+ @buttons[i].setEnabled(true)
+ else
+ @buttons[i].setEnabled(false)
+ end
+ @buttons[i].repaint
+ end
+ end
+
+ def checkBoard
+ t = 0
+ row = 0
+ col = 0
+ won = false
+
+ # check horizontal
+ for row in 0..@nBoard-1
+ if won == true
+ break
+ end
+ t = @btArray[row*@nBoard]
+ if (t == TicTacButton::Blank)
+ next
+ end
+ col = 1
+ while ( (col < @nBoard) && (@btArray[row*@nBoard+col] == t) )
+ col += 1
+ end
+ if (col == @nBoard)
+ won = true
+ end
+ end
+
+ # check vertical
+ for col in 0..@nBoard-1
+ if won == true
+ break
+ end
+ t = @btArray[col]
+ if (t == TicTacButton::Blank)
+ next
+ end
+ row = 1
+ while ( (row < @nBoard) && (@btArray[row*@nBoard+col] == t) )
+ row += 1
+ end
+ if (row == @nBoard)
+ won = true
+ end
+ end
+
+ # check diagonal top left to bottom right
+ if (won == false)
+ t = @btArray[0]
+ if (t != TicTacButton::Blank)
+ i = 1;
+ while (i<@nBoard && (@btArray[i*@nBoard+i] == t))
+ i += 1
+ end
+ if (i == @nBoard)
+ won = true
+ end
+ end
+ end
+
+ # check diagonal bottom left to top right
+ if (won == false)
+ j = @nBoard-1
+ i = 0;
+ t = @btArray[i+j*@nBoard];
+ if (t != TicTacButton::Blank)
+ i += 1
+ j -= 1
+ while ( (i<@nBoard) && (@btArray[i+j*@nBoard] == t) )
+ i += 1
+ j -= 1
+ end
+ if (i == @nBoard)
+ won = true
+ end
+ end
+ end
+
+ if (won == false)
+ # no winner
+ t = 0
+ end
+
+ t
+ end
+
+ def computerMove
+ numButtons = @nBoard*@nBoard
+ altv = Array.new
+ stopHuman = -1
+ i = 0
+
+ for i in 0..numButtons-1 # try all positions
+ if @btArray[i] != TicTacButton::Blank # already a piece there
+ next
+ end
+
+ @btArray[i] = TicTacButton::Cross # test if computer wins
+ if (checkBoard == @btArray[i]) # computer will win
+ @state = ComputerWon
+ stopHuman = -1
+ break
+ end
+
+ @btArray[i] = TicTacButton::Circle # test if human wins
+ if (checkBoard == @btArray[i]) # oops...
+ stopHuman = i # remember position
+ @btArray[i] = TicTacButton::Blank # restore button
+ next # computer still might win
+ end
+ @btArray[i] = TicTacButton::Blank; # restore button
+ altv.push(i) # remember alternative
+ end
+
+ if (stopHuman >= 0) # must stop human from winning
+ @btArray[stopHuman] = TicTacButton::Cross
+ elsif (i == numButtons-1) # tried all alternatives
+ if (altv.size > 0) # set random piece
+ @btArray[altv[rand(altv.size)]] = TicTacButton::Cross
+ end
+ if ((altv.size-1) == 0) # no more blanks
+ @state = NobodyWon
+ emit finished()
+ end
+ end
+ updateButtons # update buttons
+ end
+
+ def buttonClicked
+ unless @state == HumansTurn
+ return
+ end
+
+ at = nil
+ for i in 0..@buttons.size
+ if @buttons[i].object_id == sender.object_id
+ at = i
+ break
+ end
+ end
+ if @btArray[at] == TicTacButton::Blank
+ @btArray[at] = TicTacButton::Circle
+ updateButtons
+
+ if (checkBoard == 0)
+ computerMove
+ end
+ s = checkBoard
+ if (s != 0)
+ if (s == TicTacButton::Circle)
+ @state = HumanWon
+ else
+ @state = ComputerWon
+ end
+ emit finished()
+ end
+ end
+ end
+
+end
+
+class TicTacToe < Qt::Widget
+ slots 'newGameClicked()', 'gameOver()'
+
+ def initialize (boardSize)
+ super()
+
+ l = Qt::VBoxLayout.new(self, 6)
+
+ @state_msg = [
+ 'Click Play to start',
+ 'Make your move',
+ 'You won!',
+ 'Computer won!',
+ 'It\'s a draw']
+
+ # Create a message label
+ @message = Qt::Label.new(self)
+ @message.setFrameStyle((Qt::Frame.WinPanel|Qt::Frame.Sunken))
+ @message.setAlignment(Qt::AlignCenter)
+ l.addWidget(@message)
+
+ # Create the game board and connect the signal finished()
+ # to this/self gameOver() slot
+ @board = TicTacGameBoard.new(boardSize, self)
+ connect(@board, SIGNAL('finished()'), self, SLOT('gameOver()'));
+ l.addWidget(@board)
+
+ # Create a horizontal frame line
+ line = Qt::Frame.new(self)
+ line.setFrameStyle(Qt::Frame.HLine|Qt::Frame.Sunken)
+ l.addWidget(line)
+
+ # Create the combo box for deciding who should start
+ # and connect its clicked() signals to the buttonClicked() slot
+ @whoStarts = Qt::ComboBox.new(self)
+ @whoStarts.insertItem('Computer starts')
+ @whoStarts.insertItem('Human starts')
+ l.addWidget(@whoStarts);
+
+ # Create the push buttons and connect their signals to the right slots
+ @newGame = Qt::PushButton.new('Play!', self)
+ connect(@newGame, SIGNAL('clicked()'), self, SLOT('newGameClicked()'))
+ @quit = Qt::PushButton.new('Quit', self)
+ connect(@quit, SIGNAL('clicked()'), $qApp, SLOT('quit()'))
+ b = Qt::HBoxLayout.new
+ l.addLayout(b)
+ b.addWidget(@newGame)
+ b.addWidget(@quit)
+
+ newState()
+ end
+
+ def newState
+ @message.setText(@state_msg[@board.state])
+ end
+
+ def newGameClicked
+ if @whoStarts.currentItem == 0
+ @board.computer_starts = true
+ else
+ @board.computer_starts = false
+ end
+ @board.newGame()
+ newState()
+ end
+
+ def gameOver
+ # Update text box
+ newState()
+ end
+end