Skip to content

Instantly share code, notes, and snippets.

@chtzvt
Last active December 7, 2024 19:37
Show Gist options
  • Save chtzvt/344db37fe23ae512b49ab2a37f58ff17 to your computer and use it in GitHub Desktop.
Save chtzvt/344db37fe23ae512b49ab2a37f58ff17 to your computer and use it in GitHub Desktop.
This is my snake game. There are many like it, but this one is mine.
# frozen_string_literal: true
require "bundler/inline"
gemfile do
source "https://rubygems.org"
gem "curses"
end
class Snake
ARENA_WIDTH = 40
ARENA_HEIGHT = 40
ARENA_RUNES = {
corner_top_left: "⌜",
corner_top_right: "⌝",
corner_bottom_left: "⌞",
corner_bottom_right: "⌟",
wall_top: "―",
wall_bottom: "―",
wall_left: "❘",
wall_right: "❘",
snake_head: "&",
snake_body: "#",
empty: " ",
target: "@"
}
def initialize
@score = 0
@current_direction = nil
@snake_pos = [ARENA_WIDTH / 2, ARENA_HEIGHT / 2]
@snake_body = []
place_targets
Curses.init_screen
Curses.noecho
Curses.curs_set(0)
Curses.timeout = 0
Signal.trap("INT") do
cleanup
end
end
def run
loop do
render_arena
scan_io
move_snake
break if collision?
sleep 0.2
end
cleanup
end
def cleanup
Curses.close_screen
puts "\nScore: #{@score}\nThanks for playing!"
exit
end
def place_targets
@targets = [[rand(1..ARENA_WIDTH - 2), rand(1..ARENA_HEIGHT - 2)]]
end
def cell_at(x, y)
return :target if @targets.include?([x, y])
if x == 0 && y == 0
:corner_top_left
elsif x == ARENA_WIDTH - 1 && y == 0
:corner_top_right
elsif x == 0 && y == ARENA_HEIGHT - 1
:corner_bottom_left
elsif x == ARENA_WIDTH - 1 && y == ARENA_HEIGHT - 1
:corner_bottom_right
elsif y == 0
:wall_top
elsif y == ARENA_HEIGHT - 1
:wall_bottom
elsif x == 0
:wall_left
elsif x == ARENA_WIDTH - 1
:wall_right
elsif @snake_pos == [x, y]
:snake_head
elsif @snake_body.include?([x, y])
:snake_body
else
:empty
end
end
def render_arena
Curses.clear
Curses.setpos(0, 0)
Curses.addstr("Score: #{@score}".ljust(ARENA_WIDTH))
(0...ARENA_HEIGHT).each do |y|
Curses.setpos(y + 1, 0)
row_str = +""
(0...ARENA_WIDTH).each do |x|
row_str << ARENA_RUNES[cell_at(x, y)]
end
Curses.addstr(row_str)
end
Curses.refresh
end
def scan_io
ch = Curses.getch
case ch
when "w"
@current_direction = :up
when "a"
@current_direction = :left
when "s"
@current_direction = :down
when "d"
@current_direction = :right
end
end
def move_snake
@snake_body.unshift(@snake_pos.dup)
case @current_direction
when :up
@snake_pos[1] -= 1
when :down
@snake_pos[1] += 1
when :left
@snake_pos[0] -= 1
when :right
@snake_pos[0] += 1
end
if @targets.include?(@snake_pos)
@score += 1
place_targets
else
@snake_body.pop
end
end
def collision?
[:corner_top_left, :corner_top_right, :corner_bottom_left,
:corner_bottom_right, :wall_top, :wall_bottom, :wall_left,
:wall_right].include?(cell_at(*@snake_pos))
end
end
Snake.new.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment