![]() |
|
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 |
|
The Oblivious One
Join Date: May 2005
Location: Ontario, Canada
Posts: 641
Rep Power: 4
![]() |
[Ruby]Tic-Tac-Toe
I thought I'd learn Ruby a bit better by writing a short little tic-tac-toe game.
I have written the actual game, but it is not elegant. What I will do is post the file containing the classes I wrote to write the game. I know very few people here know Ruby, but comments would be great regardless. ![]() tictactoe.rb #!/usr/bin/env ruby
#Created by Jesse H-k on April 20, 2006
#Raised when more then 2 players are created.
class TooManyPlayersError < Exception
def initialize(message)
super(message)
end
end
#A player in a tic-tac-toe game.
class Player
@@x_taken = false
@@number = 0
def initialize
if (@@number += 1) > 2
raise TooManyPlayersError, "No more then 2 \"Player\" instances are allowed to be created."
end
if @@x_taken
@icon = 'O'
else
@icon = 'X'
@@x_taken = true
end
@wins, @losses = 0, 0
end
attr_reader :icon
attr_accessor :wins, :losses
end
# A board in a tic-tac-toe game.
class Board
def initialize
@spaces = [' '] * 9
@winner = nil
@filled = 0
end
#Make a move on the board. player must be an instance of the Player class, and is the player who
#is making the move. spot is the position on the board where the move is being made.
#example usage:
# board, player = Board.new, Player.new #create a board and player
# board.make_move(player, 3) #have player make a move on the space labeled 3
#
def make_move(player, spot)
if not (1..9) === spot
raise ArgumentError, "Invalid spot given. Spot must be [1-9]"
elsif not player.is_a?(Player)
raise TypeError, "player must be of \"Player\" class. Object of class \"%s\" provided." % player.class.to_s
elsif filled?(spot)
raise ArgumentError, "The spot (#{spot}) has been filled already!"
else
@spaces[spot - 1] = player.icon #place the player's icon on the spot
@filled += 1 #increase the number of filled spaces on the board
end
end
#return true if the board is full. false otherwise.
def full?
@filled == 9
end
#This method will calculate and return the winner (either "X", or "O").
#nil is returned when there is no winner.
def winner
#return the winner if has been already calculated. The serves 2 purposes:
# (1) Avoiding lots of unnecessary looping.
# (2) Only return the first winner. If two players eventually win, only the first to do so is returned.
return @winner if @winner != nil
['X', 'O'].each do |p| #for each icon
win = [p] * 3 #set the winning combination for each player
#rows
[0, 3, 6].each do |s| #the starting spots of any rows
if @spaces.slice(s..(s + 2)) == win #if the given row matches 3 icons of the player
return (@winner = p) #assign @winner and return the appropriate icon.
end
end
#see above
(0...3).each do |s|
if [@spaces[s], @spaces[s + 3], @spaces[s + 6]] == win
return (@winner = p)
end
end
#represents each diagonal on the board
[[0, 4, 8], [2, 4, 6]].each do |dia|
if dia.inject([]) { |result, elem| result << @spaces[elem] } == win
return (@winner = p)
end
end
end
nil
end
#Return a String representation of the board. An example could
#be the following:
#
# -----------
# X | |
# -----------
# | | X
# -----------
# O | |
# -----------
def to_s
result = '-' * 11
@spaces.join.scan(/.../).each do |triple|
result << "\n "
result << triple.scan(/./).join(' | ')
result << " \n"
result << "-" * 11
end
result
end
#Similar to Board#to_s, but will display a board above the actual board which indicates the position
#of the moves. The top and bottom of the string is padded with newlines.
#here is an example of its display:
#
# -----------
# 1 | 2 | 3
# -----------
# 4 | 5 | 6
# -----------
# 7 | 8 | 9
# -----------
#
# -----------
# X | |
# -----------
# | X |
# -----------
# O | |
# -----------
def display
#start with an empty board
empty = to_s.gsub(/( )(X|O)( )/, ' ' * 3)
#sequentialy fill the board with [1-9]
result += (1..9).inject(empty) { |result, x| result.sub(/ {3}/, " #{x} ") }
#append padding, add the board using to_s, and more padding.
result + "\n\n" + to_s + "\n\n"
end
#Reset the Board. This is required when starting a new game, or re-playing a previous one.
def reset
@spaces, @winner, @filled = [' '] * 9, nil, 0
end
#Return true if a spot is occupied by either Player. false otherwise.
def filled?(spot)
%w(X O).include?(@spaces[spot - 1])
end
endI tried to comment as best I could. ![]()
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS! |
|
|
|
![]() |
| Bookmarks |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|