diff options
Diffstat (limited to 'qtruby/rubylib/examples/qt-examples/tictac/tictac.rb')
-rw-r--r-- | qtruby/rubylib/examples/qt-examples/tictac/tictac.rb | 311 |
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 |