Last active
June 11, 2021 00:01
-
-
Save tarruda/ea4b9854955451c66f70 to your computer and use it in GitHub Desktop.
snake.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Snake for Neovim! Adapted from https://gist.github.com/sanchitgangwar/2158084 | |
# To install, create a ~/.vim/rplugin/python/snake.py file with this | |
# code, then run `nvim -c 'UpdateRemotePlugins' -c 'q'` from a shell. | |
# | |
# Make sure you have read the internal help explaining how to setup python | |
# host for external plugins(:help nvim-python) | |
# | |
# To start a new game, use the `:SnakeStart` command on an empty buffer(uses 80 | |
# columns and 20 rows) | |
from threading import Thread, Lock | |
from time import sleep | |
from random import randint | |
import neovim | |
class Game(Thread): | |
def __init__(self, vim): | |
super(Game, self).__init__() | |
self.daemon = True | |
self.vim = vim | |
self.buf = vim.current.buffer | |
self.key = 'right' | |
self.prevKey = 'right' | |
self.score = 0 | |
# Initial snake co-ordinates | |
self.snake = [[4,10], [4,9], [4,8]] | |
# First food co-ordinates | |
self.food = [10,20] | |
self.lock = Lock() | |
self.key_subscribe('k', 'up') | |
self.key_subscribe('j', 'down') | |
self.key_subscribe('h', 'left') | |
self.key_subscribe('l', 'right') | |
self.key_subscribe('<esc>', 'esc') | |
self.key_subscribe('<space>', 'space') | |
# Fill the buffer | |
empty = ' ' * 80 | |
self.buf[0] = empty | |
for n in xrange(20): | |
self.buf.append(empty) | |
# Print the food | |
self.addstr(self.food[0], self.food[1], '*') | |
def key_subscribe(self, key, to): | |
cid = self.vim.channel_id | |
self.vim.command( | |
('nnoremap <silent> <buffer> %s ' + | |
':call rpcnotify(%d, "keypress", "%s")<cr>') % | |
(key, cid, to)) | |
def key_unsubscribe(self, key): | |
self.vim.command('unmap <buffer> %s' % key) | |
def run(self): | |
timeout = 0.05 | |
while self.key != 'esc': | |
sleep(timeout) | |
with self.lock: | |
if self.key == 'space': | |
# If SPACE BAR is pressed pause the snake and wait for | |
# another | |
self.key = None | |
while self.key != 'space': | |
sleep(timeout) | |
self.key = self.prevKey | |
continue | |
# Calculates the new coordinates of the head of the snake. | |
# NOTE: len(snake) increases. This is taken care of later at | |
# [1]. | |
self.snake.insert(0, [ | |
self.snake[0][0] + | |
(self.key == 'down' and 1) + | |
(self.key == 'up' and -1), | |
self.snake[0][1] + | |
(self.key == 'left' and -1) + | |
(self.key == 'right' and 1) | |
]) | |
# If snake crosses the boundaries, make it enter from the other | |
# side | |
if self.snake[0][0] == 0: self.snake[0][0] = 18 | |
if self.snake[0][1] == 0: self.snake[0][1] = 58 | |
if self.snake[0][0] == 19: self.snake[0][0] = 1 | |
if self.snake[0][1] == 59: self.snake[0][1] = 1 | |
l = len(self.snake) | |
trail = self.snake[1:] | |
if self.snake[0] in trail: | |
# Snake runs over itself, game over | |
break | |
# Increases the speed of Snake as its length increases | |
timeout = 0.001 * (150 - (l / 5 + l /10) % 120) | |
self.prevKey = self.key # Previous key pressed | |
self.vim.session.threadsafe_call(self.update) | |
self.vim.session.threadsafe_call(self.end) | |
def addstr(self, lnum, cnum, string): | |
line = self.buf[lnum] | |
line = line[0:cnum] + string + line[cnum + len(string):] | |
self.buf[lnum] = line | |
def update(self): | |
with self.lock: | |
if self.snake[0] == self.food: # When snake eats the food | |
self.food = [] | |
self.score += 1 | |
while self.food == []: | |
# Calculating next food's coordinates | |
self.food = [randint(1, 18), randint(1, 58)] | |
if self.food in self.snake: self.food = [] | |
self.addstr(self.food[0], self.food[1], '*') | |
else: | |
# [1] If it does not eat the food, length decreases | |
last = self.snake.pop() | |
self.addstr(last[0], last[1], ' ') | |
self.addstr(self.snake[0][0], self.snake[0][1], '#') | |
# Printing 'Score' and | |
self.addstr(0, 2, 'Score : ' + str(self.score) + ' ') | |
self.addstr(0, 27, ' SNAKE / MOVEMENTs(hjkl) EXIT(esc) PAUSE(space) ') | |
def end(self): | |
with self.lock: | |
self.buf[:] = None | |
self.buf.append("Score - " + str(self.score)) | |
self.buf.append("http://bitemelater.in") | |
self.key_unsubscribe('k') | |
self.key_unsubscribe('j') | |
self.key_unsubscribe('h') | |
self.key_unsubscribe('l') | |
self.key_unsubscribe('<esc>') | |
self.key_unsubscribe('<space>') | |
def keypress(self, k): | |
self.key = k | |
@neovim.plugin | |
class Snake(object): | |
def __init__(self, vim): | |
self.vim = vim | |
self.current_game = None | |
@neovim.rpc_export('keypress') | |
def keypress(self, key): | |
self.current_game.keypress(key) | |
@neovim.command('SnakeStart', sync=True) | |
def snake_start(self): | |
if self.current_game: | |
raise Exception('Snake already running!') | |
self.current_game = Game(self.vim) | |
self.current_game.start() |
Can anyone help me running this? I copied the file to .vim/rplugin/python/snake.py
and :UpdateRemotePlugins
seems to run successfully(it's not printing any errors), but :SnakeStart
is failing with Not an editor command: SnakeStart
.
Do we have a verbose mode for :UpdateRemotePlugins
that prints updated/loaded plugins so that I can make sure this plugin is really loaded?
UPDATE: I'm using 2015-01-16 version.
@osa1 It seems registration code is changed....
@osa1 I tested snake.py and it worked.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thats because other python plugins run over the compatibility layer, which is registered manually(doesn't require UpdateRemotePlugins to work)