Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save andriytyurnikov/c6b1207e6849cedf2082d9c837f23ac0 to your computer and use it in GitHub Desktop.
Save andriytyurnikov/c6b1207e6849cedf2082d9c837f23ac0 to your computer and use it in GitHub Desktop.
15 puzzle
# fifteen_puzzle.rb
require 'io/console'
class FifteenPuzzle
def initialize
start_new_game
end
def play
loop do
until solved?
display_board
process_input
end
display_board
puts "Congratulations! You solved the puzzle in #{@moves} moves!"
puts "Press 'R' to restart or 'Q' to quit"
case $stdin.getch.downcase
when 'r' then start_new_game
when 'q' then exit
end
end
end
private
def start_new_game
@tiles = generate_solved_board
@empty_position = [3, 3]
shuffle_board
@moves = 0
end
def generate_solved_board
tiles = []
(0..3).each do |i|
row = []
(0..3).each do |j|
value = i * 4 + j + 1
row << (value < 16 ? value : nil)
end
tiles << row
end
tiles
end
def shuffle_board
directions = [:up, :down, :left, :right]
256.times do
valid_moves = directions.select do |dir|
new_pos = calculate_new_position(dir)
valid_move?(new_pos)
end
direction = valid_moves.sample
new_position = calculate_new_position(direction)
swap_tiles(@empty_position, new_position)
@empty_position = new_position
end
end
def process_input
case $stdin.getch.downcase
when 'w' then try_move(:down)
when 's' then try_move(:up)
when 'a' then try_move(:right)
when 'd' then try_move(:left)
when 'r' then start_new_game
when 'q' then exit
end
end
def try_move(direction)
new_position = calculate_new_position(direction)
if valid_move?(new_position)
swap_tiles(@empty_position, new_position)
@empty_position = new_position
@moves += 1
else
puts "Invalid move!"
sleep(0.2)
end
end
def calculate_new_position(direction)
row, col = @empty_position
case direction
when :up then [row + 1, col]
when :down then [row - 1, col]
when :left then [row, col + 1]
when :right then [row, col - 1]
end
end
def valid_move?(position)
row, col = position
row.between?(0, 3) && col.between?(0, 3)
end
def swap_tiles(pos1, pos2)
r1, c1 = pos1
r2, c2 = pos2
@tiles[r1][c1], @tiles[r2][c2] = @tiles[r2][c2], @tiles[r1][c1]
end
def solved?
target = (1..15).to_a + [nil]
@tiles.flatten == target
end
def display_board
system('clear') || system('cls')
puts "\n15 PUZZLE\n"
puts
@tiles.each do |row|
puts row.map { |tile| tile.nil? ? ' ' : tile.to_s.rjust(2) }.join(' ')
end
puts "\nMoves: #{@moves}"
puts "Controls: WASD to move tiles, R to restart, Q to quit"
end
end
# Start the game
FifteenPuzzle.new.play
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment