Tic-Tac-Toe
Author |
Message |
rdrake
![](http://compsci.ca/v3/uploads/user_avatars/113417932472fc6c9cd916.png)
|
Posted: 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. |
|
|
|
|
![](images/spacer.gif) |
Sponsor Sponsor
![Sponsor Sponsor](templates/subSilver/images/ranks/stars_rank5.gif)
|
|
![](images/spacer.gif) |
wtd
|
Posted: Fri Dec 09, 2005 11:53 pm Post subject: (No subject) |
|
|
Now, rewrite it with some thought to separating logic and display code. |
|
|
|
|
![](images/spacer.gif) |
wtd
|
Posted: 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 |
|
|
|
|
|
![](images/spacer.gif) |
wtd
|
Posted: 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", " ", " "]] |
|
|
|
|
|
![](images/spacer.gif) |
rdrake
![](http://compsci.ca/v3/uploads/user_avatars/113417932472fc6c9cd916.png)
|
Posted: 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 |
|
|
|
|
|
![](images/spacer.gif) |
wtd
|
Posted: 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:
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. |
|
|
|
|
![](images/spacer.gif) |
|
|