Ruby implementation of 2048 game
April 16, 2015
Ruby
Ruby Implementation of 2048 game
- Played in terminal.
- Control with arrow keys or vim-keybindings.
#!/usr/bin/ruby
require "io/console"
mar = Array.new(16, 0) # sheet value array
$score = 0
$target = 2048
$pieces = 0
def operate(mar, ran, gap)
mark = false
ran.each { |index|
ar = index.step(index + 3 * gap, gap).collect { |ind| ind}
tm_ar = ar.collect{|ie| mar[ie]}
pre_tm_ar = tm_ar.clone
tm_ar.delete_if{|item| item == 0}
(0..(tm_ar.size-1)).each {|ie|
if tm_ar[ie] == tm_ar[ie+1]
tm_ar[ie] *= 2
$score += tm_ar[ie]
tm_ar[ie+1] = 0
end
}
tm_ar.delete_if{|item| item == 0}
(4-tm_ar.size).times {
tm_ar << 0
}
tm_ar.size.times {|item|
mar[ar[item]] = tm_ar[item]
}
mark = true if tm_ar != pre_tm_ar
}
mark
end
def myloop(mar, a_pos, gap)
a_pos.each{|item|
3.times {|i|
if mar[item+i*gap] == mar[item+i*gap+gap]
return true
end
}
}
false
end
def judge_lose_full(mar)
ro = [0, 4, 8, 12]
col = [0, 1, 2, 3]
!myloop(mar, ro, 1) && !myloop(mar, col, 4)
end
def lose?(mar)
cnt = mar.count(0)
return cnt == 0 ? judge_lose_full(mar) : false
end
def win?(mar)
max_value = mar.sort[-1]
return max_value == 2048 ? true : false
end
def genera_num(mar)
r_pos = Random.new # get pos random seed
ran = [2, 4] # generate random new value
pos = r_pos.rand(16)
while mar[pos] != 0
r_pos = Random.new
pos = r_pos.rand(16)
end
r_val = Random.new
val = r_val.rand(2)
mar[pos] = ran[val]
end
def move?(mar, ba_r)
val = ba_r.collect{|i| mar[i]}
val.count(0) > 0 ? true : false
end
def add(mar, direc)
mark = false;
case
when direc == "j" || direc == "\e[B"
mark = (operate(mar, Array(12..15), -4) || move?(mar, Array(12..15))) #j
when direc == "k" || direc == "\e[A"
mark = (operate(mar, Array(0..3), 4) || move?(mar, Array(0..3))) #k
when direc == "h" || direc == "\e[D"
mark = (operate(mar, [0, 4, 8, 12], 1) || move?(mar, [0, 4, 8, 12])) #h
when direc == "l" || direc == "\e[C"
mark = (operate(mar, [3, 7, 11, 15], -1) || move?(mar, [3, 7 ,11, 15])) #l
end
if mark
genera_num(mar)
$pieces += 1
end
end
# print sheet
def sheet(mar)
printf("%s\n", "I am a vimer. So you can use vim-keybindings -.-")
printf("%s\n", "You can also use direction keys...")
puts "Besides, press 'q' or 'ESC' to quit."
printf("\n\n target = %-4d pieces = %-4d score = %-4d\n", $target, $pieces, $score)
printf("\n%s%s\n", " " * 5, "~" * 35)
printf("%s%s\n\n", " " * 5, "~" * 35)
printf("%s%s%s\n%s", " " * 8 + "/", ("-" * 6 + "+") * 3,
"-" * 6 + "\\", " " * 8)
16.times { |i|
if mar[i] != 0
printf("|%5d ", mar[i])
else
printf("|%5s ", " ")
end
if (i+1) % 4 == 0
printf("|\n")
if (i+1) != 16
printf("%s%s%s\n%s", " " * 8 + "|", ("-" * 6 + "+") * 3,
"-" * 6 + "|", " " * 8)
else
printf("%s%s%s\n%s", " " * 8 + "\\", ("-" * 6 + "+") * 3,
"-" * 6 + "/", " " * 8)
end
end
}
printf("\n%s%s\n", " " * 5, "~" * 35)
printf("%s%s\n\n", " " * 5, "~" * 35)
end
def read_char
STDIN.echo = false
STDIN.raw!
input = STDIN.getc.chr
if input == "\e"
input << STDIN.read_nonblock(3) rescue nil
input << STDIN.read_nonblock(2) rescue nil
end
ensure
STDIN.echo = true
STDIN.cooked!
return input
end
genera_num(mar)
$pieces += 1
system "clear"
while true
sheet(mar)
direc = read_char
if direc == "q" || direc == "\e" || direc == "\u0003"
break
end
add(mar, direc)
system "clear"
sheet(mar)
if win?(mar)
puts "Congratulations! You Win!"
break
end
if lose?(mar)
puts "Sorry, You are a loser..."
break
end
system "clear"
end
This is what you will see:
Source code on Github