#!/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() 

Ruby Online Compiler

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.

Read input from STDIN in Ruby

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" 

About Ruby

Ruby is a general purpose object oriented programming language developed by Yukihiro Matsumoto.

Key features

  • More commonly used in Rails applications.
  • Concise and simple to read and powerful too.
  • Open-source
  • Expressive features and visual appearance
  • Flexible language

Syntax help

Data types

Data typeDescriptionUsage
FixnumRepresents normal numbersx = 10
BignumRepresents big numbersx =9999999999
FloatRepresents decimal numbersx = 3.14
ComplexRepresents imaginary numbersx = 1 + 2i
RationalRepresents fractional numbersx = 1/4
BigDecimalRepresents precision decimal numbersx=1.0
HashRepresents key value pairs{"Website"=>"onecompiler","message" => "Happy learning"}

Variables

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 typeDescription
Local variablesScope is limited to the block of the variable initialization. Variable name must start with either _ or lowercase letter.
Class variablesClass 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 variablesInstance 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 variablesScope is global and hence they can be accessible anywhere in the program. Variable name must start with $

Loops and conditional statements

1. If family:

If, If-else, Nested-Ifs are used when you want to perform a certain set of operations based on conditional expressions.

If

if(conditional-expression)
    #code    
end

If-else

if(conditional-expression)  
    #code if condition is true  
else   
    #code if condition is false  
end 

Nested-If-else

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  

2. Case:

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  

3. For:

For loop is used to iterate a set of statements based on a condition.

for variable in expression do   
  # code  
end

4. While:

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  

5. Do-while:

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