Problem:


Problem C: Emacs-like Editor

Emacs is a text editor which is widely used by many programmers.

The advantage of Emacs is that we can move a cursor without arrow keys and the mice. For example, the cursor can be moved right, left, down, and up by pushing f, b, n, p with the Control Key respectively. In addition, cut-and-paste can be performed without the mouse.

Your task is to write a program which simulates key operations in the Emacs-like editor. The program should read a text and print the corresponding edited text.

The text consists of several lines and each line consists of zero or more alphabets and space characters. A line, which does not have any character, is a blank line.

The editor has a cursor which can point out a character or the end-of-line in the corresponding line. The cursor can also point out the end-of-line in a blank line.

In addition, the editor has a buffer which can hold either a string (a sequence of characters) or a linefeed.

The editor accepts the following set of commands (If the corresponding line is a blank line, the word "the first character" should be "the end-of-line"):

a

Move the cursor to the first character of the current line.

e

Move the cursor to the end-of-line of the current line.

p

Move the cursor to the first character of the next upper line, if it exists.

If there is no line above the current line, move the cursor to the first character of the current line.

n

Move the cursor to the first character of the next lower line, if it exists.

If there is no line below the current line, move the cursor to the first character of the current line.

f

Move the cursor by one character to the right, unless the cursor points out the end-of-line.

If the cursor points out the end-of-line and there is a line below the current line, move the cursor to the first character of the next lower line. Otherwise, do nothing.

b

Move the cursor by one character to the left, unless the cursor points out the first character.

If the cursor points out the first character and there is a line above the current line, move the cursor to the end-of-line of the next upper line. Otherwise, do nothing.

d

If the cursor points out a character, delete the character (Characters and end-of-line next to the deleted character are shifted to the left).

If the cursor points out the end-of-line and there is a line below, the next lower line is appended to the end-of-line of the current line (Lines below the current line are shifted to the upper). 
Otherwise, do nothing.

k

If the cursor points out the end-of-line and there is a line below the current line, perform the command d mentioned above, and record a linefeed on the buffer.

If the cursor does not point out the end-of-line, cut characters between the cursor (inclusive) and the end-of-line, and record them on the buffer.  After this operation, the cursor indicates the end-of-line of the current line.

y

If the buffer is empty, do nothing.

If the buffer is holding a linefeed, insert the linefeed at the cursor. The cursor moves to the first character of the new line.

If the buffer is holding characters, insert the characters at the cursor. The cursor moves to the character or end-of-line which is originally pointed by the cursor.

The cursor position just after reading the text is the beginning of the first line, and the initial buffer is empty.

Input

The input consists of only one data-set which includes two parts. The first part gives a text consisting of several lines. The end of the text is indicated by a line (without quotes):

"END_OF_TEXT"

This line should not be included in the text.

Next part gives a series of commands. Each command is given in a line. The end of the commands is indicated by a character '-'.

Output

For the input text, print the text edited by the commands.

Constraints

The number of lines in the text given as input ≤ 10

The number of characters in a line given as input ≤ 20 

The number of commands ≤ 300 

The maximum possible number of lines in the text during operations ≤ 100 

The maximum possible number of characters in a line during operations ≤ 1000 

Sample Input

hyo
ni
END_OF_TEXT
f
d
f
f
k
p
p
e
y
a
k
y
y
n
y
-

Output for the Sample Input

honihoni
honi



Sample input:
hyo
ni
END_OF_TEXT
f
d
f
f
k
p
p
e
y
a
k
y
y
n
y
-


Sample output:
honihoni
honi

Submission status: Accepted

Solution code:
import sys


class Cursor:
    BOL = (0,1)

    def __init__(self, text):
        assert isinstance(text, list)
        self.text = text

        for i in range(len(self.text)):
            self.text[i] = list(self.text[i])

        self.buffer = ""
        self.line = 1
        self.pos = self.BOL

    def _check(self):
        assert self.line > 0

    def _get_pos_end_of_line(self):
        last_char = len(self.text[self.line-1])
        return (last_char, last_char+1)

    def has_prev_line(self):
        return self.line > 1

    def has_next_line(self):
        return self.line < len(self.text)

    def beginning_of_line(self):
        self.pos = self.BOL

    def end_of_line(self):
        self.pos = self._get_pos_end_of_line()

    def prev_line(self):
        if self.has_prev_line():
            self.line -= 1

    def next_line(self):
        if self.has_next_line():
            self.line += 1

    def right_pos(self):
        if self._get_pos_end_of_line() != self.pos:
            self.pos = (self.pos[0] + 1, self.pos[1] + 1)
        else:
            if self.has_next_line():
                self.line += 1
                self.pos = self.BOL

    def left_pos(self):
        if self.BOL != self.pos:
            self.pos = (self.pos[0] - 1, self.pos[1] - 1)
        else:
            if self.has_prev_line():
                self.line -= 1
                self.pos = self._get_pos_end_of_line()

    def remove_current_pos(self):
        if self._get_pos_end_of_line() != self.pos:
            self.text[self.line-1] = self.text[self.line-1][:self.pos[0]] + self.text[self.line-1][self.pos[1]:]
        else:
            if self.has_next_line():
                self.text[self.line-1][self.pos[0]:self.pos[0]] = self.text[self.line]
                self.text.pop(self.line)

    def remove_to_end_of_line(self):
        if self._get_pos_end_of_line() == self.pos:
            if self.has_next_line():
                self.remove_current_pos()
                self.buffer = '\n'
        else:
            self.buffer = self.text[self.line - 1][self.pos[0]:]
            self.text[self.line - 1] = self.text[self.line - 1][:self.pos[0]]
            self.pos = self._get_pos_end_of_line()

    def paste(self):
        if self.buffer:
            if self.buffer == '\n':
                prev = self.text[self.line - 1][:self.pos[0]]
                next = self.text[self.line - 1][self.pos[0]:]

                self.text[self.line - 1] = prev
                self.text.insert(self.line, next)

                self.line += 1
                self.pos = self.BOL
            else:
                self.text[self.line - 1][self.pos[0]:self.pos[0]] = self.buffer
                self.pos = (self.pos[0] + len(self.buffer), self.pos[1] + len(self.buffer))

    def print(self):
        for t in self.text:
            print("".join(t))


class Editor:
    def __init__(self, text):
        assert isinstance(text, list)
        self.cursor = Cursor(text)

    def process(self, commands):
        if not isinstance(commands, list):
            commands = [commands]

        for command in commands:
            self._process(command)

        self.cursor.print()

    def _process(self, command):
        if command == 'a':
            self.cursor.beginning_of_line()
        elif command == 'e':
            self.cursor.end_of_line()
        elif command == 'p':
            self.cursor.prev_line()
            self.cursor.beginning_of_line()
        elif command == 'n':
            self.cursor.next_line()
            self.cursor.beginning_of_line()
        elif command == 'f':
            self.cursor.right_pos()
        elif command == 'b':
            self.cursor.left_pos()
        elif command == 'd':
            self.cursor.remove_current_pos()
        elif command == 'k':
            self.cursor.remove_to_end_of_line()
        elif command == 'y':
            self.cursor.paste()




def load_input():
    inputs = []
    while True:
        try:
            inputs.append(input())
        except EOFError:
            return inputs

def split_end_of_text(inputs):
    assert inputs
    assert 'END_OF_TEXT' in inputs

    for i in range(len(inputs)):
        if inputs[i] == 'END_OF_TEXT':
            return inputs[:i], inputs[i+1:]
    else:
        print("DO NOT DETECT END_OF_TEXT. got:", inputs)
        sys.exit(1)

    
def main():
    inputs = load_input()
    text, commands = split_end_of_text(inputs)

    # Attacking
    assert 'END_OF_TEXT' not in text
    assert 'END_OF_TEXT' not in commands

    editor = Editor(text)
    editor.process(commands)

main()

Submission status: Accepted

Solution code:
class Editer:

    def __init__(self, text):
        # カーソルの位置
        self.row = 0 #行
        self.col = 0 #列
        # 編集中のテキスト
        self.text = [list(t) + ['\n'] for t in text]
        # バッファー
        self.buffer = []

    def row_head(self):
        return 0

    def row_tail(self):
        return len(self.text) - 1

    def col_head(self):
        return 0

    def col_tail(self):
        return len(self.text[self.row]) - 1

    def __repr__(self):
        return ''.join(''.join(t) for t in self.text)

    def command_a(self):
        # カーソルを現在の行の先頭文字に移動
        self.col = self.col_head()

    def command_e(self):
        # カーソルを現在の行の行末に移動
        self.col = self.col_tail()

    def command_p(self):
        # 上に行があれば、カーソルを上の行に
        if self.row != self.row_head() :
            self.row -= 1
        # カーソルを先頭に
        self.col = self.col_head()

    def command_n(self):
        # 下に行があれば
        if self.row != self.row_tail():
            # カーソルを下の行に移動
            self.row += 1
        # カーソルを先頭文字に移動
        self.col = self.col_head()

    def command_b(self):
        # カーソルが行末にない場合
        if self.col != self.col_head():
            # カーソルを１つ左に移動
            self.col -= 1
        # カーソルが行末にあり、上に行がある場合
        elif self.row != self.row_head():
            # カーソルを前の行の先頭に
            self.row -= 1
            self.col = self.col_tail()

    def command_f(self):
        # カーソルが行末にない場合
        if self.col != self.col_tail():
            # カーソルを１つ右に移動
            self.col += 1
        # カーソルが行末にあり、下に行がある場合
        elif self.row != self.row_tail():
            # カーソルを次の行の先頭に
            self.row += 1
            self.col = self.col_head()

    def command_d(self):
        # カーソルが行末にない場合
        if self.col != self.col_tail():
            # カーソルの文字を削除
            self.text[self.row].pop(self.col)
        # カーソルが行末を指し、下に行がある場合
        elif self.row != self.row_tail():
            # 下の行をそのままカーソルの位置に繋げ、以下の行は上にシフト
            self.text[self.row].pop(self.col_tail())
            self.text[self.row] += self.text.pop(self.row+1)

    def command_k(self):
        # カーソルが行末にない場合
        if self.col != self.col_tail():
            # カーソルが指す文字を含めた右側すべての文字を切り取りそれをバッファに記録する。
            self.buffer = self.text[self.row][self.col:-1]
            self.text[self.row] = self.text[self.row][:self.col] + ['\n']
            # カーソルは元の行の行末を指すようになる
            self.col = self.col_tail()
        # カーソルが行末にあり、下に行がある場合
        elif self.row != self.row_tail():
            # バッファに改行を記録する。
            self.buffer = ['\n']
            # 下の行をそのままカーソルの位置に繋げる。以下の行は上にシフトされる。
            self.text[self.row].pop(self.col_tail())
            self.text[self.row] += self.text.pop(self.row+1)


    def command_y(self):
        '''
        カーソルが指す文字の直前にバッファを挿入
        カーソルの位置はもともと指していた文字へ移動
        バッファの内容が改行なら
        '''
        if self.buffer != ['\n']:
            self.text[self.row][self.col:self.col] = self.buffer
            self.col += len(self.buffer)

        else:
            self.text.insert(self.row+1, self.text[self.row][self.col:])
            self.text[self.row] = self.text[self.row][:self.col] + ['\n']
            self.row += 1
            self.col = self.col_head()



def main():
    # input text
    text = []
    while True:
        str = input()
        if str == 'END_OF_TEXT': break
        text.append(str)

    editer = Editer(text)

    # input command
    while True:
        command = input()
        if   command == 'a' : editer.command_a()
        elif command == 'e' : editer.command_e()
        elif command == 'p' : editer.command_p()
        elif command == 'n' : editer.command_n()
        elif command == 'f' : editer.command_f()
        elif command == 'b' : editer.command_b()
        elif command == 'd' : editer.command_d()
        elif command == 'y' : editer.command_y()
        elif command == 'k' : editer.command_k()
        elif command == '-' : break

    print(editer, end='')

if __name__ == '__main__': main()

Submission status: Accepted

Solution code:
text = []
while True:
  s = input()
  if s == "END_OF_TEXT":
    break
  text.append(s)

x, y = 0, 0
buff = ""
while True:
  c = input()
  if c == "-":
    break

  elif c == "a":
    x = 0

  elif c == "e":
    x = len(text[y])

  elif c == "p":
    if y == 0:
      x = 0
    else:
      x = 0
      y -= 1

  elif c == "n":
    if y == len(text) - 1:
      x = 0
    else:
      y += 1
      x = 0

  elif c == "f":
    if x != len(text[y]):
      x += 1
    elif y != len(text) - 1:
      y += 1
      x = 0

  elif c == "b":
    if x != 0:
      x -= 1
    elif y != 0:
      y -= 1
      x = len(text[y])

  elif c =="d":
    if x < len(text[y]):
      text[y] = text[y][:x] + text[y][x + 1:] 
    elif y != len(text) - 1:
      text[y] = text[y] + text[y + 1]
      text = text[:y + 1] + text[y + 2:]

  elif c == "k":
    if x < len(text[y]):
      buff = text[y][x:]
      text[y] = text[y][:x]
    elif y != len(text) - 1:
      text[y] = text[y] + text[y + 1]
      text = text[:y + 1] + text[y + 2:]
      buff = "\n"

  elif c =="y":
    if buff == "\n":
      new_row = text[y][x:]
      text[y] = text[y][:x]
      text = text[:y + 1] + [new_row] + text[y + 1:]
      x = 0
      y += 1
    else:
      text[y] = text[y][:x] + buff + text[y][x:]
      x += len(buff)

print(*text, sep="\n")