Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 Tic-Tac-Toe
Index -> Programming, Ruby -> Ruby Submissions
View previous topic Printable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
rdrake




PostPosted: Fri Dec 09, 2005 11:27 pm   Post subject: Tic-Tac-Toe

Kinda messy code, but it works well. It's your basic tic-tac-toe game. Not much variation, just works the way it's suppost to.

code:
########################
## Tic-Tac-Toe        ##
## Dec. 9/05          ##
########################

# Declare variables
row_1  = [" ", " ", "1", " ", "|", " ", "2", " ", "|", " ", "3", " ", " "]
row_2  = [" ", " ", "4", " ", "|", " ", "5", " ", "|", " ", "6", " ", " "]
row_3  = [" ", " ", "7", " ", "|", " ", "8", " ", "|", " ", "9", " ", " "]
line   = "------------"
number = 1
piece  = "X"

# Main program loop
loop do
  # Draw the board
  row_1.each do |char|
    putc char
  end
  puts "\n#{line}"
  row_2.each do |char|
    putc char
  end
  puts "\n#{line}"
  row_3.each do |char|
    putc char
  end

  # Get player input
  puts "\nPlayer #{number}:  Where would you like to move? (1 - 9)\n"
  move = gets.chomp.to_i

  # Make sure they don't move over another piece
  if move < 4 then
    num = move * 4 - 2
    puts num
    if row_1[num] == "X" or row_1[num] == "O" then
      puts "Can't move there!"
      next;
    end
  elsif move > 3 and move < 7 then
    num = move * 4 - 14
    puts num
    if row_2[num] == "X" or row_2[num] == "O" then
      puts "Can't move there!"
      next;
    end
  elsif move > 6 and move < 10 then
    num = move * 4 - 26
    puts num
    if row_3[num] == "X" or row_3[num] == "O" then
      puts "Can't move there!"
      next;
    end
  end

  # Place piece if all is well
  if move == 1 then
    row_1[2] = piece
  elsif move == 2 then
    row_1[6] = piece
  elsif move == 3 then
    row_1[10] = piece
  elsif move == 4 then
    row_2[2] = piece
  elsif move == 5 then
    row_2[6] = piece
  elsif move == 6 then
    row_2[10] = piece
  elsif move == 7 then
    row_3[2] = piece
  elsif move == 8 then
    row_3[6] = piece
  elsif move == 9 then
    row_3[10] = piece
  end
 
  # Check for a winner
  if row_1[2] == "X" and row_1[6] == "X" and row_1[10] == "X" then
    puts "Player #{number} wins!"
    break;
  elsif row_1[2] == "O" and row_1[6] == "O" and row_1[10] == "O" then
    puts "Player #{number} wins!"
    break;
  elsif row_2[2] == "X" and row_2[6] == "X" and row_2[10] == "X" then
    puts "Player #{number} wins!"
    break;
  elsif row_2[2] == "O" and row_2[6] == "O" and row_2[10] == "O" then
    puts "Player #{number} wins!"
    break;
  elsif row_3[2] == "X" and row_3[6] == "X" and row_3[10] == "X" then
    puts "Player #{number} wins!"
    break;
  elsif row_3[2] == "O" and row_3[6] == "O" and row_3[10] == "O" then
    puts "Player #{number} wins!"
    break;
  ##########
  elsif row_1[2] == "X" and row_2[2] == "X" and row_3[2] == "X" then
    puts "Player #{number} wins!"
    break;
  elsif row_1[2] == "O" and row_2[2] == "O" and row_3[2] == "O" then
    puts "Player #{number} wins!"
    break;
  elsif row_1[6] == "X" and row_2[6] == "X" and row_3[6] == "X" then
    puts "Player #{number} wins!"
    break;
  elsif row_1[6] == "O" and row_2[6] == "O" and row_3[6] == "O" then
    puts "Player #{number} wins!"
    break;
  elsif row_1[10] == "X" and row_2[10] == "X" and row_3[10] == "X" then
    puts "Player #{number} wins!"
    break;
  elsif row_1[10] == "O" and row_2[10] == "O" and row_3[10] == "O" then
    puts "Player #{number} wins!"
    break;
  ##########
  elsif row_1[2] == "X" and row_2[6] == "X" and row_3[10] == "X" then
    puts "Player #{number} wins!"
    break;
  elsif row_1[2] == "O" and row_2[6] == "O" and row_3[10] == "O" then
    puts "Player #{number} wins!"
    break;
  elsif row_1[10] == "X" and row_2[6] == "X" and row_3[2] == "X" then
    puts "Player #{number} wins!"
    break;
  elsif row_1[10] == "O" and row_2[6] == "O" and row_3[2] == "O" then
    puts "Player #{number} wins!"
    break;
  elsif row_1[2] == "X" or row_1[2] == "O" and row_1[6] == "X" or row_1[6] == "O" and row_1[10] == "X" or row_1[10] == "O" and row_2[2] == "X" or row_2[2] == "O" and row_2[6] == "X" or row_2[6] == "O" and row_2[10] == "X" or row_2[10] == "O" and row_3[2] == "X" or row_3[2] == "O" and row_3[6] == "X" or row_3[6] == "O" and row_3[10] == "X" or row_3[10] == "O" then
    puts "No winner."
    break;
  end
 
  # Select next player
  if number == 2 then
    number = 1
    piece = "X"
  else
    number = 2
    piece = "O"
  end
end
If there's too many lines, I can put it in a file and attach it instead. Comments/suggestions are welcome.
Sponsor
Sponsor
Sponsor
sponsor
wtd




PostPosted: Fri Dec 09, 2005 11:53 pm   Post subject: (No subject)

Now, rewrite it with some thought to separating logic and display code.
wtd




PostPosted: Fri Dec 09, 2005 11:56 pm   Post subject: (No subject)

Some simple things while you ponder that...

code:
  # Draw the board
  puts row_1.join
  puts line
  puts row_2.join
  puts line
  puts row_3.join


Replaces:

code:
  # Draw the board
  row_1.each do |char|
    putc char
  end
  puts "\n#{line}"
  row_2.each do |char|
    putc char
  end
  puts "\n#{line}"
  row_3.each do |char|
    putc char
  end


code:
  # Place piece if all is well 
  if move == 1 then
    row_1[2] = piece
  elsif move == 2 then
    row_1[6] = piece
  elsif move == 3 then
    row_1[10] = piece
  elsif move == 4 then
    row_2[2] = piece
  elsif move == 5 then
    row_2[6] = piece
  elsif move == 6 then
    row_2[10] = piece
  elsif move == 7 then
    row_3[2] = piece
  elsif move == 8 then
    row_3[6] = piece
  elsif move == 9 then
    row_3[10] = piece
  end


Can be:

code:
  index = 2 + (move - 1) * 4
  case move
     when 1 .. 3
        row_1[index] = piece
     when 4 .. 6
        row_2[index] = piece
     when 7 .. 9
        row_3[index] = piece
  end
wtd




PostPosted: Sat Dec 10, 2005 12:18 am   Post subject: (No subject)

It's worth noting that you don't need three separate "row" variables. You can easily have:

code:
rows = [[" ", " ", "1", " ", "|", " ", "2", " ", "|", " ", "3", " ", " "],
        [" ", " ", "4", " ", "|", " ", "5", " ", "|", " ", "6", " ", " "],
        [" ", " ", "7", " ", "|", " ", "8", " ", "|", " ", "9", " ", " "]]
rdrake




PostPosted: Sat Dec 10, 2005 8:37 pm   Post subject: (No subject)

wtd wrote:
Now, rewrite it with some thought to separating logic and display code.
What exactly do you mean? Can you provide an example. I'm fairly new to Ruby still.

Here's a version with nicer classes instead of just random code.
code:
########################
## Tic-Tac-Toe        ##
## Dec. 9/05          ##
########################

class TTTGame
  def initialize
    # Declare variables
    @row_1  = [" ", " ", "1", " ", "|", " ", "2", " ", "|", " ", "3", " ", " "]
    @row_2  = [" ", " ", "4", " ", "|", " ", "5", " ", "|", " ", "6", " ", " "]
    @row_3  = [" ", " ", "7", " ", "|", " ", "8", " ", "|", " ", "9", " ", " "]
    line   = "------------"
    number = 1
    piece  = "X"
  end
  def drawBoard
    # Draw the board
    puts @row_1.join
    puts line
    puts @row_2.join
    puts line
    puts @row_3.join
  end
  def isWinner
  # Check for a winner
    if @row_1[2] == "X" and @row_1[6] == "X" and @row_1[10] == "X" then
      puts "Player #{number} wins!"
      break;
    elsif @row_1[2] == "O" and @row_1[6] == "O" and @row_1[10] == "O" then
      puts "Player #{number} wins!"
      break;
    elsif @row_2[2] == "X" and @row_2[6] == "X" and @row_2[10] == "X" then
      puts "Player #{number} wins!"
      break;
    elsif @row_2[2] == "O" and @row_2[6] == "O" and @row_2[10] == "O" then
      puts "Player #{number} wins!"
      break;
    elsif @row_3[2] == "X" and @row_3[6] == "X" and @row_3[10] == "X" then
      puts "Player #{number} wins!"
      break;
    elsif @row_3[2] == "O" and @row_3[6] == "O" and @row_3[10] == "O" then
      puts "Player #{number} wins!"
      break;
    elsif @row_1[2] == "X" and @row_2[2] == "X" and @row_3[2] == "X" then
      puts "Player #{number} wins!"
      break;
    elsif @row_1[2] == "O" and @row_2[2] == "O" and @row_3[2] == "O" then
      puts "Player #{number} wins!"
      break;
    elsif @row_1[6] == "X" and @row_2[6] == "X" and @row_3[6] == "X" then
      puts "Player #{number} wins!"
      break;
    elsif @row_1[6] == "O" and @row_2[6] == "O" and @row_3[6] == "O" then
      puts "Player #{number} wins!"
      break;
    elsif @row_1[10] == "X" and @row_2[10] == "X" and @row_3[10] == "X" then
      puts "Player #{number} wins!"
      break;
    elsif @row_1[10] == "O" and @row_2[10] == "O" and @row_3[10] == "O" then
      puts "Player #{number} wins!"
      break;
    elsif @row_1[2] == "X" and @row_2[6] == "X" and @row_3[10] == "X" then
      puts "Player #{number} wins!"
      break;
    elsif @row_1[2] == "O" and @row_2[6] == "O" and @row_3[10] == "O" then
      puts "Player #{number} wins!"
      break;
    elsif @row_1[10] == "X" and @row_2[6] == "X" and @row_3[2] == "X" then
      puts "Player #{number} wins!"
      break;
    elsif @row_1[10] == "O" and @row_2[6] == "O" and @row_3[2] == "O" then
      puts "Player #{number} wins!"
      break;
    elsif @row_1[2] == "X" or @row_1[2] == "O" and @row_1[6] == "X" or @row_1[6] == "O" and @row_1[10] == "X" or @row_1[10] == "O" and @row_2[2] == "X" or @row_2[2] == "O" and @row_2[6] == "X" or @row_2[6] == "O" and @row_2[10] == "X" or @row_2[10] == "O" and @row_3[2] == "X" or @row_3[2] == "O" and @row_3[6] == "X" or @row_3[6] == "O" and @row_3[10] == "X" or @row_3[10] == "O" then
      puts "No winner."
      break;
    end
  end
  def placePiece
    # Get player input
    puts "\nPlayer #{@number}:  Where would you like to move? (1 - 9)\n"
    move = gets.chomp.to_i
    # Make sure they don't move over another piece
    if move < 4 then
      num = move * 4 - 2
      if @row_1[num] == "X" or @row_1[num] == "O" then
        puts "Can't move there!"
        next;
      end
    elsif move > 3 and move < 7 then
      num = move * 4 - 14
      if @row_2[num] == "X" or @row_2[num] == "O" then
        puts "Can't move there!"
        next;
      end
    elsif move > 6 and move < 10 then
      num = move * 4 - 26
      if @row_3[num] == "X" or @row_3[num] == "O" then
        puts "Can't move there!"
        next;
      end
    end
    # Place piece
    @index = @move * 4 - 2
    case @move
      when 1 .. 3
          @row_1[index] = piece
      when 4 .. 6
          @index -= 12
          @row_2[index] = piece
      when 7 .. 9
          @index -= 24
          @row_3[index] = piece
    end
  end
  def changeTurn
    # Select next player
    if @number == 2 then
      @number = 1
      @piece = "X"
    else
      @number = 2
      @piece = "O"
    end
  end
end
# Main program loop
loop do
  game = TTTGame.new
  game.drawBoard
  game.placePiece
  game.isWinner
  game.changeTurn
end
wtd




PostPosted: Sat Dec 10, 2005 8:44 pm   Post subject: (No subject)

cartoon_shark wrote:
wtd wrote:
Now, rewrite it with some thought to separating logic and display code.
What exactly do you mean? Can you provide an example. I'm fairly new to Ruby still.


Thinking about tic-tac-toe, we have a 3x3 grid. We can easily represent that in Ruby as an array of three arrays. Elements in the array can have one of three values. The possibilities are X, O and Empty. They should all start off empty.

code:
X = 0
O = 1
EMPTY = nil

board = Array.new(3) { Array.new(3) { EMPTY } }


Now, we'd want to print this. So, let's define a new method to do this. Except we'll make it a bit more general and just have this generate a string representation of the board.

code:
def board_to_s(board)
   board.zip([0, 1, 2]).collect do |row, row_number|
      row.zip([0, 1, 2]).collect do |square, square_number|
         case square
            when X then "X"
            when O then "O"
            else row_number * 3 + square_number + 1             
         end
      end.join("|")
   end.join("-+-+-")
end


Now when we want to print a board, we can write:

code:
puts board_to_s(board)


But that's pretty redundant, so let's turn Board into a class. The initialize method will do the setup for us. The to_s method will do the same as our board_to_s method.

code:
class Board
   X = 0
   O = 1
   EMPTY = nil
   
   def initialize
      @board = Array.new(3) { Array.new(3) { EMPTY } }
   end
   
   def to_s
      @board.zip([0, 1, 2]).collect do |row, row_number|
         row.zip([0, 1, 2]).collect do |square, square_number|
            case square
               when X then "X"
               when O then "O"
               else row_number * 3 + square_number + 1             
            end
         end.join("|")
      end.join("-+-+-")
   end
end


And now we can:

code:
puts Board.new


And get:

code:
1|2|3
-+-+-
4|5|6
-+-+-
7|8|9


This is possible because the puts method automatically calls the to_s method on an object, and the new method of the Board class creates a new Board object.
Display posts from previous:   
   Index -> Programming, Ruby -> Ruby Submissions
View previous topic Tell A FriendPrintable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 1  [ 6 Posts ]
Jump to:   


Style:  
Search: