#!/usr/bin/env python import sys import select import tty import termios import random import os import time import fcntl if (sys.hexversion >> 16) >= 0x202: FCNTL = fcntl else: import FCNTL import contextlib PLAYFIELD_W = 10 PLAYFIELD_H = 20 PLAYFIELD_X = 30 PLAYFIELD_Y = 1 BORDER_COLOR = 'yellow' HELP_X = 58 HELP_Y = 1 HELP_COLOR = 'cyan' SCORE_X = 1 SCORE_Y = 2 SCORE_COLOR = 'green' NEXT_X = 14 NEXT_Y = 11 GAMEOVER_X = 1 GAMEOVER_Y = PLAYFIELD_H + 3 INITIAL_MOVE_DOWN_DELAY = 1.0 DELAY_FACTOR = 0.8 LEVEL_UP = 20 NEXT_EMPTY_CELL = " " PLAYFIELD_EMPTY_CELL = " ." FILLED_CELL = "[]" class TetrisScreen: def __init__(self): self.s = '' self.no_color = False self.color = { 'red': 1, 'green': 2, 'yellow': 3, 'blue': 4, 'fuchsia': 5, 'cyan': 6, 'white': 7 } def xyprint(self, x, y, s): self.s += "\x1b[{0};{1}H{2}".format(y, x, s) def flush(self): sys.stdout.write(self.s) sys.stdout.flush() self.s = '' def puts(self, s): self.s += s def clear_screen(self): self.s += "\x1b[2J" def show_cursor(self): self.s += "\x1b[?25h" def hide_cursor(self): self.s += "\x1b[?25l" def set_fg(self, c): if self.no_color: return self.s += "\x1b[3{0}m".format(self.color.get(c, 7)) def set_bg(self, c): if self.no_color: return self.s += "\x1b[4{0}m".format(self.color.get(c, 7)) def reset_colors(self): self.s += "\x1b[0m" def set_bold(self): self.s += "\x1b[1m" def get_random_color(self): k = list(self.color.keys()) random.shuffle(k) return k[0] def toggle_color(self): self.no_color ^= True class TetrisScreenItem(object): def __init__(self, screen): self.visible = True self.screen = screen def show(self): if self.visible: self.draw(True) def hide(self): if self.visible: self.draw(False) def toggle(self): self.visible ^= True self.draw(self.visible) class TetrisHelp(TetrisScreenItem): def __init__(self, screen): super(TetrisHelp, self).__init__(screen) self.color = HELP_COLOR self.text = [ " Use cursor keys", " or", " s: rotate", "a: left, d: right", " space: drop", " q: quit", " c: toggle color", "n: toggle show next", "h: toggle this help" ] def draw(self, visible): self.screen.set_bold() self.screen.set_fg(self.color) i = 0 for s in self.text: if not visible: s = ' ' * len(s) self.screen.xyprint(HELP_X, HELP_Y + i, s) i += 1 self.screen.reset_colors() class TetrisPlayField: def __init__(self, screen): self.screen = screen self.cells = [[None] * PLAYFIELD_W for i in range(0, PLAYFIELD_H)] def show(self): y = 0 for row in self.cells: self.screen.xyprint(PLAYFIELD_X, PLAYFIELD_Y + y, "") y += 1 for cell in row: if cell == None: self.screen.puts(PLAYFIELD_EMPTY_CELL) else: self.screen.set_fg(cell) self.screen.set_bg(cell) self.screen.puts(FILLED_CELL) self.screen.reset_colors() def flatten_piece(self, piece): for cell in piece.get_cells(): self.cells[cell[1]][cell[0]] = piece.color def process_complete_lines(self): cells = [row for row in self.cells if None in row] complete_lines = PLAYFIELD_H - len(cells) if complete_lines > 0: self.cells = [[None] * PLAYFIELD_W for i in range(0, complete_lines)] + cells return complete_lines def draw_border(self): self.screen.set_bold() self.screen.set_fg(BORDER_COLOR) for y in range(0, PLAYFIELD_H): # 2 because border is 2 characters thick self.screen.xyprint(PLAYFIELD_X - 2, PLAYFIELD_Y + y, "<|") # 2 because each cell on play field is 2 characters wide self.screen.xyprint(PLAYFIELD_X + PLAYFIELD_W * 2, PLAYFIELD_Y+ y, "|>") y = 0 for s in ['==', '\/']: self.screen.xyprint(PLAYFIELD_X, PLAYFIELD_Y + PLAYFIELD_H + y, s * PLAYFIELD_W) y += 1 self.screen.reset_colors() def position_ok(self, cells): return all( (0 <= x < PLAYFIELD_W) and (0 <= y < PLAYFIELD_H) and self.cells[y][x] is None for x, y in cells ) class TetrisPiece(TetrisScreenItem): configurations = [ # 0123 # 4567 # 89ab # cdef [0x1256], # square [0x159d, 0x4567], # line [0x4512, 0x0459], # s [0x0156, 0x1548], # z [0x159a, 0x8456, 0x0159, 0x2654], # l [0x1598, 0x0456, 0x2159, 0xa654], # inverted l [0x1456, 0x1596, 0x4569, 0x4159] # t ] def __init__(self, screen, origin, visible): super(TetrisPiece, self).__init__(screen) self.color = screen.get_random_color() self.data = random.choice(self.configurations) self.symmetry = len(self.data) self.position = 0, 0, random.randint(0, self.symmetry - 1) self.origin = origin self.visible = visible self.empty_cell = NEXT_EMPTY_CELL def get_cells(self, new_position=None): x, y, z = new_position or self.position data = self.data[z] return [[int(x) + ((data >> (i * 4)) & 3), int(y) + ((data >> (i * 4 + 2)) & 3)] for i in range(0, 4)] def draw(self, visible): if visible: self.screen.set_fg(self.color) self.screen.set_bg(self.color) s = FILLED_CELL else: s = self.empty_cell for cell in self.get_cells(): self.screen.xyprint(self.origin[0] + cell[0] * 2, self.origin[1] + cell[1], s) self.screen.reset_colors() def set_xy(self, x, y): self.position = x, y, self.position[2] def new_position(self, dx, dy, dz): x, y, z = self.position return x + dx, y + dy, (z + dz) % self.symmetry class TetrisScore: def __init__(self, screen, tetris_input_processor): self.screen = screen self.tetris_input_processor = tetris_input_processor self.score = 0 self.level = 1 self.lines_completed = 0 def update(self, complete_lines): self.lines_completed += complete_lines self.score += (complete_lines * complete_lines) if self.score > LEVEL_UP * self.level: self.level += 1 self.tetris_input_processor.decrease_delay() self.show() def show(self): self.screen.set_bold() self.screen.set_fg(SCORE_COLOR) self.screen.xyprint(SCORE_X, SCORE_Y, "Lines completed: {0}".format(self.lines_completed)) self.screen.xyprint(SCORE_X, SCORE_Y + 1, "Level: {0}".format(self.level)) self.screen.xyprint(SCORE_X, SCORE_Y + 2, "Score: {0}".format(self.score)) self.screen.reset_colors() class TetrisController: def __init__(self, screen, tetris_input_processor): self.screen = screen self.next_piece_visible = True self.running = True self.help = TetrisHelp(screen) self.score = TetrisScore(screen, tetris_input_processor) self.play_field = TetrisPlayField(screen) self.get_next_piece() self.get_current_piece() self.redraw_screen() screen.flush() def get_current_piece(self): self.next_piece.hide() self.current_piece = self.next_piece self.current_piece.set_xy((PLAYFIELD_W - 4) / 2, 0) if not self.play_field.position_ok(self.current_piece.get_cells()): self.cmd_quit() return self.current_piece.visible = True self.current_piece.empty_cell = PLAYFIELD_EMPTY_CELL self.current_piece.origin = (PLAYFIELD_X, PLAYFIELD_Y) self.current_piece.show() self.get_next_piece() def get_next_piece(self): self.next_piece = TetrisPiece( self.screen, (NEXT_X, NEXT_Y), self.next_piece_visible, ) self.next_piece.show() def redraw_screen(self): self.screen.clear_screen() self.screen.hide_cursor() self.play_field.draw_border() for o in [self.help, self.play_field, self.score, self.next_piece, self.current_piece]: o.show() def cmd_quit(self): self.running = False self.screen.xyprint(GAMEOVER_X, GAMEOVER_Y, "Game over!") self.screen.xyprint(GAMEOVER_X, GAMEOVER_Y + 1, "") self.screen.show_cursor() def process_fallen_piece(self): self.play_field.flatten_piece(self.current_piece) complete_lines = self.play_field.process_complete_lines() if complete_lines > 0: self.score.update(complete_lines) self.play_field.show() def move(self, dx, dy, dz): position = self.current_piece.new_position(dx, dy, dz) if self.play_field.position_ok(self.current_piece.get_cells(position)): self.current_piece.hide() self.current_piece.position = position self.current_piece.show() return True return (dy == 0) def cmd_right(self): self.move(1, 0, 0) def cmd_left(self): self.move(-1, 0, 0) def cmd_rotate(self): self.move(0, 0, 1) def cmd_down(self): if self.move(0, 1, 0): return True self.process_fallen_piece() self.get_current_piece() return False def cmd_drop(self): while self.cmd_down(): pass def toggle_help(self): self.help.toggle() def toggle_next(self): self.next_piece_visible ^= True self.next_piece.toggle() def toggle_color(self): self.screen.toggle_color() self.redraw_screen() @contextlib.contextmanager def nonblocking_input(): fd = sys.stdin try: flags = fcntl.fcntl(fd, FCNTL.F_GETFL) flags = flags | os.O_NONBLOCK fcntl.fcntl(fd, FCNTL.F_SETFL, flags) yield finally: flags = fcntl.fcntl(fd, FCNTL.F_GETFL) flags = flags & ~os.O_NONBLOCK fcntl.fcntl(fd, FCNTL.F_SETFL, flags) @contextlib.contextmanager def tcattr(): try: old_settings = termios.tcgetattr(sys.stdin) yield finally: termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings) class TetrisInputProcessor: delay = INITIAL_MOVE_DOWN_DELAY def decrease_delay(self): self.delay *= DELAY_FACTOR def run(): input_processor = TetrisInputProcessor() with nonblocking_input(), tcattr(): # tty.setcbreak(sys.stdin.fileno()) tty.setraw(sys.stdin.fileno()) key = [0, 0, 0] ts = TetrisScreen() ts.clear_screen() tc = TetrisController(ts, input_processor) commands = { "\x03": tc.cmd_quit, "q": tc.cmd_quit, "C": tc.cmd_right, "d": tc.cmd_right, "D": tc.cmd_left, "a": tc.cmd_left, "A": tc.cmd_rotate, "s": tc.cmd_rotate, " ": tc.cmd_drop, "h": tc.toggle_help, "n": tc.toggle_next, "c": tc.toggle_color } last_move_down_time = time.time() while tc.running: cmd = None now = time.time() select_timeout = input_processor.delay - (now - last_move_down_time) if select_timeout < 0: tc.cmd_down() ts.flush() last_move_down_time = now select_timeout = input_processor.delay if select.select([sys.stdin], [], [], input_processor.delay)[0]: s = sys.stdin.read(16) for c in s: key[2] = key[1] key[1] = key[0] key[0] = c if key[2] == '\x1b' and key[1] == '[': # x1b is ESC cmd = commands.get(key[0], None) else: cmd = commands.get(key[0].lower(), None) if cmd: cmd() ts.flush() if __name__ == '__main__': run()
Write, Run & Share Ruby code online using OneCompiler's Ruby online compiler for free. It's one of the robust, feature-rich online compilers for Ruby language, running on the latest version 2.3.1. Getting started with the OneCompiler's Ruby compiler is simple and pretty fast. The editor shows sample boilerplate code when you choose language as Ruby
and start coding.
OneCompiler's Ruby online editor supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample Ruby program which takes name as input and prints hello message with your name.
name = gets.chomp
print "Hello #{name}.\n"
Ruby is a general purpose object oriented programming language developed by Yukihiro Matsumoto.
Data type | Description | Usage |
---|---|---|
Fixnum | Represents normal numbers | x = 10 |
Bignum | Represents big numbers | x =9999999999 |
Float | Represents decimal numbers | x = 3.14 |
Complex | Represents imaginary numbers | x = 1 + 2i |
Rational | Represents fractional numbers | x = 1/4 |
BigDecimal | Represents precision decimal numbers | x=1.0 |
Hash | Represents key value pairs | {"Website"=>"onecompiler","message" => "Happy learning"} |
In Ruby, there is no need to explicitly declare variables to reserve memory space. When you assign a value to a variable, declaration happens automatically and a prefix is needed to indicate the following variable types.
Variable type | Description |
---|---|
Local variables | Scope is limited to the block of the variable initialization. Variable name must start with either _ or lowercase letter. |
Class variables | Class variables belongs to whole class and can be accessible anywhere inside the class. Variable name must start with @@ . They must be initialized before use. |
Instance variables | Instance variables belongs to a instance of the class. They can be accessed from any instance of the class within a method. Variable name must start @ |
Global variables | Scope is global and hence they can be accessible anywhere in the program. Variable name must start with $ |
If, If-else, Nested-Ifs are used when you want to perform a certain set of operations based on conditional expressions.
if(conditional-expression)
#code
end
if(conditional-expression)
#code if condition is true
else
#code if condition is false
end
if(condition-expression1)
#code if above condition is true
elsif(condition-expression2)
#code if above condition is true
elsif(condition-expression3)
#code if above condition is true
...
else
#code if all the conditions are false
end
Case is similar to Switch statement, where it is used to execute one set of a statement from multiple conditions.
case expression
[when expression [, expression ...] [then]
# code ]...
[else
# code ]
end
For loop is used to iterate a set of statements based on a condition.
for variable in expression do
# code
end
While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.
while condition do
# code
end
Do-while is also used to iterate a set of statements based on a condition. It is mostly used when you need to execute the statements atleast once.
loop do
#code
break if conditional-expression
end