Skip to content

Instantly share code, notes, and snippets.

@amirrajan
Created September 15, 2019 21:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save amirrajan/896c4e60959b3ae27d7b7ab45a73e827 to your computer and use it in GitHub Desktop.
Save amirrajan/896c4e60959b3ae27d7b7ab45a73e827 to your computer and use it in GitHub Desktop.
Tic Tac Toe Written in DragonRuby Game Toolkit
#This sample app is a classic game of Tic Tac Toe.
class TicTacToe
attr_accessor :_, :state, :outputs, :inputs, :grid, :gtk
#Starts the game with player x's turn and creates an array for space combinations.
#Calls methods necessary for the game to run properly.
def tick
state.current_turn ||= :x
state.space_combinations = [-1, 0, 1].product([-1, 0, 1]).to_a
render_board
input_board
end
#Uses borders to create grid squares for the game's board. Also outputs the game pieces using labels.
def render_board
square_size = 80
board_left = grid.w_half - square_size * 1.5
board_top = grid.h_half - square_size * 1.5
outputs.borders << all_spaces do |x, y, space|
space.border ||= [
board_left + x.add(1) * square_size,
board_top + y.add(1) * square_size,
square_size,
square_size
]
end
outputs.labels << filled_spaces do |x, y, space|
label board_left + x.add(1) * square_size + square_size.fdiv(2),
board_top + y.add(1) * square_size + square_size - 20,
space.piece
end
#Uses a label to output whether x or o won, or if a draw occurred.
#If the game is ongoing, a label shows whose turn it currently is.
outputs.labels << if state.x_won
label grid.w_half, grid.top - 80, "x won"
elsif state.o_won
label grid.w_half, grid.top - 80, "o won"
elsif state.draw
label grid.w_half, grid.top - 80, "a draw"
else
label grid.w_half, grid.top - 80, "turn: #{state.current_turn}"
end
end
#Calls the methods responsible for handling user input and determining the winner.
#Does nothing unless the mouse is clicked.
def input_board
return unless inputs.mouse.click
input_place_piece
input_restart_game
determine_winner
end
#Handles user input for placing pieces on the board.
def input_place_piece
return if state.game_over
#Checks to find the space that the mouse was clicked inside of, and makes sure the space does not already
#have a piece in it.
__, __, space = all_spaces.find do |__, __, space|
inputs.mouse.click.point.inside_rect?(space.border) && !space.piece
end
#The piece that goes into the space belongs to the player whose turn it currently is.
return unless space
space.piece = state.current_turn
state.current_turn = state.current_turn == :x ? :o : :x
end
#Resets the game.
def input_restart_game
return unless state.game_over
gtk.reset
end
#Checks if x or o won the game.
#If neither player wins and all nine squares are filled, a draw happens.
#Once a player is chosen as the winner or a draw happens, the game is over.
def determine_winner
state.x_won = won? :x
state.o_won = won? :o
state.draw = true if filled_spaces.length == 9 && !state.x_won && !state.o_won
state.game_over = state.x_won || state.o_won || state.draw
end
#Determines if a player won by checking if there is a horizontal match or vertical match.
#Horizontal_match and vertical_match have boolean values. If either is true, the game has been won.
def won? piece
won = [[-1, 0, 1]].product([-1, 0, 1]).map do |xs, y|
horizontal_match = state.spaces[xs[0]][y].piece == piece &&
state.spaces[xs[1]][y].piece == piece &&
state.spaces[xs[2]][y].piece == piece
vertical_match = state.spaces[y][xs[0]].piece == piece &&
state.spaces[y][xs[1]].piece == piece &&
state.spaces[y][xs[2]].piece == piece
horizontal_match || vertical_match
end
won << (state.spaces[-1][-1].piece == piece &&
state.spaces[ 0][ 0].piece == piece &&
state.spaces[ 1][ 1].piece == piece)
won << (state.spaces[ 1][-1].piece == piece &&
state.spaces[ 0][ 0].piece == piece &&
state.spaces[-1][ 1].piece == piece)
won.reject_false.any?
end
#Defines filled spaces on the board by rejecting all spaces that do not have game pieces in them.
def filled_spaces
state.space_combinations
.reject { |x, y| !state.spaces[x][y].piece }
.map do |x, y|
if block_given?
yield x, y, state.spaces[x][y]
else
[x, y, state.spaces[x][y]]
end
end
end
#Defines all spaces on the board.
def all_spaces
if !block_given?
state.space_combinations.map do |x, y|
[x, y, state.spaces[x][y]]
end
else
state.space_combinations.map do |x, y|
yield x, y, state.spaces[x][y]
end
end
end
#Sets values for a label, such as the position, value, size, alignment, and color.
def label x, y, value
[x, y + 10, value, 20, 1, 0, 0, 0]
end
end
$tic_tac_toe = TicTacToe.new
def tick args
$tic_tac_toe._ = args
$tic_tac_toe.state = args.state
$tic_tac_toe.outputs = args.outputs
$tic_tac_toe.inputs = args.inputs
$tic_tac_toe.grid = args.grid
$tic_tac_toe.gtk = args.gtk
$tic_tac_toe.tick
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment