Tetris contest
On the second workshop we were struggling on tetris contest.
Objective
We had one dedicated server. All of us divided by pairs were clients.
Every second server sends us a string containing current figure figure=O
, coordinates of the figure x=4
, y=20
, next 4 figures next=OOOO
and content of the glass glass=.{#{SIZE}}
.
"figure=O&x=4&y=20&glass= **** **** &next=OOOO"
Our clients had to respond a commands left=
or right=
then rotate=
and drop
separated by commas.
Instructions to run server locally described on codenjoy.com, source code located on GitHub. Client boilerplate for Ruby located on GitHub.
To start the server type $ java -jar start.jar
. The server starts at localhost:8080.
To run a client you have to install gem 'codenjoy_connection'
.
Then you need to register at localhost:8080
and type your name
, port
and host_ip
in client.rb.
Source code
# client.rb
require 'codenjoy_connection'
require_relative 'player'
host_ip = '127.0.0.1' # ip of host with running tetris-server
port = '8080' # this port is used for communication between your client and tetris-server
user = 'dml' # your username, use the same for registration on tetris-server
opts = { username: user, host: host_ip, port: port, game_url: 'ws?' }
player = Player.new
CodenjoyConnection.play(player, opts)
# player.rb
class Player
MAX_X = 10
MAX_Y = 20
SIZE = MAX_X * MAX_Y
# initialize your player
def initialize
# @x_glass -- straight (vertical standing) glass
@x_glass = Array.new(MAX_Y) { '' }
# @y_glass -- transposed (horizontal) glass
@y_glass = Array.new(MAX_X) { ' ' * MAX_Y }
end
# process data for each event from tetris-server
def process_data(data)
@figure = data[/figure=.+?/][7, 1].to_sym
@x = data[/x=\d+/][2, 2].to_i
@y = data[/y=\d+/][2, 2].to_i
@next = data[/next=\w{4}/][5, 4]
glass = data[/glass=.{#{SIZE}}/][6, 6 + SIZE]
MAX_Y.times { |y| @x_glass[y] = glass[y * MAX_X, MAX_X] }
MAX_X.times { |x| MAX_Y.times { |y| @y_glass[x][y] = @x_glass[y][x] } }
MAX_Y.times { |y| p @x_glass[MAX_Y - 1 - y] }
#MAX_X.times { |x| p @y_glass[x] }
end
# This method should return string like left=0, right=0, rotate=0, drop'
def make_step
case @figure
when :O then step_o
when :I then step_i
when :L then step_l
when :J then step_j
when :S then step_s
when :Z then step_z
when :T then step_t
end
end
private
#
# Find lowest level for block with given width
#
def find_lowest(width)
y = MAX_Y - 1
x = 0
# process every column and find first free cell
y_cur = @y_glass.map do |column|
i = column.reverse.index('*')
i ? MAX_Y - i : 0
end
# find continuous line with 'width' number of free cells
(MAX_X - width + 1).times do |x_cur|
if y_cur[x_cur..x_cur + width - 1].uniq.size == 1 && y_cur[x_cur] < y
y = y_cur[x_cur]
x = x_cur
end
end
# find not continuous line with 'width' number of free cells
(MAX_X - width + 1).times do |x_cur|
y_max = y_cur[x_cur..x_cur + width - 1].max
if y_max < y - 2
y = y_max
x = x_cur
end
end
# @x_glass.each_with_index do |row, y|
# (MAX_X)
# i = row.index(' ' * width)
# next if i.nil?
# next if @y_glass[i][y...MAX_Y].index('*')
# end
[x, y]
end
#
# Forming result string
#
def result_string(x, rotate = 0)
str = ''
if x < @x
str << "left=#{@x - x}, "
elsif x > @x
str << "right=#{x - @x}, "
end
str << "rotate=#{rotate}, " if rotate > 0
str << 'drop'
end
# Process O block
#
# **
# **
#
def step_o
x, y = find_lowest(2)
result_string(x)
end
# Process I block
#
# *
# *
# *
# *
#
def step_i
# Process vertical I block
x_vert, y_vert = find_lowest(1)
# Process horizontal I block
x_horiz, y_horiz = find_lowest(4)
if y_vert < y_horiz
result_string(x_vert)
else
result_string(x_horiz + 2, 1)
end
end
# Process L block
#
# *
# *
# **
#
def step_l
# Process rotate = 0
x_1, y_1 = find_lowest(2)
# Process rotate = 3
x_2, y_2 = find_lowest(3)
if y_1 < y_2
result_string(x_1)
else
result_string(x_2 + 1, 3)
end
end
# Process J block
#
# *
# *
# **
#
def step_j
# Process rotate = 0
x_1, y_1 = find_lowest(2)
# Process rotate = 1
x_2, y_2 = find_lowest(3)
if y_1 < y_2
result_string(x_1 + 1)
else
result_string(x_2 + 1, 1)
end
end
# Process S block
#
# **
# **
#
def step_s
x, y = find_lowest(2)
result_string(x + 1)
end
# Process Z block
#
# **
# **
#
def step_z
x, y = find_lowest(2)
result_string(x)
end
# Process T block
#
# *
# ***
#
def step_t
x, y = find_lowest(3)
result_string(x + 1)
end
end
Video
Source files are available on GitHub.