├── .gitignore ├── gameplay.png ├── test ├── fnl │ └── nvim-tetris │ │ └── main-test.fnl └── lua │ └── nvim-tetris │ └── main-test.lua ├── fnl └── nvim-tetris │ ├── main.fnl │ ├── const.fnl │ ├── util.fnl │ ├── io.fnl │ └── game.fnl ├── Makefile ├── plugin └── nvim-tetris.vim ├── scripts └── dep.sh ├── lua └── nvim-tetris │ ├── aniseed │ ├── nvim.lua │ ├── view.lua │ ├── dotfiles.lua │ ├── fs.lua │ ├── eval.lua │ ├── fennel.lua │ ├── env.lua │ ├── nvim │ │ └── util.lua │ ├── compile.lua │ ├── string.lua │ ├── macros.fnl │ ├── test.lua │ ├── deps │ │ ├── nvim.lua │ │ └── fennelview.lua │ └── core.lua │ ├── main.lua │ ├── const.lua │ ├── io.lua │ ├── util.lua │ └── game.lua ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | deps/* 2 | -------------------------------------------------------------------------------- /gameplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alec-gibson/nvim-tetris/HEAD/gameplay.png -------------------------------------------------------------------------------- /test/fnl/nvim-tetris/main-test.fnl: -------------------------------------------------------------------------------- 1 | (module nvim-tetris.main-test) 2 | 3 | (deftest something-simple 4 | (t.= 1 1 "1 should equal 1, I hope!")) 5 | -------------------------------------------------------------------------------- /fnl/nvim-tetris/main.fnl: -------------------------------------------------------------------------------- 1 | (module nvim-tetris.main 2 | {require {game nvim-tetris.game 3 | const nvim-tetris.const}}) 4 | 5 | (defn init [] 6 | (game.start)) 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: deps compile test 2 | 3 | default: deps compile test 4 | 5 | deps: 6 | scripts/dep.sh Olical aniseed origin/master 7 | 8 | compile: 9 | rm -rf lua 10 | deps/aniseed/scripts/compile.sh 11 | 12 | # Remove this if you only want Aniseed at compile time. 13 | deps/aniseed/scripts/embed.sh aniseed nvim-tetris 14 | 15 | test: 16 | rm -rf test/lua 17 | deps/aniseed/scripts/test.sh 18 | -------------------------------------------------------------------------------- /plugin/nvim-tetris.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_nvim_tetris') | finish | endif " prevent loading file twice 2 | 3 | let s:save_cpo = &cpo " save user coptions 4 | set cpo&vim " reset them to defaults 5 | 6 | if has("nvim") 7 | command Tetris lua require("nvim-tetris.main").init() 8 | endif 9 | 10 | let &cpo = s:save_cpo " and restore after 11 | unlet s:save_cpo 12 | 13 | let g:loaded_nvim_tetris = 1 14 | -------------------------------------------------------------------------------- /scripts/dep.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Clones a GitHub repo into deps/{name} if it's not there already. 4 | # Will update the repository each time and ensure the right commit is checked out. 5 | # Args: GitHub user, repository name, checkout target. 6 | # Usage (after copying to your scripts directory): scripts/dep.sh Olical aniseed vX.Y.Z 7 | 8 | mkdir -p deps 9 | 10 | if [ ! -d "deps/$2" ]; then 11 | git clone "https://github.com/$1/$2.git" "deps/$2" 12 | fi 13 | 14 | cd "deps/$2" && git fetch && git checkout "$3" 15 | 16 | -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/nvim.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.aniseed.nvim" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = require("nvim-tetris.aniseed.deps.nvim") 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local _2amodule_2a = _0_0 34 | local _2amodule_name_2a = "nvim-tetris.aniseed.nvim" 35 | return ({nil, _0_0, {{}, nil, nil, nil}})[2] 36 | -------------------------------------------------------------------------------- /test/lua/nvim-tetris/main-test.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.main-test" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local _2amodule_2a = _0_0 34 | local _2amodule_name_2a = "nvim-tetris.main-test" 35 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 36 | local tests_0_ = ((_0_0)["aniseed/tests"] or {}) 37 | local function _2_(t) 38 | return t["="](1, 1, "1 should equal 1, I hope!") 39 | end 40 | tests_0_["something-simple"] = _2_ 41 | _0_0["aniseed/tests"] = tests_0_ 42 | return nil -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/view.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.aniseed.view" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {require("nvim-tetris.aniseed.deps.fennelview")} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {require = {view = "nvim-tetris.aniseed.deps.fennelview"}} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local view = _local_0_[1] 34 | local _2amodule_2a = _0_0 35 | local _2amodule_name_2a = "nvim-tetris.aniseed.view" 36 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 37 | local serialise = nil 38 | do 39 | local v_0_ = nil 40 | do 41 | local v_0_0 = view 42 | _0_0["serialise"] = v_0_0 43 | v_0_ = v_0_0 44 | end 45 | local t_0_ = (_0_0)["aniseed/locals"] 46 | t_0_["serialise"] = v_0_ 47 | serialise = v_0_ 48 | end 49 | return nil 50 | -------------------------------------------------------------------------------- /lua/nvim-tetris/main.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.main" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {require("nvim-tetris.const"), require("nvim-tetris.game")} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {require = {const = "nvim-tetris.const", game = "nvim-tetris.game"}} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local const = _local_0_[1] 34 | local game = _local_0_[2] 35 | local _2amodule_2a = _0_0 36 | local _2amodule_name_2a = "nvim-tetris.main" 37 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 38 | local init = nil 39 | do 40 | local v_0_ = nil 41 | do 42 | local v_0_0 = nil 43 | local function init0() 44 | return game.start() 45 | end 46 | v_0_0 = init0 47 | _0_0["init"] = v_0_0 48 | v_0_ = v_0_0 49 | end 50 | local t_0_ = (_0_0)["aniseed/locals"] 51 | t_0_["init"] = v_0_ 52 | init = v_0_ 53 | end 54 | return nil -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/dotfiles.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.aniseed.dotfiles" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {require("nvim-tetris.aniseed.compile"), require("nvim-tetris.aniseed.fennel"), require("nvim-tetris.aniseed.nvim")} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {require = {compile = "nvim-tetris.aniseed.compile", fennel = "nvim-tetris.aniseed.fennel", nvim = "nvim-tetris.aniseed.nvim"}} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local compile = _local_0_[1] 34 | local fennel = _local_0_[2] 35 | local nvim = _local_0_[3] 36 | local _2amodule_2a = _0_0 37 | local _2amodule_name_2a = "nvim-tetris.aniseed.dotfiles" 38 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 39 | nvim.out_write("Warning: aniseed.dotfiles is deprecated, see :help aniseed-dotfiles\n") 40 | local config_dir = nil 41 | do 42 | local v_0_ = nvim.fn.stdpath("config") 43 | local t_0_ = (_0_0)["aniseed/locals"] 44 | t_0_["config-dir"] = v_0_ 45 | config_dir = v_0_ 46 | end 47 | fennel["add-path"]((config_dir .. "/?.fnl")) 48 | compile.glob("**/*.fnl", (config_dir .. "/fnl"), (config_dir .. "/lua")) 49 | return require("dotfiles.init") 50 | -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/fs.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.aniseed.fs" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {require("nvim-tetris.aniseed.nvim")} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {require = {nvim = "nvim-tetris.aniseed.nvim"}} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local nvim = _local_0_[1] 34 | local _2amodule_2a = _0_0 35 | local _2amodule_name_2a = "nvim-tetris.aniseed.fs" 36 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 37 | local basename = nil 38 | do 39 | local v_0_ = nil 40 | do 41 | local v_0_0 = nil 42 | local function basename0(path) 43 | return nvim.fn.fnamemodify(path, ":h") 44 | end 45 | v_0_0 = basename0 46 | _0_0["basename"] = v_0_0 47 | v_0_ = v_0_0 48 | end 49 | local t_0_ = (_0_0)["aniseed/locals"] 50 | t_0_["basename"] = v_0_ 51 | basename = v_0_ 52 | end 53 | local mkdirp = nil 54 | do 55 | local v_0_ = nil 56 | do 57 | local v_0_0 = nil 58 | local function mkdirp0(dir) 59 | return nvim.fn.mkdir(dir, "p") 60 | end 61 | v_0_0 = mkdirp0 62 | _0_0["mkdirp"] = v_0_0 63 | v_0_ = v_0_0 64 | end 65 | local t_0_ = (_0_0)["aniseed/locals"] 66 | t_0_["mkdirp"] = v_0_ 67 | mkdirp = v_0_ 68 | end 69 | return nil 70 | -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/eval.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.aniseed.eval" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {require("nvim-tetris.aniseed.core"), require("nvim-tetris.aniseed.compile"), require("nvim-tetris.aniseed.fennel"), require("nvim-tetris.aniseed.fs"), require("nvim-tetris.aniseed.nvim")} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {require = {a = "nvim-tetris.aniseed.core", compile = "nvim-tetris.aniseed.compile", fennel = "nvim-tetris.aniseed.fennel", fs = "nvim-tetris.aniseed.fs", nvim = "nvim-tetris.aniseed.nvim"}} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local a = _local_0_[1] 34 | local compile = _local_0_[2] 35 | local fennel = _local_0_[3] 36 | local fs = _local_0_[4] 37 | local nvim = _local_0_[5] 38 | local _2amodule_2a = _0_0 39 | local _2amodule_name_2a = "nvim-tetris.aniseed.eval" 40 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 41 | local str = nil 42 | do 43 | local v_0_ = nil 44 | do 45 | local v_0_0 = nil 46 | local function str0(code, opts) 47 | local function _2_() 48 | return fennel.eval(compile["macros-prefix"](code), a.merge({["compiler-env"] = _G}, opts)) 49 | end 50 | return xpcall(_2_, fennel.traceback) 51 | end 52 | v_0_0 = str0 53 | _0_0["str"] = v_0_0 54 | v_0_ = v_0_0 55 | end 56 | local t_0_ = (_0_0)["aniseed/locals"] 57 | t_0_["str"] = v_0_ 58 | str = v_0_ 59 | end 60 | return nil 61 | -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/fennel.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.aniseed.fennel" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = require("nvim-tetris.aniseed.deps.fennel") 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {require("nvim-tetris.aniseed.deps.fennel"), require("nvim-tetris.aniseed.nvim")} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {require = {fennel = "nvim-tetris.aniseed.deps.fennel", nvim = "nvim-tetris.aniseed.nvim"}} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local fennel = _local_0_[1] 34 | local nvim = _local_0_[2] 35 | local _2amodule_2a = _0_0 36 | local _2amodule_name_2a = "nvim-tetris.aniseed.fennel" 37 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 38 | local add_path = nil 39 | do 40 | local v_0_ = nil 41 | do 42 | local v_0_0 = nil 43 | local function add_path0(path) 44 | fennel.path = (fennel.path .. ";" .. path) 45 | return nil 46 | end 47 | v_0_0 = add_path0 48 | _0_0["add-path"] = v_0_0 49 | v_0_ = v_0_0 50 | end 51 | local t_0_ = (_0_0)["aniseed/locals"] 52 | t_0_["add-path"] = v_0_ 53 | add_path = v_0_ 54 | end 55 | local sync_rtp = nil 56 | do 57 | local v_0_ = nil 58 | do 59 | local v_0_0 = nil 60 | local function sync_rtp0() 61 | local fnl_suffix = "/fnl/?.fnl" 62 | local rtp = nvim.o.runtimepath 63 | local fnl_path = (rtp:gsub(",", (fnl_suffix .. ";")) .. fnl_suffix) 64 | local lua_path = fnl_path:gsub("/fnl/", "/lua/") 65 | fennel["path"] = (fnl_path .. ";" .. lua_path) 66 | return nil 67 | end 68 | v_0_0 = sync_rtp0 69 | _0_0["sync-rtp"] = v_0_0 70 | v_0_ = v_0_0 71 | end 72 | local t_0_ = (_0_0)["aniseed/locals"] 73 | t_0_["sync-rtp"] = v_0_ 74 | sync_rtp = v_0_ 75 | end 76 | return sync_rtp() 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nvim-tetris 2 | Bringing emacs' greatest feature to neovim - Tetris! 3 | 4 | ![Gameplay Screenshot](./gameplay.png "Some poorly executed demo gameplay") 5 | 6 | This plugin is written in [Fennel](https://fennel-lang.org/) using Olical's project [Aniseed](https://github.com/Olical/aniseed) for creating the project structure, and as a library of helper functions and macros. The game compiles to Lua and uses Neovim API functions, so Vim support is not currently a goal. 7 | 8 | nvim-tetris is a work-in-progress, and is not feature complete. 9 | 10 | ## How To Install 11 | - Prerequisites: neovim 12 | - You can install the plugin just like any other Neovim plugin. I personally use [vim-plug](https://github.com/junegunn/vim-plug). 13 | - Another way to install would be to just clone this repo into `~/.local/share/nvim/site/pack/*/start/`, where `*` is whatever you choose (I use "alec"). 14 | - After installing, you can launch a game of Tetris using the `:Tetris` command inside Neovim. 15 | - If your colours look weird, ensure you are using a terminal which supports true colour, you have configured tmux for true colour support if you are using tmux, and you have the `termguicolors` option enabled in Neovim. 16 | 17 | ## Controls 18 | - Left Arrow: move left 19 | - Right Arrow: move right 20 | - Up Arrow: rotate piece 21 | - Down Arrow: soft drop 22 | - Space Bar: hard drop 23 | 24 | ## What Works 25 | - Core game functions including controlling the current piece, clearing lines, and gameover when you run out of space 26 | - Piece shadow showing where the current piece will land 27 | - Level progression - you progress a level every 10 lines cleared, and the game gets faster with each level 28 | - Short delays when the piece appears and when it locks. The locking delay resets when rotating or moving your piece, to make gameplay more fun at high speeds 29 | - Correct rotation behaviour including wall-kicks according to "How Guideline SRS Really Works" from https://harddrop.com/wiki/SRS (this means T-spins work) 30 | 31 | ## Next Steps 32 | - Add border showing current level, current score, next piece, saved piece (and add logic for saving pieces) 33 | - Add pause screen (with options to resume game, start new game or quit) 34 | - Add game over screen (with options to play again or quit) 35 | - Add intro screen which shows controls 36 | - Add logic for score 37 | - Configuration 38 | - Documentation 39 | - Tests 40 | - Stretch goals: music, leaderboards?, ... 41 | -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/env.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.aniseed.env" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local _2amodule_2a = _0_0 34 | local _2amodule_name_2a = "nvim-tetris.aniseed.env" 35 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 36 | local config_dir = nil 37 | do 38 | local v_0_ = vim.api.nvim_call_function("stdpath", {"config"}) 39 | local t_0_ = (_0_0)["aniseed/locals"] 40 | t_0_["config-dir"] = v_0_ 41 | config_dir = v_0_ 42 | end 43 | local state = nil 44 | do 45 | local v_0_ = (((_0_0)["aniseed/locals"]).state or {["path-added?"] = false}) 46 | local t_0_ = (_0_0)["aniseed/locals"] 47 | t_0_["state"] = v_0_ 48 | state = v_0_ 49 | end 50 | local init = nil 51 | do 52 | local v_0_ = nil 53 | do 54 | local v_0_0 = nil 55 | local function init0(opts) 56 | local opts0 = nil 57 | if ("table" == type(opts)) then 58 | opts0 = opts 59 | else 60 | opts0 = {} 61 | end 62 | if ((false ~= opts0.compile) or os.getenv("ANISEED_ENV_COMPILE")) then 63 | local compile = require("nvim-tetris.aniseed.compile") 64 | local fennel = require("nvim-tetris.aniseed.fennel") 65 | if not state["path-added?"] then 66 | fennel["add-path"]((config_dir .. "/?.fnl")) 67 | state["path-added?"] = true 68 | end 69 | compile.glob("**/*.fnl", (config_dir .. (opts0.input or "/fnl")), (config_dir .. (opts0.output or "/lua")), opts0) 70 | end 71 | return require((opts0.module or "init")) 72 | end 73 | v_0_0 = init0 74 | _0_0["init"] = v_0_0 75 | v_0_ = v_0_0 76 | end 77 | local t_0_ = (_0_0)["aniseed/locals"] 78 | t_0_["init"] = v_0_ 79 | init = v_0_ 80 | end 81 | return nil 82 | -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/nvim/util.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.aniseed.nvim.util" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {require("nvim-tetris.aniseed.nvim")} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {require = {nvim = "nvim-tetris.aniseed.nvim"}} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local nvim = _local_0_[1] 34 | local _2amodule_2a = _0_0 35 | local _2amodule_name_2a = "nvim-tetris.aniseed.nvim.util" 36 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 37 | local normal = nil 38 | do 39 | local v_0_ = nil 40 | do 41 | local v_0_0 = nil 42 | local function normal0(keys) 43 | return nvim.ex.silent(("exe \"normal! " .. keys .. "\"")) 44 | end 45 | v_0_0 = normal0 46 | _0_0["normal"] = v_0_0 47 | v_0_ = v_0_0 48 | end 49 | local t_0_ = (_0_0)["aniseed/locals"] 50 | t_0_["normal"] = v_0_ 51 | normal = v_0_ 52 | end 53 | local fn_bridge = nil 54 | do 55 | local v_0_ = nil 56 | do 57 | local v_0_0 = nil 58 | local function fn_bridge0(viml_name, mod, lua_name, opts) 59 | local _let_0_ = (opts or {}) 60 | local range = _let_0_["range"] 61 | local _return = _let_0_["return"] 62 | local _2_ 63 | if range then 64 | _2_ = " range" 65 | else 66 | _2_ = "" 67 | end 68 | local _4_ 69 | if (_return ~= false) then 70 | _4_ = "return" 71 | else 72 | _4_ = "call" 73 | end 74 | local _6_ 75 | if range then 76 | _6_ = "\" . a:firstline . \", \" . a:lastline . \", " 77 | else 78 | _6_ = "" 79 | end 80 | return nvim.ex.function_((viml_name .. "(...)" .. _2_ .. "\n " .. _4_ .. " luaeval(\"require('" .. mod .. "')['" .. lua_name .. "'](" .. _6_ .. "unpack(_A))\", a:000)\n endfunction")) 81 | end 82 | v_0_0 = fn_bridge0 83 | _0_0["fn-bridge"] = v_0_0 84 | v_0_ = v_0_0 85 | end 86 | local t_0_ = (_0_0)["aniseed/locals"] 87 | t_0_["fn-bridge"] = v_0_ 88 | fn_bridge = v_0_ 89 | end 90 | local with_out_str = nil 91 | do 92 | local v_0_ = nil 93 | do 94 | local v_0_0 = nil 95 | local function with_out_str0(f) 96 | nvim.ex.redir("=> g:aniseed_nvim_util_out_str") 97 | do 98 | local ok_3f, err = pcall(f) 99 | nvim.ex.redir("END") 100 | nvim.ex.echon("") 101 | nvim.ex.redraw() 102 | if not ok_3f then 103 | error(err) 104 | end 105 | end 106 | return string.gsub(nvim.g.aniseed_nvim_util_out_str, "^(\n?)(.*)$", "%2%1") 107 | end 108 | v_0_0 = with_out_str0 109 | _0_0["with-out-str"] = v_0_0 110 | v_0_ = v_0_0 111 | end 112 | local t_0_ = (_0_0)["aniseed/locals"] 113 | t_0_["with-out-str"] = v_0_ 114 | with_out_str = v_0_ 115 | end 116 | return nil 117 | -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/compile.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.aniseed.compile" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {require("nvim-tetris.aniseed.core"), require("nvim-tetris.aniseed.fennel"), require("nvim-tetris.aniseed.fs"), require("nvim-tetris.aniseed.nvim")} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {require = {a = "nvim-tetris.aniseed.core", fennel = "nvim-tetris.aniseed.fennel", fs = "nvim-tetris.aniseed.fs", nvim = "nvim-tetris.aniseed.nvim"}} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local a = _local_0_[1] 34 | local fennel = _local_0_[2] 35 | local fs = _local_0_[3] 36 | local nvim = _local_0_[4] 37 | local _2amodule_2a = _0_0 38 | local _2amodule_name_2a = "nvim-tetris.aniseed.compile" 39 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 40 | local macros_prefix = nil 41 | do 42 | local v_0_ = nil 43 | do 44 | local v_0_0 = nil 45 | local function macros_prefix0(code) 46 | local macros_module = "nvim-tetris.aniseed.macros" 47 | return ("(require-macros \"" .. macros_module .. "\")\n" .. code) 48 | end 49 | v_0_0 = macros_prefix0 50 | _0_0["macros-prefix"] = v_0_0 51 | v_0_ = v_0_0 52 | end 53 | local t_0_ = (_0_0)["aniseed/locals"] 54 | t_0_["macros-prefix"] = v_0_ 55 | macros_prefix = v_0_ 56 | end 57 | local str = nil 58 | do 59 | local v_0_ = nil 60 | do 61 | local v_0_0 = nil 62 | local function str0(code, opts) 63 | local function _2_() 64 | return fennel.compileString(macros_prefix(code), a.merge({["compiler-env"] = _G}, opts)) 65 | end 66 | return xpcall(_2_, fennel.traceback) 67 | end 68 | v_0_0 = str0 69 | _0_0["str"] = v_0_0 70 | v_0_ = v_0_0 71 | end 72 | local t_0_ = (_0_0)["aniseed/locals"] 73 | t_0_["str"] = v_0_ 74 | str = v_0_ 75 | end 76 | local file = nil 77 | do 78 | local v_0_ = nil 79 | do 80 | local v_0_0 = nil 81 | local function file0(src, dest, opts) 82 | if ((a["table?"](opts) and opts.force) or (nvim.fn.getftime(src) > nvim.fn.getftime(dest))) then 83 | local code = a.slurp(src) 84 | local _2_0, _3_0 = str(code, {filename = src}) 85 | if ((_2_0 == false) and (nil ~= _3_0)) then 86 | local err = _3_0 87 | return nvim.err_writeln(err) 88 | elseif ((_2_0 == true) and (nil ~= _3_0)) then 89 | local result = _3_0 90 | fs.mkdirp(fs.basename(dest)) 91 | return a.spit(dest, result) 92 | end 93 | end 94 | end 95 | v_0_0 = file0 96 | _0_0["file"] = v_0_0 97 | v_0_ = v_0_0 98 | end 99 | local t_0_ = (_0_0)["aniseed/locals"] 100 | t_0_["file"] = v_0_ 101 | file = v_0_ 102 | end 103 | local glob = nil 104 | do 105 | local v_0_ = nil 106 | do 107 | local v_0_0 = nil 108 | local function glob0(src_expr, src_dir, dest_dir, opts) 109 | local src_dir_len = a.inc(string.len(src_dir)) 110 | local src_paths = nil 111 | local function _2_(path) 112 | return string.sub(path, src_dir_len) 113 | end 114 | src_paths = a.map(_2_, nvim.fn.globpath(src_dir, src_expr, true, true)) 115 | for _, path in ipairs(src_paths) do 116 | if (a.get(opts, "include-macros-suffix?") or not string.match(path, "macros.fnl$")) then 117 | file((src_dir .. path), string.gsub((dest_dir .. path), ".fnl$", ".lua"), opts) 118 | end 119 | end 120 | return nil 121 | end 122 | v_0_0 = glob0 123 | _0_0["glob"] = v_0_0 124 | v_0_ = v_0_0 125 | end 126 | local t_0_ = (_0_0)["aniseed/locals"] 127 | t_0_["glob"] = v_0_ 128 | glob = v_0_ 129 | end 130 | return nil 131 | -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/string.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.aniseed.string" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {require("nvim-tetris.aniseed.core")} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {require = {a = "nvim-tetris.aniseed.core"}} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local a = _local_0_[1] 34 | local _2amodule_2a = _0_0 35 | local _2amodule_name_2a = "nvim-tetris.aniseed.string" 36 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 37 | local join = nil 38 | do 39 | local v_0_ = nil 40 | do 41 | local v_0_0 = nil 42 | local function join0(...) 43 | local args = {...} 44 | local function _2_(...) 45 | if (2 == a.count(args)) then 46 | return args 47 | else 48 | return {"", a.first(args)} 49 | end 50 | end 51 | local _let_0_ = _2_(...) 52 | local sep = _let_0_[1] 53 | local xs = _let_0_[2] 54 | local len = a.count(xs) 55 | local result = {} 56 | if (len > 0) then 57 | for i = 1, len do 58 | local x = xs[i] 59 | local _3_0 = nil 60 | if ("string" == type(x)) then 61 | _3_0 = x 62 | elseif (nil == x) then 63 | _3_0 = x 64 | else 65 | _3_0 = a["pr-str"](x) 66 | end 67 | if _3_0 then 68 | table.insert(result, _3_0) 69 | else 70 | end 71 | end 72 | end 73 | return table.concat(result, sep) 74 | end 75 | v_0_0 = join0 76 | _0_0["join"] = v_0_0 77 | v_0_ = v_0_0 78 | end 79 | local t_0_ = (_0_0)["aniseed/locals"] 80 | t_0_["join"] = v_0_ 81 | join = v_0_ 82 | end 83 | local split = nil 84 | do 85 | local v_0_ = nil 86 | do 87 | local v_0_0 = nil 88 | local function split0(s, pat) 89 | local done_3f = false 90 | local acc = {} 91 | local index = 1 92 | while not done_3f do 93 | local start, _end = string.find(s, pat, index) 94 | if ("nil" == type(start)) then 95 | table.insert(acc, string.sub(s, index)) 96 | done_3f = true 97 | else 98 | table.insert(acc, string.sub(s, index, (start - 1))) 99 | index = (_end + 1) 100 | end 101 | end 102 | return acc 103 | end 104 | v_0_0 = split0 105 | _0_0["split"] = v_0_0 106 | v_0_ = v_0_0 107 | end 108 | local t_0_ = (_0_0)["aniseed/locals"] 109 | t_0_["split"] = v_0_ 110 | split = v_0_ 111 | end 112 | local blank_3f = nil 113 | do 114 | local v_0_ = nil 115 | do 116 | local v_0_0 = nil 117 | local function blank_3f0(s) 118 | return (a["empty?"](s) or not string.find(s, "[^%s]")) 119 | end 120 | v_0_0 = blank_3f0 121 | _0_0["blank?"] = v_0_0 122 | v_0_ = v_0_0 123 | end 124 | local t_0_ = (_0_0)["aniseed/locals"] 125 | t_0_["blank?"] = v_0_ 126 | blank_3f = v_0_ 127 | end 128 | local triml = nil 129 | do 130 | local v_0_ = nil 131 | do 132 | local v_0_0 = nil 133 | local function triml0(s) 134 | return string.gsub(s, "^%s*(.-)", "%1") 135 | end 136 | v_0_0 = triml0 137 | _0_0["triml"] = v_0_0 138 | v_0_ = v_0_0 139 | end 140 | local t_0_ = (_0_0)["aniseed/locals"] 141 | t_0_["triml"] = v_0_ 142 | triml = v_0_ 143 | end 144 | local trimr = nil 145 | do 146 | local v_0_ = nil 147 | do 148 | local v_0_0 = nil 149 | local function trimr0(s) 150 | return string.gsub(s, "(.-)%s*$", "%1") 151 | end 152 | v_0_0 = trimr0 153 | _0_0["trimr"] = v_0_0 154 | v_0_ = v_0_0 155 | end 156 | local t_0_ = (_0_0)["aniseed/locals"] 157 | t_0_["trimr"] = v_0_ 158 | trimr = v_0_ 159 | end 160 | local trim = nil 161 | do 162 | local v_0_ = nil 163 | do 164 | local v_0_0 = nil 165 | local function trim0(s) 166 | return string.gsub(s, "^%s*(.-)%s*$", "%1") 167 | end 168 | v_0_0 = trim0 169 | _0_0["trim"] = v_0_0 170 | v_0_ = v_0_0 171 | end 172 | local t_0_ = (_0_0)["aniseed/locals"] 173 | t_0_["trim"] = v_0_ 174 | trim = v_0_ 175 | end 176 | return nil 177 | -------------------------------------------------------------------------------- /fnl/nvim-tetris/const.fnl: -------------------------------------------------------------------------------- 1 | (module nvim-tetris.const) 2 | 3 | (def rows 24) ; only 20 drawn inside the game border 4 | (def columns 10) 5 | (def screen_rows 20) 6 | (def screen_cols 10) 7 | (def max_level 18) ; after level 18, all levels are same speed 8 | (def frame_delay (math.floor (/ 1000 60))) 9 | (def lock_delay 10) ; in frames. My game will support move reset - successfully moving or rotating resets the lock delay 10 | (def entry_delay 10) ; in frames. Time between previous piece locking and new piece starting to fall 11 | (def lines_per_level 10) 12 | 13 | (def game_states {"appearing" 0 14 | "falling" 1 15 | "locking" 2 16 | "intro" 3 17 | "paused" 4 18 | "gameover" 5}) 19 | 20 | (def colours {:TetrisBackground {:guifg "Black" :ctermfg "Black"} 21 | :TetrisHeader {:guifg "DarkGray" :ctermfg "DarkGray"} 22 | :TetrisIPiece {:guifg "Cyan" :ctermfg "DarkCyan"} 23 | :TetrisJPiece {:guifg "Blue" :ctermfg "DarkBlue"} 24 | :TetrisLPiece {:guifg "Orange" :ctermfg "Brown"} 25 | :TetrisOPiece {:guifg "Yellow" :ctermfg "Yellow"} 26 | :TetrisSPiece {:guifg "Green" :ctermfg "DarkGreen"} 27 | :TetrisTPiece {:guifg "Purple" :ctermfg "DarkMagenta"} 28 | :TetrisZPiece {:guifg "Red" :ctermfg "DarkRed"} 29 | :TetrisShadow {:guifg "LightGray" :ctermfg "LightGray"}}) 30 | 31 | ; following "How Guideline SRS Really Works" from https://harddrop.com/wiki/SRS 32 | ; How wallkicking works: say we're changing an I piece from rotation state 0 to 1 33 | ; - try shifting by wallkick_offsets.I.0[1] - wallkick_offsets.I.1[1] 34 | ; - if that puts you inside another piece, try shifting by wallkick_offsets.I.0[2] - wallkick_offsets.I.1[2] 35 | ; - keep trying until you find one that doesn't put you inside another piece 36 | ; - if no wallkick works, the rotation fails 37 | (def wallkick_offsets {:normal {0 [[0 0] [0 0] [0 0] [0 0] [0 0]] 38 | 1 [[0 0] [1 0] [1 -1] [0 2] [1 2]] 39 | 2 [[0 0] [0 0] [0 0] [0 0] [0 0]] 40 | 3 [[0 0] [-1 0] [-1 -1] [0 2] [-1 2]]} 41 | :I {0 [[0 0] [-1 0] [2 0] [-1 0] [2 0]] 42 | 1 [[-1 0] [0 0] [0 0] [0 1] [0 -2]] 43 | 2 [[-1 1] [1 1] [-2 1] [1 0] [-2 0]] 44 | 3 [[0 1] [0 1] [0 1] [0 -1] [0 2]]} 45 | :O {0 [[0 0]] 46 | 1 [[0 -1]] 47 | 2 [[-1 -1]] 48 | 3 [[-1 0]]}}) 49 | 50 | ; list of pieces in their initial positions / orientations 51 | ; following "How Guideline SRS Really Works" from https://harddrop.com/wiki/SRS 52 | ; piece pivot always starts off at [5 21] 53 | (def piece_types [{:name "I" 54 | :colour "TetrisIPiece" 55 | :square_offsets [[-1 0] [0 0] [1 0] [2 0]] 56 | :wallkick_offsets wallkick_offsets.I} 57 | {:name "J" 58 | :colour "TetrisJPiece" 59 | :square_offsets [[-1 1] [-1 0] [0 0] [1 0]] 60 | :wallkick_offsets wallkick_offsets.normal} 61 | {:name "L" 62 | :colour "TetrisLPiece" 63 | :square_offsets [[-1 0] [0 0] [1 0] [1 1]] 64 | :wallkick_offsets wallkick_offsets.normal} 65 | {:name "O" 66 | :colour "TetrisOPiece" 67 | :square_offsets [[0 0] [1 0] [1 1] [0 1]] 68 | :wallkick_offsets wallkick_offsets.O} 69 | {:name "S" 70 | :colour "TetrisSPiece" 71 | :square_offsets [[-1 0] [0 0] [0 1] [1 1]] 72 | :wallkick_offsets wallkick_offsets.normal} 73 | {:name "T" 74 | :colour "TetrisTPiece" 75 | :square_offsets [[-1 0] [0 0] [0 1] [1 0]] 76 | :wallkick_offsets wallkick_offsets.normal} 77 | {:name "Z" 78 | :colour "TetrisZPiece" 79 | :square_offsets [[-1 1] [0 0] [0 1] [1 0]] 80 | :wallkick_offsets wallkick_offsets.normal}]) 81 | 82 | ; level -> frames taken to drop one gridcell 83 | ; if level > max_level, 1 frame is taken to drop one gridcell 84 | (def gravity {0 30 85 | 1 25 86 | 2 20 87 | 3 16 88 | 4 13 89 | 5 10 90 | 6 8 91 | 7 6 92 | 8 7 93 | 9 6 94 | 10 5 95 | 11 4 96 | 12 4 97 | 13 3 98 | 14 3 99 | 15 2 100 | 16 2 101 | 17 1 102 | 18 1}) 103 | -------------------------------------------------------------------------------- /fnl/nvim-tetris/util.fnl: -------------------------------------------------------------------------------- 1 | (module nvim-tetris.util 2 | {require {const nvim-tetris.const 3 | a nvim-tetris.aniseed.core 4 | v nvim-tetris.aniseed.view}}) 5 | 6 | (defn- unique [tbl] 7 | (let [vals {}] 8 | (each [_ val (ipairs tbl)] 9 | (tset vals val true)) 10 | (a.keys vals))) 11 | 12 | (defn- sort_descending [tbl] 13 | (table.sort tbl (fn [a b] (> a b))) 14 | tbl) 15 | 16 | ; [x y], [x y] -> [x y] 17 | (defn- add_pairs [p1 p2] 18 | (let [[x1 y1] p1 19 | [x2 y2] p2] 20 | [(+ x1 x2) (+ y1 y2)])) 21 | 22 | (defn- apply_rotation [piece rotation] 23 | (let [{:square_offsets offsets} piece 24 | mod (% rotation 4)] 25 | (icollect [_ offset (ipairs offsets)] 26 | (let [[x y] offset] 27 | (if (= 0 mod) 28 | offset 29 | (= 1 mod) 30 | [y (- 0 x)] 31 | (= 2 mod) 32 | [(- 0 x) (- 0 y)] 33 | [(- 0 y) x]))))) 34 | 35 | (defn- out_of_game_bounds? [row col] 36 | (or (< row 1) (< col 1) (> row const.rows) (> col const.columns))) 37 | 38 | (defn- out_of_screen_bounds? [row col] 39 | (or (< row 1) (< col 1) (> row const.screen_rows) (> col const.screen_cols))) 40 | 41 | (defn- square_collides_or_out_of_bounds? [row col occupied_squares] 42 | (or (out_of_game_bounds? row col) 43 | (. (. occupied_squares row) col))) 44 | 45 | (defn- square_collides_or_below_screen? [row col occupied_squares] 46 | (or (< row 1) 47 | (. (. occupied_squares row) col))) 48 | 49 | ; [x y] {:square_offsets [[x y]] :colour ""} int -> [{:coords [x y] :colour ""}] 50 | (defn get_piece_squares [pivot piece rotation] 51 | (icollect [_ offset (ipairs (apply_rotation piece rotation))] 52 | {:coords (add_pairs pivot offset) :colour piece.colour})) 53 | ; (get_piece_squares [5 15] (. const.piece_types 1) 0) 54 | 55 | ; nil -> int 56 | (defn get_gravity [level] 57 | (if (> level const.max_level) 58 | 0 59 | (. const.gravity level))) 60 | 61 | (defn get_shadow_offset [piece_squares occupied_squares] 62 | (var vert_dist const.rows) 63 | (each [_ square (ipairs piece_squares)] 64 | (let [{:coords [col row]} square] 65 | (for [shadow_row row 0 -1] 66 | (if (square_collides_or_below_screen? shadow_row col occupied_squares) 67 | (let [diff (a.dec (- row shadow_row))] 68 | (if (< diff vert_dist) 69 | (set vert_dist diff)) 70 | (lua "break"))) 71 | ))) 72 | vert_dist) 73 | 74 | (defn get_shadow_squares [piece_squares vert_dist] 75 | (a.map (fn [square] 76 | (let [{:coords [col row] : colour} square] 77 | {:coords [col (- row vert_dist)] :colour "TetrisShadow"})) piece_squares)) 78 | 79 | (defn piece_collides_or_out_of_bounds? [piece_squares occupied_squares] 80 | (a.reduce (fn [collides square] 81 | (let [{:coords [col row]} square] 82 | (or collides 83 | (square_collides_or_out_of_bounds? row col occupied_squares) 84 | ))) false piece_squares)) 85 | 86 | (defn get_random_piece [] 87 | (. const.piece_types (math.ceil (a.rand (a.count const.piece_types))))) 88 | 89 | (defn row_full? [row occupied_squares] 90 | (a.reduce (fn [is_clear val] (and is_clear val)) true (. occupied_squares row))) 91 | 92 | ; must return a list of rows from greatest to least 93 | (defn get_square_rows [piece_squares] 94 | (sort_descending 95 | (unique 96 | (a.map 97 | (fn [square] 98 | (let [{:coords [col row]} square] row)) 99 | piece_squares)))) 100 | 101 | (defn squares_in_bounds [squares] 102 | (a.filter (fn [square] 103 | (let [{:coords [col row]} square] 104 | (not ( out_of_screen_bounds? row col)))) 105 | squares)) 106 | 107 | (defn- get_trial_offsets [old_offsets new_offsets] 108 | (let [trial_offsets []] 109 | (for [i 1 (a.count old_offsets)] 110 | (let [[old_col old_row] (. old_offsets i) 111 | [new_col new_row] (. new_offsets i)] 112 | (table.insert trial_offsets [(- old_col new_col) (- old_row new_row)]))) 113 | trial_offsets)) 114 | 115 | (defn get_rotation_offset [pivot piece old_rotation new_rotation occupied_squares] 116 | (var rotation_offset nil) 117 | (let [old_offsets (. piece.wallkick_offsets (% old_rotation 4)) 118 | new_offsets (. piece.wallkick_offsets (% new_rotation 4)) 119 | trial_offsets (get_trial_offsets old_offsets new_offsets)] 120 | (each [_ offset (ipairs trial_offsets)] 121 | (let [[d_x d_y] offset 122 | [x y] pivot 123 | new_pivot [(+ x d_x) (+ y d_y)]] 124 | (when (not (piece_collides_or_out_of_bounds? (get_piece_squares new_pivot piece new_rotation) occupied_squares)) 125 | (set rotation_offset offset) 126 | (lua "break")))) 127 | rotation_offset)) 128 | -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/macros.fnl: -------------------------------------------------------------------------------- 1 | ;; All of Aniseed's macros in one place. 2 | ;; Can't be compiled to Lua directly. 3 | 4 | ;; Automatically loaded through require-macros for all Aniseed based evaluations. 5 | 6 | (local module-sym (gensym)) 7 | 8 | (fn sorted-each [f x] 9 | (let [acc []] 10 | (each [k v (pairs x)] 11 | (table.insert acc [k v])) 12 | (table.sort 13 | acc 14 | (fn [a b] 15 | (< (. a 1) (. b 1)))) 16 | (each [_ [k v] (ipairs acc)] 17 | (f k v)))) 18 | 19 | (fn module [name new-local-fns initial-mod] 20 | `(-> [(local ,module-sym 21 | (let [name# ,(tostring name) 22 | module# (let [x# (. package.loaded name#)] 23 | (if (= :table (type x#)) 24 | x# 25 | ,(or initial-mod {})))] 26 | (tset module# :aniseed/module name#) 27 | (tset module# :aniseed/locals (or (. module# :aniseed/locals) {})) 28 | (tset module# :aniseed/local-fns (or (. module# :aniseed/local-fns) {})) 29 | (tset package.loaded name# module#) 30 | module#)) 31 | 32 | ,module-sym 33 | 34 | ,(let [aliases [] 35 | vals [] 36 | effects [] 37 | pkg (let [x (. package.loaded (tostring name))] 38 | (when (= :table (type x)) 39 | x)) 40 | locals (-?> pkg (. :aniseed/locals)) 41 | local-fns (or (and (not new-local-fns) 42 | (-?> pkg (. :aniseed/local-fns))) 43 | {})] 44 | 45 | (when new-local-fns 46 | (each [action binds (pairs new-local-fns)] 47 | (let [action-str (tostring action) 48 | current (or (. local-fns action-str) {})] 49 | (tset local-fns action-str current) 50 | (each [alias module (pairs binds)] 51 | (if (= :number (type alias)) 52 | (tset current (tostring module) true) 53 | (tset current (tostring alias) (tostring module))))))) 54 | 55 | (sorted-each 56 | (fn [action binds] 57 | (sorted-each 58 | (fn [alias-or-val val] 59 | (if (= true val) 60 | 61 | ;; {require-macros [bar]} 62 | (table.insert effects `(,(sym action) ,alias-or-val)) 63 | 64 | ;; {require {foo bar}} 65 | (do 66 | (table.insert aliases (sym alias-or-val)) 67 | (table.insert vals `(,(sym action) ,val))))) 68 | 69 | binds)) 70 | local-fns) 71 | 72 | (when locals 73 | (sorted-each 74 | (fn [alias val] 75 | (table.insert aliases (sym alias)) 76 | (table.insert vals `(-> ,module-sym (. :aniseed/locals) (. ,alias)))) 77 | locals)) 78 | 79 | `[,effects 80 | (local ,aliases 81 | (let [(ok?# val#) 82 | (pcall 83 | (fn [] ,vals))] 84 | (if ok?# 85 | (do 86 | (tset ,module-sym :aniseed/local-fns ,local-fns) 87 | val#) 88 | (print val#)))) 89 | (local ,(sym "*module*") ,module-sym) 90 | (local ,(sym "*module-name*") ,(tostring name))])] 91 | (. 2))) 92 | 93 | (fn def- [name value] 94 | `(local ,name 95 | (let [v# ,value 96 | t# (. ,module-sym :aniseed/locals)] 97 | (tset t# ,(tostring name) v#) 98 | v#))) 99 | 100 | (fn def [name value] 101 | `(def- ,name 102 | (do 103 | (let [v# ,value] 104 | (tset ,module-sym ,(tostring name) v#) 105 | v#)))) 106 | 107 | (fn defn- [name ...] 108 | `(def- ,name (fn ,name ,...))) 109 | 110 | (fn defn [name ...] 111 | `(def ,name (fn ,name ,...))) 112 | 113 | (fn defonce- [name value] 114 | `(def- ,name 115 | (or (. (. ,module-sym :aniseed/locals) ,(tostring name)) 116 | ,value))) 117 | 118 | (fn defonce [name value] 119 | `(def ,name 120 | (or (. ,module-sym ,(tostring name)) 121 | ,value))) 122 | 123 | (fn deftest [name ...] 124 | `(let [tests# (or (. ,module-sym :aniseed/tests) {})] 125 | (tset tests# ,(tostring name) (fn [,(sym :t)] ,...)) 126 | (tset ,module-sym :aniseed/tests tests#))) 127 | 128 | (fn time [...] 129 | `(let [start# (vim.loop.hrtime) 130 | result# (do ,...) 131 | end# (vim.loop.hrtime)] 132 | (print (.. "Elapsed time: " (/ (- end# start#) 1000000) " msecs")) 133 | result#)) 134 | 135 | {:module module 136 | :def- def- :def def 137 | :defn- defn- :defn defn 138 | :defonce- defonce- :defonce defonce 139 | :deftest deftest 140 | :time time} 141 | -------------------------------------------------------------------------------- /fnl/nvim-tetris/io.fnl: -------------------------------------------------------------------------------- 1 | (module nvim-tetris.io 2 | {require {a nvim-tetris.aniseed.core 3 | v nvim-tetris.aniseed.view 4 | const nvim-tetris.const 5 | util nvim-tetris.util}}) 6 | 7 | (def- api vim.api) 8 | (def- piece_ns_name "piece_ns") 9 | (def- shadow_ns_name "shadow_ns") 10 | (def- locked_ns_name "locked_ns") 11 | (var buf nil) 12 | (var win nil) 13 | (var piece_ns nil) ; namespace for piece highlights 14 | (var shadow_ns nil) ; namespace for shadow highlights 15 | (var locked_ns nil) ; namespace for locked highlights 16 | 17 | (def- square_width 2) ; number of columns in a board square 18 | (def- square_height 1) ; number of rows in a board square 19 | (def- square_bytes_per_char 3) 20 | (def- header_height 1) 21 | (def- win_char_width (* const.screen_cols square_width)) ; window width in chars 22 | (def- win_char_height (+ (* const.screen_rows square_height) header_height)) ; window height in chars 23 | 24 | (defn remove_row [row] 25 | (let [buf_row (a.inc (- const.screen_rows row)) 26 | top_row 1] 27 | (api.nvim_buf_set_lines buf buf_row (a.inc buf_row) false []) 28 | (api.nvim_buf_set_lines buf top_row top_row false [(string.rep "██" const.screen_cols)]) 29 | (api.nvim_buf_add_highlight buf -1 "TetrisBackground" top_row 0 -1))) 30 | 31 | ; draw the play board to the screen 32 | ; relevant api functions: 33 | ; - nvim_buf_set_lines for setting entire lines 34 | ; - nvim_buf_set_text for setting segments of lines 35 | ; NOTE: nvim_buf_add_highlight is byte indexed 36 | ; - need to convert from columns to bytes before calling it 37 | ; [{:coords [col row] :colour "string"}] -> nil 38 | (defn draw_squares [squares ns] 39 | (let [filtered_squares (util.squares_in_bounds squares)] 40 | (each [i square (ipairs filtered_squares)] 41 | (let [{:coords [col row] : colour} square 42 | x (a.dec col) 43 | y (+ (- const.screen_rows row) header_height) 44 | start_col (* x 2) 45 | start_hl (* start_col 3) 46 | end_hl (+ start_hl (* square_width square_bytes_per_char))] 47 | (api.nvim_buf_add_highlight buf ns colour y start_hl end_hl))))) 48 | 49 | (defn draw_piece_squares [squares] 50 | (draw_squares squares piece_ns)) 51 | 52 | (defn draw_shadow_squares [squares] 53 | (draw_squares squares shadow_ns)) 54 | 55 | (defn draw_locked_squares [squares] 56 | (draw_squares squares locked_ns)) 57 | 58 | (defn clear_ns [ns] 59 | (api.nvim_buf_clear_namespace buf ns 0 -1)) 60 | 61 | (defn clear_piece_ns [] 62 | (clear_ns piece_ns)) 63 | 64 | (defn clear_shadow_ns [] 65 | (clear_ns shadow_ns)) 66 | 67 | (defn clear_locked_ns [] 68 | (clear_ns locked_ns)) 69 | 70 | ; Just a helper for centering a string horizontally in a buffer 71 | (defn- center [str] 72 | (let [width (api.nvim_win_get_width 0) 73 | shift (- (math.floor (/ width 2)) (math.floor (/ (string.len str) 2)))] 74 | (.. (string.rep " " shift) str))) 75 | 76 | ; Sets all the tetris highlights based on the `colours` array in const.fnl 77 | (defn- init_highlights [] 78 | (each [group colours (pairs const.colours)] 79 | (api.nvim_command (.. "hi " group " guifg=" colours.guifg " ctermfg=" colours.ctermfg)))) 80 | 81 | ; create the initial buffer and window for drawing the game in 82 | (defn init_window [] 83 | (set buf (api.nvim_create_buf false true)) 84 | (api.nvim_buf_set_option buf "bufhidden" "wipe") 85 | (api.nvim_buf_set_option buf "filetype" "tetris") 86 | (api.nvim_buf_set_name buf "tetris") 87 | (let [width (api.nvim_get_option "columns") 88 | height (api.nvim_get_option "lines") 89 | col (math.ceil (/ (- width win_char_width) 2)) 90 | row (math.ceil (a.dec (/ (- height win_char_height) 2))) 91 | border_opts {:style "minimal" 92 | :relative "editor" 93 | :width win_char_width 94 | :height win_char_height 95 | :row (a.dec row) 96 | :col (a.dec col)} 97 | opts {:style "minimal" 98 | :relative "editor" 99 | :width win_char_width 100 | :height win_char_height 101 | : row 102 | : col}] 103 | (set win (api.nvim_open_win buf true opts)) 104 | (api.nvim_buf_set_lines buf 0 -1 false [(center "Tetris")]) 105 | (for [i 1 const.screen_rows] 106 | (api.nvim_buf_set_lines buf i i false [(string.rep "██" const.screen_cols)]) 107 | (api.nvim_buf_add_highlight buf -1 "TetrisBackground" i 0 -1)) 108 | (api.nvim_buf_add_highlight buf -1 "TetrisHeader" 0 0 -1)) 109 | (set piece_ns (api.nvim_create_namespace piece_ns_name)) 110 | (set shadow_ns (api.nvim_create_namespace shadow_ns_name)) 111 | (set locked_ns (api.nvim_create_namespace locked_ns_name)) 112 | (init_highlights)) 113 | 114 | (defn set_game_maps [] 115 | (let [mappings {"" "move_left()" 116 | "" "move_right()" 117 | "" "rotate()" 118 | "" "soft_drop()" 119 | "" "hard_drop()"}] 120 | (each [k v (pairs mappings)] 121 | (api.nvim_buf_set_keymap buf "n" k (.. ":lua require\"nvim-tetris.game\"." v "") {:nowait true 122 | :noremap true 123 | :silent true})) 124 | (let [other_chars ["a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"]] 125 | (each [k v (ipairs other_chars)] 126 | (api.nvim_buf_set_keymap buf "n" v "" {:nowait true :noremap true :silent true}) 127 | (api.nvim_buf_set_keymap buf "n" (string.upper v) "" {:nowait true :noremap true :silent true}) 128 | (api.nvim_buf_set_keymap buf "n" (.. "") "" {:nowait true :noremap true :silent true}))))) 129 | 130 | (defn prepare_game_cleanup [] 131 | (api.nvim_command "autocmd BufWipeout tetris lua require(\"nvim-tetris.game\").stop_game()")) 132 | 133 | ; (defn- draw_some_squares [] 134 | ; (init_window) 135 | ; (global squares [{:coords [10 4] 136 | ; :colour "TetrisIPiece"} 137 | ; {:coords [1 9] 138 | ; :colour "TetrisJPiece"} 139 | ; {:coords [2 4] 140 | ; :colour "TetrisLPiece"} 141 | ; {:coords [5 19] 142 | ; :colour "TetrisOPiece"} 143 | ; {:coords [4 20] 144 | ; :colour "TetrisSPiece"} 145 | ; {:coords [6 6] 146 | ; :colour "TetrisTPiece"} 147 | ; {:coords [9 1] 148 | ; :colour "TetrisZPiece"}]) 149 | ; (draw_squares squares)) 150 | ; (draw_some_squares) 151 | -------------------------------------------------------------------------------- /lua/nvim-tetris/const.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.const" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local _2amodule_2a = _0_0 34 | local _2amodule_name_2a = "nvim-tetris.const" 35 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 36 | local rows = nil 37 | do 38 | local v_0_ = nil 39 | do 40 | local v_0_0 = 24 41 | _0_0["rows"] = v_0_0 42 | v_0_ = v_0_0 43 | end 44 | local t_0_ = (_0_0)["aniseed/locals"] 45 | t_0_["rows"] = v_0_ 46 | rows = v_0_ 47 | end 48 | local columns = nil 49 | do 50 | local v_0_ = nil 51 | do 52 | local v_0_0 = 10 53 | _0_0["columns"] = v_0_0 54 | v_0_ = v_0_0 55 | end 56 | local t_0_ = (_0_0)["aniseed/locals"] 57 | t_0_["columns"] = v_0_ 58 | columns = v_0_ 59 | end 60 | local screen_rows = nil 61 | do 62 | local v_0_ = nil 63 | do 64 | local v_0_0 = 20 65 | _0_0["screen_rows"] = v_0_0 66 | v_0_ = v_0_0 67 | end 68 | local t_0_ = (_0_0)["aniseed/locals"] 69 | t_0_["screen_rows"] = v_0_ 70 | screen_rows = v_0_ 71 | end 72 | local screen_cols = nil 73 | do 74 | local v_0_ = nil 75 | do 76 | local v_0_0 = 10 77 | _0_0["screen_cols"] = v_0_0 78 | v_0_ = v_0_0 79 | end 80 | local t_0_ = (_0_0)["aniseed/locals"] 81 | t_0_["screen_cols"] = v_0_ 82 | screen_cols = v_0_ 83 | end 84 | local max_level = nil 85 | do 86 | local v_0_ = nil 87 | do 88 | local v_0_0 = 18 89 | _0_0["max_level"] = v_0_0 90 | v_0_ = v_0_0 91 | end 92 | local t_0_ = (_0_0)["aniseed/locals"] 93 | t_0_["max_level"] = v_0_ 94 | max_level = v_0_ 95 | end 96 | local frame_delay = nil 97 | do 98 | local v_0_ = nil 99 | do 100 | local v_0_0 = math.floor((1000 / 60)) 101 | _0_0["frame_delay"] = v_0_0 102 | v_0_ = v_0_0 103 | end 104 | local t_0_ = (_0_0)["aniseed/locals"] 105 | t_0_["frame_delay"] = v_0_ 106 | frame_delay = v_0_ 107 | end 108 | local lock_delay = nil 109 | do 110 | local v_0_ = nil 111 | do 112 | local v_0_0 = 10 113 | _0_0["lock_delay"] = v_0_0 114 | v_0_ = v_0_0 115 | end 116 | local t_0_ = (_0_0)["aniseed/locals"] 117 | t_0_["lock_delay"] = v_0_ 118 | lock_delay = v_0_ 119 | end 120 | local entry_delay = nil 121 | do 122 | local v_0_ = nil 123 | do 124 | local v_0_0 = 10 125 | _0_0["entry_delay"] = v_0_0 126 | v_0_ = v_0_0 127 | end 128 | local t_0_ = (_0_0)["aniseed/locals"] 129 | t_0_["entry_delay"] = v_0_ 130 | entry_delay = v_0_ 131 | end 132 | local lines_per_level = nil 133 | do 134 | local v_0_ = nil 135 | do 136 | local v_0_0 = 10 137 | _0_0["lines_per_level"] = v_0_0 138 | v_0_ = v_0_0 139 | end 140 | local t_0_ = (_0_0)["aniseed/locals"] 141 | t_0_["lines_per_level"] = v_0_ 142 | lines_per_level = v_0_ 143 | end 144 | local game_states = nil 145 | do 146 | local v_0_ = nil 147 | do 148 | local v_0_0 = {appearing = 0, falling = 1, gameover = 5, intro = 3, locking = 2, paused = 4} 149 | _0_0["game_states"] = v_0_0 150 | v_0_ = v_0_0 151 | end 152 | local t_0_ = (_0_0)["aniseed/locals"] 153 | t_0_["game_states"] = v_0_ 154 | game_states = v_0_ 155 | end 156 | local colours = nil 157 | do 158 | local v_0_ = nil 159 | do 160 | local v_0_0 = {TetrisBackground = {ctermfg = "Black", guifg = "Black"}, TetrisHeader = {ctermfg = "DarkGray", guifg = "DarkGray"}, TetrisIPiece = {ctermfg = "Cyan", guifg = "Cyan"}, TetrisJPiece = {ctermfg = "Blue", guifg = "Blue"}, TetrisLPiece = {ctermfg = "Brown", guifg = "Orange"}, TetrisOPiece = {ctermfg = "Yellow", guifg = "Yellow"}, TetrisSPiece = {ctermfg = "Green", guifg = "Green"}, TetrisShadow = {ctermfg = "LightGray", guifg = "LightGray"}, TetrisTPiece = {ctermfg = "DarkMagenta", guifg = "Purple"}, TetrisZPiece = {ctermfg = "Red", guifg = "Red"}} 161 | _0_0["colours"] = v_0_0 162 | v_0_ = v_0_0 163 | end 164 | local t_0_ = (_0_0)["aniseed/locals"] 165 | t_0_["colours"] = v_0_ 166 | colours = v_0_ 167 | end 168 | local wallkick_offsets = nil 169 | do 170 | local v_0_ = nil 171 | do 172 | local v_0_0 = {I = {{{-1, 0}, {0, 0}, {0, 0}, {0, 1}, {0, -2}}, {{-1, 1}, {1, 1}, {-2, 1}, {1, 0}, {-2, 0}}, {{0, 1}, {0, 1}, {0, 1}, {0, -1}, {0, 2}}, [0] = {{0, 0}, {-1, 0}, {2, 0}, {-1, 0}, {2, 0}}}, O = {{{0, -1}}, {{-1, -1}}, {{-1, 0}}, [0] = {{0, 0}}}, normal = {{{0, 0}, {1, 0}, {1, -1}, {0, 2}, {1, 2}}, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, {{0, 0}, {-1, 0}, {-1, -1}, {0, 2}, {-1, 2}}, [0] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}}} 173 | _0_0["wallkick_offsets"] = v_0_0 174 | v_0_ = v_0_0 175 | end 176 | local t_0_ = (_0_0)["aniseed/locals"] 177 | t_0_["wallkick_offsets"] = v_0_ 178 | wallkick_offsets = v_0_ 179 | end 180 | local piece_types = nil 181 | do 182 | local v_0_ = nil 183 | do 184 | local v_0_0 = {{colour = "TetrisIPiece", name = "I", square_offsets = {{-1, 0}, {0, 0}, {1, 0}, {2, 0}}, wallkick_offsets = wallkick_offsets.I}, {colour = "TetrisJPiece", name = "J", square_offsets = {{-1, 1}, {-1, 0}, {0, 0}, {1, 0}}, wallkick_offsets = wallkick_offsets.normal}, {colour = "TetrisLPiece", name = "L", square_offsets = {{-1, 0}, {0, 0}, {1, 0}, {1, 1}}, wallkick_offsets = wallkick_offsets.normal}, {colour = "TetrisOPiece", name = "O", square_offsets = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}, wallkick_offsets = wallkick_offsets.O}, {colour = "TetrisSPiece", name = "S", square_offsets = {{-1, 0}, {0, 0}, {0, 1}, {1, 1}}, wallkick_offsets = wallkick_offsets.normal}, {colour = "TetrisTPiece", name = "T", square_offsets = {{-1, 0}, {0, 0}, {0, 1}, {1, 0}}, wallkick_offsets = wallkick_offsets.normal}, {colour = "TetrisZPiece", name = "Z", square_offsets = {{-1, 1}, {0, 0}, {0, 1}, {1, 0}}, wallkick_offsets = wallkick_offsets.normal}} 185 | _0_0["piece_types"] = v_0_0 186 | v_0_ = v_0_0 187 | end 188 | local t_0_ = (_0_0)["aniseed/locals"] 189 | t_0_["piece_types"] = v_0_ 190 | piece_types = v_0_ 191 | end 192 | local gravity = nil 193 | do 194 | local v_0_ = nil 195 | do 196 | local v_0_0 = {25, 20, 16, 13, 10, 8, 6, 7, 6, 5, 4, 4, 3, 3, 2, 2, 1, 1, [0] = 30} 197 | _0_0["gravity"] = v_0_0 198 | v_0_ = v_0_0 199 | end 200 | local t_0_ = (_0_0)["aniseed/locals"] 201 | t_0_["gravity"] = v_0_ 202 | gravity = v_0_ 203 | end 204 | return nil -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/test.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.aniseed.test" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {require("nvim-tetris.aniseed.core"), require("nvim-tetris.aniseed.nvim"), require("nvim-tetris.aniseed.string")} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {require = {a = "nvim-tetris.aniseed.core", nvim = "nvim-tetris.aniseed.nvim", str = "nvim-tetris.aniseed.string"}} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local a = _local_0_[1] 34 | local nvim = _local_0_[2] 35 | local str = _local_0_[3] 36 | local _2amodule_2a = _0_0 37 | local _2amodule_name_2a = "nvim-tetris.aniseed.test" 38 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 39 | local ok_3f = nil 40 | do 41 | local v_0_ = nil 42 | do 43 | local v_0_0 = nil 44 | local function ok_3f0(_2_0) 45 | local _arg_0_ = _2_0 46 | local tests = _arg_0_["tests"] 47 | local tests_passed = _arg_0_["tests-passed"] 48 | return (tests == tests_passed) 49 | end 50 | v_0_0 = ok_3f0 51 | _0_0["ok?"] = v_0_0 52 | v_0_ = v_0_0 53 | end 54 | local t_0_ = (_0_0)["aniseed/locals"] 55 | t_0_["ok?"] = v_0_ 56 | ok_3f = v_0_ 57 | end 58 | local display_results = nil 59 | do 60 | local v_0_ = nil 61 | do 62 | local v_0_0 = nil 63 | local function display_results0(results, prefix) 64 | do 65 | local _let_0_ = results 66 | local assertions = _let_0_["assertions"] 67 | local assertions_passed = _let_0_["assertions-passed"] 68 | local tests = _let_0_["tests"] 69 | local tests_passed = _let_0_["tests-passed"] 70 | local _2_ 71 | if ok_3f(results) then 72 | _2_ = "OK" 73 | else 74 | _2_ = "FAILED" 75 | end 76 | a.println((prefix .. " " .. _2_ .. " " .. tests_passed .. "/" .. tests .. " tests and " .. assertions_passed .. "/" .. assertions .. " assertions passed")) 77 | end 78 | return results 79 | end 80 | v_0_0 = display_results0 81 | _0_0["display-results"] = v_0_0 82 | v_0_ = v_0_0 83 | end 84 | local t_0_ = (_0_0)["aniseed/locals"] 85 | t_0_["display-results"] = v_0_ 86 | display_results = v_0_ 87 | end 88 | local run = nil 89 | do 90 | local v_0_ = nil 91 | do 92 | local v_0_0 = nil 93 | local function run0(mod_name) 94 | local mod = package.loaded[mod_name] 95 | local tests = (a["table?"](mod) and mod["aniseed/tests"]) 96 | if a["table?"](tests) then 97 | local results = {["assertions-passed"] = 0, ["tests-passed"] = 0, assertions = 0, tests = #tests} 98 | for label, f in pairs(tests) do 99 | local test_failed = false 100 | a.update(results, "tests", a.inc) 101 | do 102 | local prefix = ("[" .. mod_name .. "/" .. label .. "]") 103 | local fail = nil 104 | local function _2_(desc, ...) 105 | test_failed = true 106 | local function _3_(...) 107 | if desc then 108 | return (" (" .. desc .. ")") 109 | else 110 | return "" 111 | end 112 | end 113 | return a.println((str.join({prefix, " ", ...}) .. _3_(...))) 114 | end 115 | fail = _2_ 116 | local begin = nil 117 | local function _3_() 118 | return a.update(results, "assertions", a.inc) 119 | end 120 | begin = _3_ 121 | local pass = nil 122 | local function _4_() 123 | return a.update(results, "assertions-passed", a.inc) 124 | end 125 | pass = _4_ 126 | local t = nil 127 | local function _5_(e, r, desc) 128 | begin() 129 | if (e == r) then 130 | return pass() 131 | else 132 | return fail(desc, "Expected '", a["pr-str"](e), "' but received '", a["pr-str"](r), "'") 133 | end 134 | end 135 | local function _6_(r, desc) 136 | begin() 137 | if r then 138 | return pass() 139 | else 140 | return fail(desc, "Expected truthy result but received '", a["pr-str"](r), "'") 141 | end 142 | end 143 | local function _7_(e, r, desc) 144 | begin() 145 | local se = a["pr-str"](e) 146 | local sr = a["pr-str"](r) 147 | if (se == sr) then 148 | return pass() 149 | else 150 | return fail(desc, "Expected (with pr) '", se, "' but received '", sr, "'") 151 | end 152 | end 153 | t = {["="] = _5_, ["ok?"] = _6_, ["pr="] = _7_} 154 | local _8_0, _9_0 = nil, nil 155 | local function _10_() 156 | return f(t) 157 | end 158 | _8_0, _9_0 = pcall(_10_) 159 | if ((_8_0 == false) and (nil ~= _9_0)) then 160 | local err = _9_0 161 | fail("Exception: ", err) 162 | end 163 | end 164 | if not test_failed then 165 | a.update(results, "tests-passed", a.inc) 166 | end 167 | end 168 | return display_results(results, ("[" .. mod_name .. "]")) 169 | end 170 | end 171 | v_0_0 = run0 172 | _0_0["run"] = v_0_0 173 | v_0_ = v_0_0 174 | end 175 | local t_0_ = (_0_0)["aniseed/locals"] 176 | t_0_["run"] = v_0_ 177 | run = v_0_ 178 | end 179 | local run_all = nil 180 | do 181 | local v_0_ = nil 182 | do 183 | local v_0_0 = nil 184 | local function run_all0() 185 | local function _2_(totals, results) 186 | for k, v in pairs(results) do 187 | totals[k] = (v + totals[k]) 188 | end 189 | return totals 190 | end 191 | return display_results(a.reduce(_2_, {["assertions-passed"] = 0, ["tests-passed"] = 0, assertions = 0, tests = 0}, a.filter(a["table?"], a.map(run, a.keys(package.loaded)))), "[total]") 192 | end 193 | v_0_0 = run_all0 194 | _0_0["run-all"] = v_0_0 195 | v_0_ = v_0_0 196 | end 197 | local t_0_ = (_0_0)["aniseed/locals"] 198 | t_0_["run-all"] = v_0_ 199 | run_all = v_0_ 200 | end 201 | local suite = nil 202 | do 203 | local v_0_ = nil 204 | do 205 | local v_0_0 = nil 206 | local function suite0() 207 | local function _2_(path) 208 | return require(string.gsub(string.match(path, "^test/fnl/(.-).fnl$"), "/", ".")) 209 | end 210 | a["run!"](_2_, nvim.fn.globpath("test/fnl", "**/*-test.fnl", false, true)) 211 | if ok_3f(run_all()) then 212 | return nvim.ex.q() 213 | else 214 | return nvim.ex.cq() 215 | end 216 | end 217 | v_0_0 = suite0 218 | _0_0["suite"] = v_0_0 219 | v_0_ = v_0_0 220 | end 221 | local t_0_ = (_0_0)["aniseed/locals"] 222 | t_0_["suite"] = v_0_ 223 | suite = v_0_ 224 | end 225 | return nil 226 | -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/deps/nvim.lua: -------------------------------------------------------------------------------- 1 | -- Bring vim into local scope. 2 | local vim = vim 3 | local api = vim.api 4 | local inspect = vim.inspect 5 | 6 | local function extend(t, o) 7 | local mt = getmetatable(t) 8 | for k, v in pairs(o) do 9 | rawset(mt, k, v) 10 | end 11 | return t 12 | end 13 | 14 | -- Equivalent to `echo vim.inspect(...)` 15 | local function nvim_print(...) 16 | if select("#", ...) == 1 then 17 | api.nvim_out_write(inspect((...))) 18 | else 19 | api.nvim_out_write(inspect {...}) 20 | end 21 | api.nvim_out_write("\n") 22 | end 23 | 24 | --- Equivalent to `echo` EX command 25 | local function nvim_echo(...) 26 | for i = 1, select("#", ...) do 27 | local part = select(i, ...) 28 | api.nvim_out_write(tostring(part)) 29 | -- vim.api.nvim_out_write("\n") 30 | api.nvim_out_write(" ") 31 | end 32 | api.nvim_out_write("\n") 33 | end 34 | 35 | local window_options = { 36 | arab = true; arabic = true; breakindent = true; breakindentopt = true; 37 | bri = true; briopt = true; cc = true; cocu = true; 38 | cole = true; colorcolumn = true; concealcursor = true; conceallevel = true; 39 | crb = true; cuc = true; cul = true; cursorbind = true; 40 | cursorcolumn = true; cursorline = true; diff = true; fcs = true; 41 | fdc = true; fde = true; fdi = true; fdl = true; 42 | fdm = true; fdn = true; fdt = true; fen = true; 43 | fillchars = true; fml = true; fmr = true; foldcolumn = true; 44 | foldenable = true; foldexpr = true; foldignore = true; foldlevel = true; 45 | foldmarker = true; foldmethod = true; foldminlines = true; foldnestmax = true; 46 | foldtext = true; lbr = true; lcs = true; linebreak = true; 47 | list = true; listchars = true; nu = true; number = true; 48 | numberwidth = true; nuw = true; previewwindow = true; pvw = true; 49 | relativenumber = true; rightleft = true; rightleftcmd = true; rl = true; 50 | rlc = true; rnu = true; scb = true; scl = true; 51 | scr = true; scroll = true; scrollbind = true; signcolumn = true; 52 | spell = true; statusline = true; stl = true; wfh = true; 53 | wfw = true; winbl = true; winblend = true; winfixheight = true; 54 | winfixwidth = true; winhighlight = true; winhl = true; wrap = true; 55 | } 56 | 57 | local function validate(conf) 58 | assert(type(conf) == 'table') 59 | local type_names = { 60 | t='table', s='string', n='number', b='boolean', f='function', c='callable', 61 | ['table']='table', ['string']='string', ['number']='number', 62 | ['boolean']='boolean', ['function']='function', ['callable']='callable', 63 | ['nil']='nil', ['thread']='thread', ['userdata']='userdata', 64 | } 65 | for k, v in pairs(conf) do 66 | if not (v[3] and v[1] == nil) and type(v[1]) ~= type_names[v[2]] then 67 | error(string.format("validation_failed: %q: expected %s, received %s", k, type_names[v[2]], type(v[1]))) 68 | end 69 | end 70 | return true 71 | end 72 | 73 | local function make_meta_accessor(get, set, del) 74 | validate { 75 | get = {get, 'f'}; 76 | set = {set, 'f'}; 77 | del = {del, 'f', true}; 78 | } 79 | local mt = {} 80 | if del then 81 | function mt:__newindex(k, v) 82 | if v == nil then 83 | return del(k) 84 | end 85 | return set(k, v) 86 | end 87 | else 88 | function mt:__newindex(k, v) 89 | return set(k, v) 90 | end 91 | end 92 | function mt:__index(k) 93 | return get(k) 94 | end 95 | return setmetatable({}, mt) 96 | end 97 | 98 | local function pcall_ret(status, ...) 99 | if status then return ... end 100 | end 101 | 102 | local function nil_wrap(fn) 103 | return function(...) 104 | return pcall_ret(pcall(fn, ...)) 105 | end 106 | end 107 | 108 | local fn = setmetatable({}, { 109 | __index = function(t, k) 110 | local f = function(...) return api.nvim_call_function(k, {...}) end 111 | rawset(t, k, f) 112 | return f 113 | end 114 | }) 115 | 116 | local function getenv(k) 117 | local v = fn.getenv(k) 118 | if v == vim.NIL then 119 | return nil 120 | end 121 | return v 122 | end 123 | 124 | local function new_win_accessor(winnr) 125 | local function get(k) 126 | if winnr == nil and type(k) == 'number' then 127 | return new_win_accessor(k) 128 | end 129 | return api.nvim_win_get_var(winnr or 0, k) 130 | end 131 | local function set(k, v) return api.nvim_win_set_var(winnr or 0, k, v) end 132 | local function del(k) return api.nvim_win_del_var(winnr or 0, k) end 133 | return make_meta_accessor(nil_wrap(get), set, del) 134 | end 135 | 136 | local function new_win_opt_accessor(winnr) 137 | local function get(k) 138 | if winnr == nil and type(k) == 'number' then 139 | return new_win_opt_accessor(k) 140 | end 141 | return api.nvim_win_get_option(winnr or 0, k) 142 | end 143 | local function set(k, v) return api.nvim_win_set_option(winnr or 0, k, v) end 144 | return make_meta_accessor(nil_wrap(get), set) 145 | end 146 | 147 | local function new_buf_accessor(bufnr) 148 | local function get(k) 149 | if bufnr == nil and type(k) == 'number' then 150 | return new_buf_accessor(k) 151 | end 152 | return api.nvim_buf_get_var(bufnr or 0, k) 153 | end 154 | local function set(k, v) return api.nvim_buf_set_var(bufnr or 0, k, v) end 155 | local function del(k) return api.nvim_buf_del_var(bufnr or 0, k) end 156 | return make_meta_accessor(nil_wrap(get), set, del) 157 | end 158 | 159 | local function new_buf_opt_accessor(bufnr) 160 | local function get(k) 161 | if window_options[k] then 162 | return api.nvim_err_writeln(k.." is a window option, not a buffer option") 163 | end 164 | if bufnr == nil and type(k) == 'number' then 165 | return new_buf_opt_accessor(k) 166 | end 167 | return api.nvim_buf_get_option(bufnr or 0, k) 168 | end 169 | local function set(k, v) 170 | if window_options[k] then 171 | return api.nvim_err_writeln(k.." is a window option, not a buffer option") 172 | end 173 | return api.nvim_buf_set_option(bufnr or 0, k, v) 174 | end 175 | return make_meta_accessor(nil_wrap(get), set) 176 | end 177 | 178 | -- `nvim.$method(...)` redirects to `nvim.api.nvim_$method(...)` 179 | -- `nvim.fn.$method(...)` redirects to `vim.api.nvim_call_function($method, {...})` 180 | -- TODO `nvim.ex.$command(...)` is approximately `:$command {...}.join(" ")` 181 | -- `nvim.print(...)` is approximately `echo vim.inspect(...)` 182 | -- `nvim.echo(...)` is approximately `echo table.concat({...}, '\n')` 183 | -- Both methods cache the inital lookup in the metatable, but there is api small overhead regardless. 184 | return setmetatable({ 185 | print = nvim_print; 186 | echo = nvim_echo; 187 | fn = rawget(vim, "fn") or fn; 188 | validate = validate; 189 | g = rawget(vim, 'g') or make_meta_accessor(nil_wrap(api.nvim_get_var), api.nvim_set_var, api.nvim_del_var); 190 | v = rawget(vim, 'v') or make_meta_accessor(nil_wrap(api.nvim_get_vvar), api.nvim_set_vvar); 191 | o = rawget(vim, 'o') or make_meta_accessor(api.nvim_get_option, api.nvim_set_option); 192 | w = new_win_accessor(nil); 193 | b = new_buf_accessor(nil); 194 | env = rawget(vim, "env") or make_meta_accessor(getenv, fn.setenv); 195 | wo = rawget(vim, "wo") or new_win_opt_accessor(nil); 196 | bo = rawget(vim, "bo") or new_buf_opt_accessor(nil); 197 | buf = { 198 | line = api.nvim_get_current_line; 199 | nr = api.nvim_get_current_buf; 200 | }; 201 | ex = setmetatable({}, { 202 | __index = function(t, k) 203 | local command = k:gsub("_$", "!") 204 | local f = function(...) 205 | return api.nvim_command(table.concat(vim.tbl_flatten {command, ...}, " ")) 206 | end 207 | rawset(t, k, f) 208 | return f 209 | end 210 | }); 211 | }, { 212 | __index = function(t, k) 213 | local f = api['nvim_'..k] 214 | if f then 215 | rawset(t, k, f) 216 | end 217 | return f 218 | end 219 | }) 220 | -- vim:et ts=2 sw=2 221 | -------------------------------------------------------------------------------- /fnl/nvim-tetris/game.fnl: -------------------------------------------------------------------------------- 1 | (module nvim-tetris.game 2 | {require {const nvim-tetris.const 3 | util nvim-tetris.util 4 | v nvim-tetris.aniseed.view 5 | tetris_io nvim-tetris.io 6 | luv luv 7 | a nvim-tetris.aniseed.core}}) 8 | 9 | ; ------------ ALIASES ------------- 10 | 11 | (def- states const.game_states) 12 | (def- api vim.api) 13 | 14 | ; -------- CONSTS AND VARS --------- 15 | 16 | (var occupied_squares nil) ; 2D table of bools indicating squares occupied by locked pieces (for collision detection) 17 | (var piece nil) ; current piece being controlled by the player 18 | (var piece_pivot nil) ; current piece pivot location (column, row) 19 | (var shadow_offset nil) 20 | (var piece_rotation nil) 21 | (var game_state nil) 22 | (var timer nil) 23 | (var remaining_appearing_frames nil) 24 | (var falling_delay_frames nil) 25 | (var locking_delay_frames nil) 26 | 27 | ;; FOR LEVEL PROGRESSION 28 | (var level nil) 29 | (var lines_cleared nil) 30 | 31 | ;; FOR SAVING PIECES 32 | (var next_piece nil) ; TODO 33 | (var saved_piece nil) ; TODO 34 | 35 | ; --------- HELPER FUNCS ----------- 36 | 37 | (defn- remove_row [row] 38 | (for [r row (a.dec const.rows)] 39 | (for [c 1 const.columns] 40 | (tset (. occupied_squares r) c (. (. occupied_squares (a.inc r)) c)))) 41 | (for [c 1 const.columns] 42 | (tset (. occupied_squares const.rows) c false)) 43 | (tetris_io.remove_row row)) 44 | 45 | (defn- check_for_cleared_rows [piece_squares] 46 | (let [rows (util.get_square_rows piece_squares)] 47 | (each [_ row (ipairs rows)] 48 | (when (util.row_full? row occupied_squares) 49 | (remove_row row) 50 | (set lines_cleared (a.inc lines_cleared)) 51 | (when (= 0 (% lines_cleared const.lines_per_level)) 52 | (set level (a.inc level))))))) 53 | 54 | (defn- lock_piece [] 55 | (let [piece_squares (util.get_piece_squares piece_pivot piece piece_rotation)] 56 | (tetris_io.clear_piece_ns) 57 | (tetris_io.clear_shadow_ns) 58 | (tetris_io.draw_locked_squares piece_squares) 59 | (each [_ square (ipairs piece_squares)] 60 | (let [{:coords [col row]} square] 61 | (tset (. occupied_squares row) col true))) 62 | (check_for_cleared_rows piece_squares))) 63 | 64 | (defn- reset_falling_delay [] 65 | (set falling_delay_frames (util.get_gravity level))) 66 | 67 | ; use when pausing the game 68 | (defn- stop_timer [] 69 | (timer:stop)) 70 | 71 | ; use when quitting the game 72 | (defn- close_timer [] 73 | (timer:close)) 74 | 75 | ; ---------- INIT STATES ----------- 76 | 77 | (defn stop_game [] 78 | (when (not (timer:is_closing)) 79 | (close_timer))) 80 | 81 | (defn- do_game_over [] 82 | (print "Game over at level" level) 83 | (stop_game)) 84 | 85 | (defn- init_appearing [] 86 | (set remaining_appearing_frames const.entry_delay) 87 | (set piece (util.get_random_piece)) 88 | (set piece_pivot [5 20]) 89 | (set piece_rotation 0) 90 | (when (util.piece_collides_or_out_of_bounds? (util.get_piece_squares piece_pivot piece piece_rotation) occupied_squares) 91 | (do_game_over)) 92 | (set game_state states.appearing)) 93 | 94 | ; (util.piece_collides_or_out_of_bounds? (util.get_piece_squares [5 20] (. const.piece_types 1) 0) occupied_squares) 95 | ; (v.serialise occupied_squares) 96 | 97 | (defn- init_falling [] 98 | (reset_falling_delay) 99 | (set game_state states.falling)) 100 | 101 | (defn- init_locking [] 102 | (set locking_delay_frames const.lock_delay) 103 | (set game_state states.locking)) 104 | 105 | ; ----------- MOVEMENT ------------- 106 | 107 | (defn move_left [] 108 | (let [[col row] piece_pivot 109 | new_pivot [(a.dec col) row]] 110 | (when (not (util.piece_collides_or_out_of_bounds? (util.get_piece_squares new_pivot piece piece_rotation) occupied_squares)) 111 | (set piece_pivot new_pivot) 112 | (when (= game_state states.locking) 113 | (init_falling))))) 114 | 115 | (defn move_right [] 116 | (let [[col row] piece_pivot 117 | new_pivot [(a.inc col) row]] 118 | (when (not (util.piece_collides_or_out_of_bounds? (util.get_piece_squares new_pivot piece piece_rotation) occupied_squares)) 119 | (set piece_pivot new_pivot) 120 | (when (= game_state states.locking) 121 | (init_falling))))) 122 | 123 | (defn rotate [] 124 | (let [rotation_offset (util.get_rotation_offset piece_pivot piece piece_rotation (a.inc piece_rotation) occupied_squares)] 125 | (when (not (a.nil? rotation_offset)) 126 | (let [[d_x d_y] rotation_offset 127 | [x y] piece_pivot 128 | new_pivot [(+ x d_x) (+ y d_y)]] 129 | (set piece_pivot new_pivot) 130 | (set piece_rotation (a.inc piece_rotation)) 131 | (when (= game_state states.locking) 132 | (init_falling)))))) 133 | 134 | (defn soft_drop [] 135 | (let [[col row] piece_pivot 136 | new_pivot [col (a.dec row)]] 137 | (if (not (util.piece_collides_or_out_of_bounds? (util.get_piece_squares new_pivot piece piece_rotation) occupied_squares)) 138 | (set piece_pivot new_pivot)))) 139 | 140 | (defn hard_drop [] 141 | (let [[col row] piece_pivot 142 | new_pivot [col (- row shadow_offset)]] 143 | (if (not (util.piece_collides_or_out_of_bounds? (util.get_piece_squares new_pivot piece piece_rotation) occupied_squares)) 144 | (set piece_pivot new_pivot)))) 145 | 146 | ; ---------- FRAME LOGIC ----------- 147 | 148 | ; logic for a single frame when game is in the "appearing" state 149 | (defn- do_appearing_frame [] 150 | (if (> remaining_appearing_frames 0) 151 | (set remaining_appearing_frames (a.dec remaining_appearing_frames)) 152 | (init_falling))) 153 | 154 | ; logic for a single frame when game is in the "falling" state 155 | (defn- do_falling_frame [] 156 | (if (> falling_delay_frames 0) 157 | (set falling_delay_frames (a.dec falling_delay_frames)) 158 | (let [[col row] piece_pivot 159 | new_pivot [col (a.dec row)] 160 | new_squares (util.get_piece_squares new_pivot piece piece_rotation)] 161 | (if (not (util.piece_collides_or_out_of_bounds? new_squares occupied_squares)) 162 | (do 163 | (set piece_pivot new_pivot) 164 | (reset_falling_delay)) 165 | (init_locking))))) 166 | 167 | ; logic for a single frame when game is in the "locking" state 168 | (defn- do_locking_frame [] 169 | (if (> locking_delay_frames 0) 170 | (set locking_delay_frames (a.dec locking_delay_frames)) 171 | (do 172 | (lock_piece) 173 | (init_appearing)))) 174 | 175 | ; logic for a single frame when game is in the "intro" state 176 | (defn- do_intro_frame [] 177 | (comment "TODO") 178 | (init_appearing)) 179 | 180 | ; logic for a single frame when game is in the "paused" state 181 | (defn- do_paused_frame [] 182 | (comment "TODO")) 183 | 184 | ; logic for a single frame when game is in the "gameover" state 185 | (defn- do_gameover_frame [] 186 | (comment "TODO")) 187 | 188 | ; keep current piece in its own namespace, so its easy to clear 189 | ; clear highlights before moving and re-highlighting 190 | ; don't need to redraw locked pieces, they move when rows are inserted above 191 | (defn- draw_all_pieces [] 192 | (let [piece_squares (util.get_piece_squares piece_pivot piece piece_rotation) 193 | vert_dist (util.get_shadow_offset piece_squares occupied_squares) 194 | shadow_squares (util.get_shadow_squares piece_squares vert_dist)] 195 | (set shadow_offset vert_dist) 196 | (tetris_io.clear_piece_ns) ; clear the namespace for the current piece's highlights 197 | (tetris_io.clear_shadow_ns) ; clear the namespace for the current shadow's highlights 198 | (tetris_io.draw_shadow_squares shadow_squares) ; draw shadow 199 | (tetris_io.draw_piece_squares piece_squares))) ; draw current piece 200 | 201 | ; the logic to be executed on every game frame 202 | (defn- do_frame [] 203 | (print "Level:" level) 204 | (match game_state 205 | states.appearing (do_appearing_frame) 206 | states.falling (do_falling_frame) 207 | states.locking (do_locking_frame) 208 | states.intro (do_intro_frame) 209 | states.paused (do_paused_frame) 210 | states.gameover (do_gameover_frame)) 211 | (draw_all_pieces)) 212 | 213 | ; ---------- INIT FUNCTIONS ------------ 214 | 215 | ; starts the main game loop 216 | (defn- start_timer [] 217 | (timer:start const.frame_delay const.frame_delay (vim.schedule_wrap do_frame))) 218 | 219 | ; treat the row below, and the columns to the left and right of the board 220 | ; as if they are occupied by squares (for collision detection) 221 | (defn- init_occupied_squares [] 222 | (for [i 1 const.rows] 223 | (tset occupied_squares i {}) 224 | (for [j 1 const.columns] 225 | (tset (. occupied_squares i) j false)))) 226 | 227 | ; luv docs: https://github.com/luvit/luv/blob/master/docs.md 228 | ; Create a timer handle (implementation detail: uv_timer_t). 229 | (defn- init_timer [] 230 | (set timer (vim.loop.new_timer))) 231 | 232 | (defn- init_globals [] 233 | (set occupied_squares {}) 234 | (set piece {}) 235 | (set piece_pivot [5 20]) 236 | (set shadow_offset 0) 237 | (set piece_rotation 0) 238 | (set game_state states.intro) 239 | (set timer nil) 240 | (set remaining_appearing_frames 0) 241 | (set falling_delay_frames 0) 242 | (set locking_delay_frames 0) 243 | (set level 0) 244 | (set lines_cleared 0) 245 | (set next_piece 1) 246 | (set saved_piece 1)) 247 | 248 | (defn- init_game [] 249 | (init_globals) 250 | (init_occupied_squares) 251 | (init_timer) 252 | (start_timer)) 253 | 254 | ; ---------- MAIN FUNCTION ------------- 255 | 256 | (defn start [] 257 | (tetris_io.init_window) 258 | (tetris_io.set_game_maps) 259 | (tetris_io.prepare_game_cleanup) 260 | (init_game)) 261 | 262 | ; (start) 263 | ; (close_timer) 264 | ; (stop_timer) 265 | -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/deps/fennelview.lua: -------------------------------------------------------------------------------- 1 | local type_order = {["function"] = 5, boolean = 2, number = 1, string = 3, table = 4, thread = 7, userdata = 6} 2 | local function sort_keys(_0_0, _1_0) 3 | local _1_ = _0_0 4 | local a = _1_[1] 5 | local _2_ = _1_0 6 | local b = _2_[1] 7 | local ta = type(a) 8 | local tb = type(b) 9 | if ((ta == tb) and ((ta == "string") or (ta == "number"))) then 10 | return (a < b) 11 | else 12 | local dta = type_order[ta] 13 | local dtb = type_order[tb] 14 | if (dta and dtb) then 15 | return (dta < dtb) 16 | elseif dta then 17 | return true 18 | elseif dtb then 19 | return false 20 | else 21 | return (ta < tb) 22 | end 23 | end 24 | end 25 | local function table_kv_pairs(t) 26 | local assoc_3f = false 27 | local i = 1 28 | local kv = {} 29 | local insert = table.insert 30 | for k, v in pairs(t) do 31 | if ((type(k) ~= "number") or (k ~= i)) then 32 | assoc_3f = true 33 | end 34 | i = (i + 1) 35 | insert(kv, {k, v}) 36 | end 37 | table.sort(kv, sort_keys) 38 | if (#kv == 0) then 39 | return kv, "empty" 40 | else 41 | local function _2_() 42 | if assoc_3f then 43 | return "table" 44 | else 45 | return "seq" 46 | end 47 | end 48 | return kv, _2_() 49 | end 50 | end 51 | local function count_table_appearances(t, appearances) 52 | if (type(t) == "table") then 53 | if not appearances[t] then 54 | appearances[t] = 1 55 | for k, v in pairs(t) do 56 | count_table_appearances(k, appearances) 57 | count_table_appearances(v, appearances) 58 | end 59 | else 60 | appearances[t] = ((appearances[t] or 0) + 1) 61 | end 62 | end 63 | return appearances 64 | end 65 | local function save_table(t, seen) 66 | local seen0 = (seen or {len = 0}) 67 | local id = (seen0.len + 1) 68 | if not seen0[t] then 69 | seen0[t] = id 70 | seen0.len = id 71 | end 72 | return seen0 73 | end 74 | local function detect_cycle(t, seen, _3fk) 75 | if ("table" == type(t)) then 76 | seen[t] = true 77 | local _2_0, _3_0 = next(t, _3fk) 78 | if ((nil ~= _2_0) and (nil ~= _3_0)) then 79 | local k = _2_0 80 | local v = _3_0 81 | return (seen[k] or detect_cycle(k, seen) or seen[v] or detect_cycle(v, seen) or detect_cycle(t, seen, k)) 82 | end 83 | end 84 | end 85 | local function visible_cycle_3f(t, options) 86 | return (options["detect-cycles?"] and detect_cycle(t, {}) and save_table(t, options.seen) and (1 < (options.appearances[t] or 0))) 87 | end 88 | local function table_indent(t, indent, id) 89 | local opener_length = nil 90 | if id then 91 | opener_length = (#tostring(id) + 2) 92 | else 93 | opener_length = 1 94 | end 95 | return (indent + opener_length) 96 | end 97 | local pp = {} 98 | local function concat_table_lines(elements, options, multiline_3f, indent, table_type, prefix) 99 | local indent_str = ("\n" .. string.rep(" ", indent)) 100 | local open = nil 101 | local function _2_() 102 | if ("seq" == table_type) then 103 | return "[" 104 | else 105 | return "{" 106 | end 107 | end 108 | open = ((prefix or "") .. _2_()) 109 | local close = nil 110 | if ("seq" == table_type) then 111 | close = "]" 112 | else 113 | close = "}" 114 | end 115 | local oneline = (open .. table.concat(elements, " ") .. close) 116 | if (not options["one-line?"] and (multiline_3f or ((indent + #oneline) > options["line-length"]))) then 117 | return (open .. table.concat(elements, indent_str) .. close) 118 | else 119 | return oneline 120 | end 121 | end 122 | local function pp_associative(t, kv, options, indent, key_3f) 123 | local multiline_3f = false 124 | local id = options.seen[t] 125 | if (options.level >= options.depth) then 126 | return "{...}" 127 | elseif (id and options["detect-cycles?"]) then 128 | return ("@" .. id .. "{...}") 129 | else 130 | local visible_cycle_3f0 = visible_cycle_3f(t, options) 131 | local id0 = (visible_cycle_3f0 and options.seen[t]) 132 | local indent0 = table_indent(t, indent, id0) 133 | local slength = nil 134 | local function _3_() 135 | local _2_0 = rawget(_G, "utf8") 136 | if _2_0 then 137 | return _2_0.len 138 | else 139 | return _2_0 140 | end 141 | end 142 | local function _4_(_241) 143 | return #_241 144 | end 145 | slength = ((options["utf8?"] and _3_()) or _4_) 146 | local prefix = nil 147 | if visible_cycle_3f0 then 148 | prefix = ("@" .. id0) 149 | else 150 | prefix = "" 151 | end 152 | local elements = nil 153 | do 154 | local tbl_0_ = {} 155 | for _, _6_0 in pairs(kv) do 156 | local _7_ = _6_0 157 | local k = _7_[1] 158 | local v = _7_[2] 159 | local _8_ 160 | do 161 | local k0 = pp.pp(k, options, (indent0 + 1), true) 162 | local v0 = pp.pp(v, options, (indent0 + slength(k0) + 1)) 163 | multiline_3f = (multiline_3f or k0:find("\n") or v0:find("\n")) 164 | _8_ = (k0 .. " " .. v0) 165 | end 166 | tbl_0_[(#tbl_0_ + 1)] = _8_ 167 | end 168 | elements = tbl_0_ 169 | end 170 | return concat_table_lines(elements, options, multiline_3f, indent0, "table", prefix) 171 | end 172 | end 173 | local function pp_sequence(t, kv, options, indent) 174 | local multiline_3f = false 175 | local id = options.seen[t] 176 | if (options.level >= options.depth) then 177 | return "[...]" 178 | elseif (id and options["detect-cycles?"]) then 179 | return ("@" .. id .. "[...]") 180 | else 181 | local visible_cycle_3f0 = visible_cycle_3f(t, options) 182 | local id0 = (visible_cycle_3f0 and options.seen[t]) 183 | local indent0 = table_indent(t, indent, id0) 184 | local prefix = nil 185 | if visible_cycle_3f0 then 186 | prefix = ("@" .. id0) 187 | else 188 | prefix = "" 189 | end 190 | local elements = nil 191 | do 192 | local tbl_0_ = {} 193 | for _, _3_0 in pairs(kv) do 194 | local _4_ = _3_0 195 | local _0 = _4_[1] 196 | local v = _4_[2] 197 | local _5_ 198 | do 199 | local v0 = pp.pp(v, options, indent0) 200 | multiline_3f = (multiline_3f or v0:find("\n")) 201 | _5_ = v0 202 | end 203 | tbl_0_[(#tbl_0_ + 1)] = _5_ 204 | end 205 | elements = tbl_0_ 206 | end 207 | return concat_table_lines(elements, options, multiline_3f, indent0, "seq", prefix) 208 | end 209 | end 210 | local function concat_lines(lines, options, indent, force_multi_line_3f) 211 | if (#lines == 0) then 212 | if options["empty-as-sequence?"] then 213 | return "[]" 214 | else 215 | return "{}" 216 | end 217 | else 218 | local oneline = nil 219 | local _2_ 220 | do 221 | local tbl_0_ = {} 222 | for _, line in ipairs(lines) do 223 | tbl_0_[(#tbl_0_ + 1)] = line:gsub("^%s+", "") 224 | end 225 | _2_ = tbl_0_ 226 | end 227 | oneline = table.concat(_2_, " ") 228 | if (not options["one-line?"] and (force_multi_line_3f or oneline:find("\n") or ((indent + #oneline) > options["line-length"]))) then 229 | return table.concat(lines, ("\n" .. string.rep(" ", indent))) 230 | else 231 | return oneline 232 | end 233 | end 234 | end 235 | local function pp_metamethod(t, metamethod, options, indent) 236 | if (options.level >= options.depth) then 237 | if options["empty-as-sequence?"] then 238 | return "[...]" 239 | else 240 | return "{...}" 241 | end 242 | else 243 | local _ = nil 244 | local function _2_(_241) 245 | return visible_cycle_3f(_241, options) 246 | end 247 | options["visible-cycle?"] = _2_ 248 | _ = nil 249 | local lines, force_multi_line_3f = metamethod(t, pp.pp, options, indent) 250 | options["visible-cycle?"] = nil 251 | local _3_0 = type(lines) 252 | if (_3_0 == "string") then 253 | return lines 254 | elseif (_3_0 == "table") then 255 | return concat_lines(lines, options, indent, force_multi_line_3f) 256 | else 257 | local _0 = _3_0 258 | return error("Error: __fennelview metamethod must return a table of lines") 259 | end 260 | end 261 | end 262 | local function pp_table(x, options, indent) 263 | options.level = (options.level + 1) 264 | local x0 = nil 265 | do 266 | local _2_0 = nil 267 | if options["metamethod?"] then 268 | local _3_0 = x 269 | if _3_0 then 270 | local _4_0 = getmetatable(_3_0) 271 | if _4_0 then 272 | _2_0 = _4_0.__fennelview 273 | else 274 | _2_0 = _4_0 275 | end 276 | else 277 | _2_0 = _3_0 278 | end 279 | else 280 | _2_0 = nil 281 | end 282 | if (nil ~= _2_0) then 283 | local metamethod = _2_0 284 | x0 = pp_metamethod(x, metamethod, options, indent) 285 | else 286 | local _ = _2_0 287 | local _4_0, _5_0 = table_kv_pairs(x) 288 | if (true and (_5_0 == "empty")) then 289 | local _0 = _4_0 290 | if options["empty-as-sequence?"] then 291 | x0 = "[]" 292 | else 293 | x0 = "{}" 294 | end 295 | elseif ((nil ~= _4_0) and (_5_0 == "table")) then 296 | local kv = _4_0 297 | x0 = pp_associative(x, kv, options, indent) 298 | elseif ((nil ~= _4_0) and (_5_0 == "seq")) then 299 | local kv = _4_0 300 | x0 = pp_sequence(x, kv, options, indent) 301 | else 302 | x0 = nil 303 | end 304 | end 305 | end 306 | options.level = (options.level - 1) 307 | return x0 308 | end 309 | local function number__3estring(n) 310 | local _2_0 = string.gsub(tostring(n), ",", ".") 311 | return _2_0 312 | end 313 | local function colon_string_3f(s) 314 | return s:find("^[-%w?\\^_!$%&*+./@|<=>]+$") 315 | end 316 | local function make_options(t, options) 317 | local defaults = {["detect-cycles?"] = true, ["empty-as-sequence?"] = false, ["line-length"] = 80, ["metamethod?"] = true, ["one-line?"] = false, ["utf8?"] = true, depth = 128} 318 | local overrides = {appearances = count_table_appearances(t, {}), level = 0, seen = {len = 0}} 319 | for k, v in pairs((options or {})) do 320 | defaults[k] = v 321 | end 322 | for k, v in pairs(overrides) do 323 | defaults[k] = v 324 | end 325 | return defaults 326 | end 327 | pp.pp = function(x, options, indent, key_3f) 328 | local indent0 = (indent or 0) 329 | local options0 = (options or make_options(x)) 330 | local tv = type(x) 331 | local function _3_() 332 | local _2_0 = getmetatable(x) 333 | if _2_0 then 334 | return _2_0.__fennelview 335 | else 336 | return _2_0 337 | end 338 | end 339 | if ((tv == "table") or ((tv == "userdata") and _3_())) then 340 | return pp_table(x, options0, indent0) 341 | elseif (tv == "number") then 342 | return number__3estring(x) 343 | elseif ((tv == "string") and colon_string_3f(x) and ((key_3f ~= nil) or options0["prefer-colon?"])) then 344 | return (":" .. x) 345 | elseif (tv == "string") then 346 | local _4_0 = nil 347 | local function _5_() 348 | if options0["escape-newlines?"] then 349 | return "\\n" 350 | else 351 | return "\n" 352 | end 353 | end 354 | _4_0 = string.format("%q", x):gsub("\\\n", _5_()) 355 | return _4_0 356 | elseif ((tv == "boolean") or (tv == "nil")) then 357 | return tostring(x) 358 | else 359 | return ("#<" .. tostring(x) .. ">") 360 | end 361 | end 362 | local function view(x, options) 363 | return pp.pp(x, make_options(x, options), 0) 364 | end 365 | return view 366 | -------------------------------------------------------------------------------- /lua/nvim-tetris/io.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.io" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {require("nvim-tetris.aniseed.core"), require("nvim-tetris.const"), require("nvim-tetris.util"), require("nvim-tetris.aniseed.view")} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {require = {a = "nvim-tetris.aniseed.core", const = "nvim-tetris.const", util = "nvim-tetris.util", v = "nvim-tetris.aniseed.view"}} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local a = _local_0_[1] 34 | local const = _local_0_[2] 35 | local util = _local_0_[3] 36 | local v = _local_0_[4] 37 | local _2amodule_2a = _0_0 38 | local _2amodule_name_2a = "nvim-tetris.io" 39 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 40 | local api = nil 41 | do 42 | local v_0_ = vim.api 43 | local t_0_ = (_0_0)["aniseed/locals"] 44 | t_0_["api"] = v_0_ 45 | api = v_0_ 46 | end 47 | local piece_ns_name = nil 48 | do 49 | local v_0_ = "piece_ns" 50 | local t_0_ = (_0_0)["aniseed/locals"] 51 | t_0_["piece_ns_name"] = v_0_ 52 | piece_ns_name = v_0_ 53 | end 54 | local shadow_ns_name = nil 55 | do 56 | local v_0_ = "shadow_ns" 57 | local t_0_ = (_0_0)["aniseed/locals"] 58 | t_0_["shadow_ns_name"] = v_0_ 59 | shadow_ns_name = v_0_ 60 | end 61 | local locked_ns_name = nil 62 | do 63 | local v_0_ = "locked_ns" 64 | local t_0_ = (_0_0)["aniseed/locals"] 65 | t_0_["locked_ns_name"] = v_0_ 66 | locked_ns_name = v_0_ 67 | end 68 | local buf = nil 69 | local win = nil 70 | local piece_ns = nil 71 | local shadow_ns = nil 72 | local locked_ns = nil 73 | local square_width = nil 74 | do 75 | local v_0_ = 2 76 | local t_0_ = (_0_0)["aniseed/locals"] 77 | t_0_["square_width"] = v_0_ 78 | square_width = v_0_ 79 | end 80 | local square_height = nil 81 | do 82 | local v_0_ = 1 83 | local t_0_ = (_0_0)["aniseed/locals"] 84 | t_0_["square_height"] = v_0_ 85 | square_height = v_0_ 86 | end 87 | local square_bytes_per_char = nil 88 | do 89 | local v_0_ = 3 90 | local t_0_ = (_0_0)["aniseed/locals"] 91 | t_0_["square_bytes_per_char"] = v_0_ 92 | square_bytes_per_char = v_0_ 93 | end 94 | local header_height = nil 95 | do 96 | local v_0_ = 1 97 | local t_0_ = (_0_0)["aniseed/locals"] 98 | t_0_["header_height"] = v_0_ 99 | header_height = v_0_ 100 | end 101 | local win_char_width = nil 102 | do 103 | local v_0_ = (const.screen_cols * square_width) 104 | local t_0_ = (_0_0)["aniseed/locals"] 105 | t_0_["win_char_width"] = v_0_ 106 | win_char_width = v_0_ 107 | end 108 | local win_char_height = nil 109 | do 110 | local v_0_ = ((const.screen_rows * square_height) + header_height) 111 | local t_0_ = (_0_0)["aniseed/locals"] 112 | t_0_["win_char_height"] = v_0_ 113 | win_char_height = v_0_ 114 | end 115 | local remove_row = nil 116 | do 117 | local v_0_ = nil 118 | do 119 | local v_0_0 = nil 120 | local function remove_row0(row) 121 | local buf_row = a.inc((const.screen_rows - row)) 122 | local top_row = 1 123 | api.nvim_buf_set_lines(buf, buf_row, a.inc(buf_row), false, {}) 124 | api.nvim_buf_set_lines(buf, top_row, top_row, false, {string.rep("\226\150\136\226\150\136", const.screen_cols)}) 125 | return api.nvim_buf_add_highlight(buf, -1, "TetrisBackground", top_row, 0, -1) 126 | end 127 | v_0_0 = remove_row0 128 | _0_0["remove_row"] = v_0_0 129 | v_0_ = v_0_0 130 | end 131 | local t_0_ = (_0_0)["aniseed/locals"] 132 | t_0_["remove_row"] = v_0_ 133 | remove_row = v_0_ 134 | end 135 | local draw_squares = nil 136 | do 137 | local v_0_ = nil 138 | do 139 | local v_0_0 = nil 140 | local function draw_squares0(squares, ns) 141 | local filtered_squares = util.squares_in_bounds(squares) 142 | for i, square in ipairs(filtered_squares) do 143 | local _let_0_ = square 144 | local colour = _let_0_["colour"] 145 | local _let_1_ = _let_0_["coords"] 146 | local col = _let_1_[1] 147 | local row = _let_1_[2] 148 | local x = a.dec(col) 149 | local y = ((const.screen_rows - row) + header_height) 150 | local start_col = (x * 2) 151 | local start_hl = (start_col * 3) 152 | local end_hl = (start_hl + (square_width * square_bytes_per_char)) 153 | api.nvim_buf_add_highlight(buf, ns, colour, y, start_hl, end_hl) 154 | end 155 | return nil 156 | end 157 | v_0_0 = draw_squares0 158 | _0_0["draw_squares"] = v_0_0 159 | v_0_ = v_0_0 160 | end 161 | local t_0_ = (_0_0)["aniseed/locals"] 162 | t_0_["draw_squares"] = v_0_ 163 | draw_squares = v_0_ 164 | end 165 | local draw_piece_squares = nil 166 | do 167 | local v_0_ = nil 168 | do 169 | local v_0_0 = nil 170 | local function draw_piece_squares0(squares) 171 | return draw_squares(squares, piece_ns) 172 | end 173 | v_0_0 = draw_piece_squares0 174 | _0_0["draw_piece_squares"] = v_0_0 175 | v_0_ = v_0_0 176 | end 177 | local t_0_ = (_0_0)["aniseed/locals"] 178 | t_0_["draw_piece_squares"] = v_0_ 179 | draw_piece_squares = v_0_ 180 | end 181 | local draw_shadow_squares = nil 182 | do 183 | local v_0_ = nil 184 | do 185 | local v_0_0 = nil 186 | local function draw_shadow_squares0(squares) 187 | return draw_squares(squares, shadow_ns) 188 | end 189 | v_0_0 = draw_shadow_squares0 190 | _0_0["draw_shadow_squares"] = v_0_0 191 | v_0_ = v_0_0 192 | end 193 | local t_0_ = (_0_0)["aniseed/locals"] 194 | t_0_["draw_shadow_squares"] = v_0_ 195 | draw_shadow_squares = v_0_ 196 | end 197 | local draw_locked_squares = nil 198 | do 199 | local v_0_ = nil 200 | do 201 | local v_0_0 = nil 202 | local function draw_locked_squares0(squares) 203 | return draw_squares(squares, locked_ns) 204 | end 205 | v_0_0 = draw_locked_squares0 206 | _0_0["draw_locked_squares"] = v_0_0 207 | v_0_ = v_0_0 208 | end 209 | local t_0_ = (_0_0)["aniseed/locals"] 210 | t_0_["draw_locked_squares"] = v_0_ 211 | draw_locked_squares = v_0_ 212 | end 213 | local clear_ns = nil 214 | do 215 | local v_0_ = nil 216 | do 217 | local v_0_0 = nil 218 | local function clear_ns0(ns) 219 | return api.nvim_buf_clear_namespace(buf, ns, 0, -1) 220 | end 221 | v_0_0 = clear_ns0 222 | _0_0["clear_ns"] = v_0_0 223 | v_0_ = v_0_0 224 | end 225 | local t_0_ = (_0_0)["aniseed/locals"] 226 | t_0_["clear_ns"] = v_0_ 227 | clear_ns = v_0_ 228 | end 229 | local clear_piece_ns = nil 230 | do 231 | local v_0_ = nil 232 | do 233 | local v_0_0 = nil 234 | local function clear_piece_ns0() 235 | return clear_ns(piece_ns) 236 | end 237 | v_0_0 = clear_piece_ns0 238 | _0_0["clear_piece_ns"] = v_0_0 239 | v_0_ = v_0_0 240 | end 241 | local t_0_ = (_0_0)["aniseed/locals"] 242 | t_0_["clear_piece_ns"] = v_0_ 243 | clear_piece_ns = v_0_ 244 | end 245 | local clear_shadow_ns = nil 246 | do 247 | local v_0_ = nil 248 | do 249 | local v_0_0 = nil 250 | local function clear_shadow_ns0() 251 | return clear_ns(shadow_ns) 252 | end 253 | v_0_0 = clear_shadow_ns0 254 | _0_0["clear_shadow_ns"] = v_0_0 255 | v_0_ = v_0_0 256 | end 257 | local t_0_ = (_0_0)["aniseed/locals"] 258 | t_0_["clear_shadow_ns"] = v_0_ 259 | clear_shadow_ns = v_0_ 260 | end 261 | local clear_locked_ns = nil 262 | do 263 | local v_0_ = nil 264 | do 265 | local v_0_0 = nil 266 | local function clear_locked_ns0() 267 | return clear_ns(locked_ns) 268 | end 269 | v_0_0 = clear_locked_ns0 270 | _0_0["clear_locked_ns"] = v_0_0 271 | v_0_ = v_0_0 272 | end 273 | local t_0_ = (_0_0)["aniseed/locals"] 274 | t_0_["clear_locked_ns"] = v_0_ 275 | clear_locked_ns = v_0_ 276 | end 277 | local center = nil 278 | do 279 | local v_0_ = nil 280 | local function center0(str) 281 | local width = api.nvim_win_get_width(0) 282 | local shift = (math.floor((width / 2)) - math.floor((string.len(str) / 2))) 283 | return (string.rep(" ", shift) .. str) 284 | end 285 | v_0_ = center0 286 | local t_0_ = (_0_0)["aniseed/locals"] 287 | t_0_["center"] = v_0_ 288 | center = v_0_ 289 | end 290 | local init_highlights = nil 291 | do 292 | local v_0_ = nil 293 | local function init_highlights0() 294 | for group, colours in pairs(const.colours) do 295 | api.nvim_command(("hi " .. group .. " guifg=" .. colours.guifg .. " ctermfg=" .. colours.ctermfg)) 296 | end 297 | return nil 298 | end 299 | v_0_ = init_highlights0 300 | local t_0_ = (_0_0)["aniseed/locals"] 301 | t_0_["init_highlights"] = v_0_ 302 | init_highlights = v_0_ 303 | end 304 | local init_window = nil 305 | do 306 | local v_0_ = nil 307 | do 308 | local v_0_0 = nil 309 | local function init_window0() 310 | buf = api.nvim_create_buf(false, true) 311 | api.nvim_buf_set_option(buf, "bufhidden", "wipe") 312 | api.nvim_buf_set_option(buf, "filetype", "tetris") 313 | api.nvim_buf_set_name(buf, "tetris") 314 | do 315 | local width = api.nvim_get_option("columns") 316 | local height = api.nvim_get_option("lines") 317 | local col = math.ceil(((width - win_char_width) / 2)) 318 | local row = math.ceil(a.dec(((height - win_char_height) / 2))) 319 | local border_opts = {col = a.dec(col), height = win_char_height, relative = "editor", row = a.dec(row), style = "minimal", width = win_char_width} 320 | local opts = {col = col, height = win_char_height, relative = "editor", row = row, style = "minimal", width = win_char_width} 321 | win = api.nvim_open_win(buf, true, opts) 322 | api.nvim_buf_set_lines(buf, 0, -1, false, {center("Tetris")}) 323 | for i = 1, const.screen_rows do 324 | api.nvim_buf_set_lines(buf, i, i, false, {string.rep("\226\150\136\226\150\136", const.screen_cols)}) 325 | api.nvim_buf_add_highlight(buf, -1, "TetrisBackground", i, 0, -1) 326 | end 327 | api.nvim_buf_add_highlight(buf, -1, "TetrisHeader", 0, 0, -1) 328 | end 329 | piece_ns = api.nvim_create_namespace(piece_ns_name) 330 | shadow_ns = api.nvim_create_namespace(shadow_ns_name) 331 | locked_ns = api.nvim_create_namespace(locked_ns_name) 332 | return init_highlights() 333 | end 334 | v_0_0 = init_window0 335 | _0_0["init_window"] = v_0_0 336 | v_0_ = v_0_0 337 | end 338 | local t_0_ = (_0_0)["aniseed/locals"] 339 | t_0_["init_window"] = v_0_ 340 | init_window = v_0_ 341 | end 342 | local set_game_maps = nil 343 | do 344 | local v_0_ = nil 345 | do 346 | local v_0_0 = nil 347 | local function set_game_maps0() 348 | local mappings = {[""] = "soft_drop()", [""] = "move_left()", [""] = "move_right()", [""] = "hard_drop()", [""] = "rotate()"} 349 | for k, v0 in pairs(mappings) do 350 | api.nvim_buf_set_keymap(buf, "n", k, (":lua require\"nvim-tetris.game\"." .. v0 .. ""), {noremap = true, nowait = true, silent = true}) 351 | end 352 | local other_chars = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"} 353 | for k, v0 in ipairs(other_chars) do 354 | api.nvim_buf_set_keymap(buf, "n", v0, "", {noremap = true, nowait = true, silent = true}) 355 | api.nvim_buf_set_keymap(buf, "n", string.upper(v0), "", {noremap = true, nowait = true, silent = true}) 356 | api.nvim_buf_set_keymap(buf, "n", (""), "", {noremap = true, nowait = true, silent = true}) 357 | end 358 | return nil 359 | end 360 | v_0_0 = set_game_maps0 361 | _0_0["set_game_maps"] = v_0_0 362 | v_0_ = v_0_0 363 | end 364 | local t_0_ = (_0_0)["aniseed/locals"] 365 | t_0_["set_game_maps"] = v_0_ 366 | set_game_maps = v_0_ 367 | end 368 | local prepare_game_cleanup = nil 369 | do 370 | local v_0_ = nil 371 | do 372 | local v_0_0 = nil 373 | local function prepare_game_cleanup0() 374 | return api.nvim_command("autocmd BufWipeout tetris lua require(\"nvim-tetris.game\").stop_game()") 375 | end 376 | v_0_0 = prepare_game_cleanup0 377 | _0_0["prepare_game_cleanup"] = v_0_0 378 | v_0_ = v_0_0 379 | end 380 | local t_0_ = (_0_0)["aniseed/locals"] 381 | t_0_["prepare_game_cleanup"] = v_0_ 382 | prepare_game_cleanup = v_0_ 383 | end 384 | return nil -------------------------------------------------------------------------------- /lua/nvim-tetris/util.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.util" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {require("nvim-tetris.aniseed.core"), require("nvim-tetris.const"), require("nvim-tetris.aniseed.view")} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {require = {a = "nvim-tetris.aniseed.core", const = "nvim-tetris.const", v = "nvim-tetris.aniseed.view"}} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local a = _local_0_[1] 34 | local const = _local_0_[2] 35 | local v = _local_0_[3] 36 | local _2amodule_2a = _0_0 37 | local _2amodule_name_2a = "nvim-tetris.util" 38 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 39 | local unique = nil 40 | do 41 | local v_0_ = nil 42 | local function unique0(tbl) 43 | local vals = {} 44 | for _, val in ipairs(tbl) do 45 | vals[val] = true 46 | end 47 | return a.keys(vals) 48 | end 49 | v_0_ = unique0 50 | local t_0_ = (_0_0)["aniseed/locals"] 51 | t_0_["unique"] = v_0_ 52 | unique = v_0_ 53 | end 54 | local sort_descending = nil 55 | do 56 | local v_0_ = nil 57 | local function sort_descending0(tbl) 58 | local function _2_(a0, b) 59 | return (a0 > b) 60 | end 61 | table.sort(tbl, _2_) 62 | return tbl 63 | end 64 | v_0_ = sort_descending0 65 | local t_0_ = (_0_0)["aniseed/locals"] 66 | t_0_["sort_descending"] = v_0_ 67 | sort_descending = v_0_ 68 | end 69 | local add_pairs = nil 70 | do 71 | local v_0_ = nil 72 | local function add_pairs0(p1, p2) 73 | local _let_0_ = p1 74 | local x1 = _let_0_[1] 75 | local y1 = _let_0_[2] 76 | local _let_1_ = p2 77 | local x2 = _let_1_[1] 78 | local y2 = _let_1_[2] 79 | return {(x1 + x2), (y1 + y2)} 80 | end 81 | v_0_ = add_pairs0 82 | local t_0_ = (_0_0)["aniseed/locals"] 83 | t_0_["add_pairs"] = v_0_ 84 | add_pairs = v_0_ 85 | end 86 | local apply_rotation = nil 87 | do 88 | local v_0_ = nil 89 | local function apply_rotation0(piece, rotation) 90 | local _let_0_ = piece 91 | local offsets = _let_0_["square_offsets"] 92 | local mod = (rotation % 4) 93 | local tbl_0_ = {} 94 | for _, offset in ipairs(offsets) do 95 | local _2_ 96 | do 97 | local _let_1_ = offset 98 | local x = _let_1_[1] 99 | local y = _let_1_[2] 100 | if (0 == mod) then 101 | _2_ = offset 102 | elseif (1 == mod) then 103 | _2_ = {y, (0 - x)} 104 | elseif (2 == mod) then 105 | _2_ = {(0 - x), (0 - y)} 106 | else 107 | _2_ = {(0 - y), x} 108 | end 109 | end 110 | tbl_0_[(#tbl_0_ + 1)] = _2_ 111 | end 112 | return tbl_0_ 113 | end 114 | v_0_ = apply_rotation0 115 | local t_0_ = (_0_0)["aniseed/locals"] 116 | t_0_["apply_rotation"] = v_0_ 117 | apply_rotation = v_0_ 118 | end 119 | local out_of_game_bounds_3f = nil 120 | do 121 | local v_0_ = nil 122 | local function out_of_game_bounds_3f0(row, col) 123 | return ((row < 1) or (col < 1) or (row > const.rows) or (col > const.columns)) 124 | end 125 | v_0_ = out_of_game_bounds_3f0 126 | local t_0_ = (_0_0)["aniseed/locals"] 127 | t_0_["out_of_game_bounds?"] = v_0_ 128 | out_of_game_bounds_3f = v_0_ 129 | end 130 | local out_of_screen_bounds_3f = nil 131 | do 132 | local v_0_ = nil 133 | local function out_of_screen_bounds_3f0(row, col) 134 | return ((row < 1) or (col < 1) or (row > const.screen_rows) or (col > const.screen_cols)) 135 | end 136 | v_0_ = out_of_screen_bounds_3f0 137 | local t_0_ = (_0_0)["aniseed/locals"] 138 | t_0_["out_of_screen_bounds?"] = v_0_ 139 | out_of_screen_bounds_3f = v_0_ 140 | end 141 | local square_collides_or_out_of_bounds_3f = nil 142 | do 143 | local v_0_ = nil 144 | local function square_collides_or_out_of_bounds_3f0(row, col, occupied_squares) 145 | return (out_of_game_bounds_3f(row, col) or occupied_squares[row][col]) 146 | end 147 | v_0_ = square_collides_or_out_of_bounds_3f0 148 | local t_0_ = (_0_0)["aniseed/locals"] 149 | t_0_["square_collides_or_out_of_bounds?"] = v_0_ 150 | square_collides_or_out_of_bounds_3f = v_0_ 151 | end 152 | local square_collides_or_below_screen_3f = nil 153 | do 154 | local v_0_ = nil 155 | local function square_collides_or_below_screen_3f0(row, col, occupied_squares) 156 | return ((row < 1) or occupied_squares[row][col]) 157 | end 158 | v_0_ = square_collides_or_below_screen_3f0 159 | local t_0_ = (_0_0)["aniseed/locals"] 160 | t_0_["square_collides_or_below_screen?"] = v_0_ 161 | square_collides_or_below_screen_3f = v_0_ 162 | end 163 | local get_piece_squares = nil 164 | do 165 | local v_0_ = nil 166 | do 167 | local v_0_0 = nil 168 | local function get_piece_squares0(pivot, piece, rotation) 169 | local tbl_0_ = {} 170 | for _, offset in ipairs(apply_rotation(piece, rotation)) do 171 | tbl_0_[(#tbl_0_ + 1)] = {colour = piece.colour, coords = add_pairs(pivot, offset)} 172 | end 173 | return tbl_0_ 174 | end 175 | v_0_0 = get_piece_squares0 176 | _0_0["get_piece_squares"] = v_0_0 177 | v_0_ = v_0_0 178 | end 179 | local t_0_ = (_0_0)["aniseed/locals"] 180 | t_0_["get_piece_squares"] = v_0_ 181 | get_piece_squares = v_0_ 182 | end 183 | local get_gravity = nil 184 | do 185 | local v_0_ = nil 186 | do 187 | local v_0_0 = nil 188 | local function get_gravity0(level) 189 | if (level > const.max_level) then 190 | return 0 191 | else 192 | return const.gravity[level] 193 | end 194 | end 195 | v_0_0 = get_gravity0 196 | _0_0["get_gravity"] = v_0_0 197 | v_0_ = v_0_0 198 | end 199 | local t_0_ = (_0_0)["aniseed/locals"] 200 | t_0_["get_gravity"] = v_0_ 201 | get_gravity = v_0_ 202 | end 203 | local get_shadow_offset = nil 204 | do 205 | local v_0_ = nil 206 | do 207 | local v_0_0 = nil 208 | local function get_shadow_offset0(piece_squares, occupied_squares) 209 | local vert_dist = const.rows 210 | for _, square in ipairs(piece_squares) do 211 | local _let_0_ = square 212 | local _let_1_ = _let_0_["coords"] 213 | local col = _let_1_[1] 214 | local row = _let_1_[2] 215 | for shadow_row = row, 0, -1 do 216 | if square_collides_or_below_screen_3f(shadow_row, col, occupied_squares) then 217 | local diff = a.dec((row - shadow_row)) 218 | if (diff < vert_dist) then 219 | vert_dist = diff 220 | end 221 | break 222 | end 223 | end 224 | end 225 | return vert_dist 226 | end 227 | v_0_0 = get_shadow_offset0 228 | _0_0["get_shadow_offset"] = v_0_0 229 | v_0_ = v_0_0 230 | end 231 | local t_0_ = (_0_0)["aniseed/locals"] 232 | t_0_["get_shadow_offset"] = v_0_ 233 | get_shadow_offset = v_0_ 234 | end 235 | local get_shadow_squares = nil 236 | do 237 | local v_0_ = nil 238 | do 239 | local v_0_0 = nil 240 | local function get_shadow_squares0(piece_squares, vert_dist) 241 | local function _2_(square) 242 | local _let_0_ = square 243 | local colour = _let_0_["colour"] 244 | local _let_1_ = _let_0_["coords"] 245 | local col = _let_1_[1] 246 | local row = _let_1_[2] 247 | return {colour = "TetrisShadow", coords = {col, (row - vert_dist)}} 248 | end 249 | return a.map(_2_, piece_squares) 250 | end 251 | v_0_0 = get_shadow_squares0 252 | _0_0["get_shadow_squares"] = v_0_0 253 | v_0_ = v_0_0 254 | end 255 | local t_0_ = (_0_0)["aniseed/locals"] 256 | t_0_["get_shadow_squares"] = v_0_ 257 | get_shadow_squares = v_0_ 258 | end 259 | local piece_collides_or_out_of_bounds_3f = nil 260 | do 261 | local v_0_ = nil 262 | do 263 | local v_0_0 = nil 264 | local function piece_collides_or_out_of_bounds_3f0(piece_squares, occupied_squares) 265 | local function _2_(collides, square) 266 | local _let_0_ = square 267 | local _let_1_ = _let_0_["coords"] 268 | local col = _let_1_[1] 269 | local row = _let_1_[2] 270 | return (collides or square_collides_or_out_of_bounds_3f(row, col, occupied_squares)) 271 | end 272 | return a.reduce(_2_, false, piece_squares) 273 | end 274 | v_0_0 = piece_collides_or_out_of_bounds_3f0 275 | _0_0["piece_collides_or_out_of_bounds?"] = v_0_0 276 | v_0_ = v_0_0 277 | end 278 | local t_0_ = (_0_0)["aniseed/locals"] 279 | t_0_["piece_collides_or_out_of_bounds?"] = v_0_ 280 | piece_collides_or_out_of_bounds_3f = v_0_ 281 | end 282 | local get_random_piece = nil 283 | do 284 | local v_0_ = nil 285 | do 286 | local v_0_0 = nil 287 | local function get_random_piece0() 288 | return const.piece_types[math.ceil(a.rand(a.count(const.piece_types)))] 289 | end 290 | v_0_0 = get_random_piece0 291 | _0_0["get_random_piece"] = v_0_0 292 | v_0_ = v_0_0 293 | end 294 | local t_0_ = (_0_0)["aniseed/locals"] 295 | t_0_["get_random_piece"] = v_0_ 296 | get_random_piece = v_0_ 297 | end 298 | local row_full_3f = nil 299 | do 300 | local v_0_ = nil 301 | do 302 | local v_0_0 = nil 303 | local function row_full_3f0(row, occupied_squares) 304 | local function _2_(is_clear, val) 305 | return (is_clear and val) 306 | end 307 | return a.reduce(_2_, true, occupied_squares[row]) 308 | end 309 | v_0_0 = row_full_3f0 310 | _0_0["row_full?"] = v_0_0 311 | v_0_ = v_0_0 312 | end 313 | local t_0_ = (_0_0)["aniseed/locals"] 314 | t_0_["row_full?"] = v_0_ 315 | row_full_3f = v_0_ 316 | end 317 | local get_square_rows = nil 318 | do 319 | local v_0_ = nil 320 | do 321 | local v_0_0 = nil 322 | local function get_square_rows0(piece_squares) 323 | local function _2_(square) 324 | local _let_0_ = square 325 | local _let_1_ = _let_0_["coords"] 326 | local col = _let_1_[1] 327 | local row = _let_1_[2] 328 | return row 329 | end 330 | return sort_descending(unique(a.map(_2_, piece_squares))) 331 | end 332 | v_0_0 = get_square_rows0 333 | _0_0["get_square_rows"] = v_0_0 334 | v_0_ = v_0_0 335 | end 336 | local t_0_ = (_0_0)["aniseed/locals"] 337 | t_0_["get_square_rows"] = v_0_ 338 | get_square_rows = v_0_ 339 | end 340 | local squares_in_bounds = nil 341 | do 342 | local v_0_ = nil 343 | do 344 | local v_0_0 = nil 345 | local function squares_in_bounds0(squares) 346 | local function _2_(square) 347 | local _let_0_ = square 348 | local _let_1_ = _let_0_["coords"] 349 | local col = _let_1_[1] 350 | local row = _let_1_[2] 351 | return not out_of_screen_bounds_3f(row, col) 352 | end 353 | return a.filter(_2_, squares) 354 | end 355 | v_0_0 = squares_in_bounds0 356 | _0_0["squares_in_bounds"] = v_0_0 357 | v_0_ = v_0_0 358 | end 359 | local t_0_ = (_0_0)["aniseed/locals"] 360 | t_0_["squares_in_bounds"] = v_0_ 361 | squares_in_bounds = v_0_ 362 | end 363 | local get_trial_offsets = nil 364 | do 365 | local v_0_ = nil 366 | local function get_trial_offsets0(old_offsets, new_offsets) 367 | local trial_offsets = {} 368 | for i = 1, a.count(old_offsets) do 369 | local _let_0_ = old_offsets[i] 370 | local old_col = _let_0_[1] 371 | local old_row = _let_0_[2] 372 | local _let_1_ = new_offsets[i] 373 | local new_col = _let_1_[1] 374 | local new_row = _let_1_[2] 375 | table.insert(trial_offsets, {(old_col - new_col), (old_row - new_row)}) 376 | end 377 | return trial_offsets 378 | end 379 | v_0_ = get_trial_offsets0 380 | local t_0_ = (_0_0)["aniseed/locals"] 381 | t_0_["get_trial_offsets"] = v_0_ 382 | get_trial_offsets = v_0_ 383 | end 384 | local get_rotation_offset = nil 385 | do 386 | local v_0_ = nil 387 | do 388 | local v_0_0 = nil 389 | local function get_rotation_offset0(pivot, piece, old_rotation, new_rotation, occupied_squares) 390 | local rotation_offset = nil 391 | local old_offsets = piece.wallkick_offsets[(old_rotation % 4)] 392 | local new_offsets = piece.wallkick_offsets[(new_rotation % 4)] 393 | local trial_offsets = get_trial_offsets(old_offsets, new_offsets) 394 | for _, offset in ipairs(trial_offsets) do 395 | local _let_0_ = offset 396 | local d_x = _let_0_[1] 397 | local d_y = _let_0_[2] 398 | local _let_1_ = pivot 399 | local x = _let_1_[1] 400 | local y = _let_1_[2] 401 | local new_pivot = {(x + d_x), (y + d_y)} 402 | if not piece_collides_or_out_of_bounds_3f(get_piece_squares(new_pivot, piece, new_rotation), occupied_squares) then 403 | rotation_offset = offset 404 | break 405 | end 406 | end 407 | return rotation_offset 408 | end 409 | v_0_0 = get_rotation_offset0 410 | _0_0["get_rotation_offset"] = v_0_0 411 | v_0_ = v_0_0 412 | end 413 | local t_0_ = (_0_0)["aniseed/locals"] 414 | t_0_["get_rotation_offset"] = v_0_ 415 | get_rotation_offset = v_0_ 416 | end 417 | return nil -------------------------------------------------------------------------------- /lua/nvim-tetris/game.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.game" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {require("nvim-tetris.aniseed.core"), require("nvim-tetris.const"), require("luv"), require("nvim-tetris.io"), require("nvim-tetris.util"), require("nvim-tetris.aniseed.view")} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {require = {a = "nvim-tetris.aniseed.core", const = "nvim-tetris.const", luv = "luv", tetris_io = "nvim-tetris.io", util = "nvim-tetris.util", v = "nvim-tetris.aniseed.view"}} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local a = _local_0_[1] 34 | local const = _local_0_[2] 35 | local luv = _local_0_[3] 36 | local tetris_io = _local_0_[4] 37 | local util = _local_0_[5] 38 | local v = _local_0_[6] 39 | local _2amodule_2a = _0_0 40 | local _2amodule_name_2a = "nvim-tetris.game" 41 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 42 | local states = nil 43 | do 44 | local v_0_ = const.game_states 45 | local t_0_ = (_0_0)["aniseed/locals"] 46 | t_0_["states"] = v_0_ 47 | states = v_0_ 48 | end 49 | local api = nil 50 | do 51 | local v_0_ = vim.api 52 | local t_0_ = (_0_0)["aniseed/locals"] 53 | t_0_["api"] = v_0_ 54 | api = v_0_ 55 | end 56 | local occupied_squares = nil 57 | local piece = nil 58 | local piece_pivot = nil 59 | local shadow_offset = nil 60 | local piece_rotation = nil 61 | local game_state = nil 62 | local timer = nil 63 | local remaining_appearing_frames = nil 64 | local falling_delay_frames = nil 65 | local locking_delay_frames = nil 66 | local level = nil 67 | local lines_cleared = nil 68 | local next_piece = nil 69 | local saved_piece = nil 70 | local remove_row = nil 71 | do 72 | local v_0_ = nil 73 | local function remove_row0(row) 74 | for r = row, a.dec(const.rows) do 75 | for c = 1, const.columns do 76 | occupied_squares[r][c] = occupied_squares[a.inc(r)][c] 77 | end 78 | end 79 | for c = 1, const.columns do 80 | occupied_squares[const.rows][c] = false 81 | end 82 | return tetris_io.remove_row(row) 83 | end 84 | v_0_ = remove_row0 85 | local t_0_ = (_0_0)["aniseed/locals"] 86 | t_0_["remove_row"] = v_0_ 87 | remove_row = v_0_ 88 | end 89 | local check_for_cleared_rows = nil 90 | do 91 | local v_0_ = nil 92 | local function check_for_cleared_rows0(piece_squares) 93 | local rows = util.get_square_rows(piece_squares) 94 | for _, row in ipairs(rows) do 95 | if util["row_full?"](row, occupied_squares) then 96 | remove_row(row) 97 | lines_cleared = a.inc(lines_cleared) 98 | if (0 == (lines_cleared % const.lines_per_level)) then 99 | level = a.inc(level) 100 | end 101 | end 102 | end 103 | return nil 104 | end 105 | v_0_ = check_for_cleared_rows0 106 | local t_0_ = (_0_0)["aniseed/locals"] 107 | t_0_["check_for_cleared_rows"] = v_0_ 108 | check_for_cleared_rows = v_0_ 109 | end 110 | local lock_piece = nil 111 | do 112 | local v_0_ = nil 113 | local function lock_piece0() 114 | local piece_squares = util.get_piece_squares(piece_pivot, piece, piece_rotation) 115 | tetris_io.clear_piece_ns() 116 | tetris_io.clear_shadow_ns() 117 | tetris_io.draw_locked_squares(piece_squares) 118 | for _, square in ipairs(piece_squares) do 119 | local _let_0_ = square 120 | local _let_1_ = _let_0_["coords"] 121 | local col = _let_1_[1] 122 | local row = _let_1_[2] 123 | occupied_squares[row][col] = true 124 | end 125 | return check_for_cleared_rows(piece_squares) 126 | end 127 | v_0_ = lock_piece0 128 | local t_0_ = (_0_0)["aniseed/locals"] 129 | t_0_["lock_piece"] = v_0_ 130 | lock_piece = v_0_ 131 | end 132 | local reset_falling_delay = nil 133 | do 134 | local v_0_ = nil 135 | local function reset_falling_delay0() 136 | falling_delay_frames = util.get_gravity(level) 137 | return nil 138 | end 139 | v_0_ = reset_falling_delay0 140 | local t_0_ = (_0_0)["aniseed/locals"] 141 | t_0_["reset_falling_delay"] = v_0_ 142 | reset_falling_delay = v_0_ 143 | end 144 | local stop_timer = nil 145 | do 146 | local v_0_ = nil 147 | local function stop_timer0() 148 | return timer:stop() 149 | end 150 | v_0_ = stop_timer0 151 | local t_0_ = (_0_0)["aniseed/locals"] 152 | t_0_["stop_timer"] = v_0_ 153 | stop_timer = v_0_ 154 | end 155 | local close_timer = nil 156 | do 157 | local v_0_ = nil 158 | local function close_timer0() 159 | return timer:close() 160 | end 161 | v_0_ = close_timer0 162 | local t_0_ = (_0_0)["aniseed/locals"] 163 | t_0_["close_timer"] = v_0_ 164 | close_timer = v_0_ 165 | end 166 | local stop_game = nil 167 | do 168 | local v_0_ = nil 169 | do 170 | local v_0_0 = nil 171 | local function stop_game0() 172 | if not timer:is_closing() then 173 | return close_timer() 174 | end 175 | end 176 | v_0_0 = stop_game0 177 | _0_0["stop_game"] = v_0_0 178 | v_0_ = v_0_0 179 | end 180 | local t_0_ = (_0_0)["aniseed/locals"] 181 | t_0_["stop_game"] = v_0_ 182 | stop_game = v_0_ 183 | end 184 | local do_game_over = nil 185 | do 186 | local v_0_ = nil 187 | local function do_game_over0() 188 | print("Game over at level", level) 189 | return stop_game() 190 | end 191 | v_0_ = do_game_over0 192 | local t_0_ = (_0_0)["aniseed/locals"] 193 | t_0_["do_game_over"] = v_0_ 194 | do_game_over = v_0_ 195 | end 196 | local init_appearing = nil 197 | do 198 | local v_0_ = nil 199 | local function init_appearing0() 200 | remaining_appearing_frames = const.entry_delay 201 | piece = util.get_random_piece() 202 | piece_pivot = {5, 20} 203 | piece_rotation = 0 204 | if util["piece_collides_or_out_of_bounds?"](util.get_piece_squares(piece_pivot, piece, piece_rotation), occupied_squares) then 205 | do_game_over() 206 | end 207 | game_state = states.appearing 208 | return nil 209 | end 210 | v_0_ = init_appearing0 211 | local t_0_ = (_0_0)["aniseed/locals"] 212 | t_0_["init_appearing"] = v_0_ 213 | init_appearing = v_0_ 214 | end 215 | local init_falling = nil 216 | do 217 | local v_0_ = nil 218 | local function init_falling0() 219 | reset_falling_delay() 220 | game_state = states.falling 221 | return nil 222 | end 223 | v_0_ = init_falling0 224 | local t_0_ = (_0_0)["aniseed/locals"] 225 | t_0_["init_falling"] = v_0_ 226 | init_falling = v_0_ 227 | end 228 | local init_locking = nil 229 | do 230 | local v_0_ = nil 231 | local function init_locking0() 232 | locking_delay_frames = const.lock_delay 233 | game_state = states.locking 234 | return nil 235 | end 236 | v_0_ = init_locking0 237 | local t_0_ = (_0_0)["aniseed/locals"] 238 | t_0_["init_locking"] = v_0_ 239 | init_locking = v_0_ 240 | end 241 | local move_left = nil 242 | do 243 | local v_0_ = nil 244 | do 245 | local v_0_0 = nil 246 | local function move_left0() 247 | local _let_0_ = piece_pivot 248 | local col = _let_0_[1] 249 | local row = _let_0_[2] 250 | local new_pivot = {a.dec(col), row} 251 | if not util["piece_collides_or_out_of_bounds?"](util.get_piece_squares(new_pivot, piece, piece_rotation), occupied_squares) then 252 | piece_pivot = new_pivot 253 | if (game_state == states.locking) then 254 | return init_falling() 255 | end 256 | end 257 | end 258 | v_0_0 = move_left0 259 | _0_0["move_left"] = v_0_0 260 | v_0_ = v_0_0 261 | end 262 | local t_0_ = (_0_0)["aniseed/locals"] 263 | t_0_["move_left"] = v_0_ 264 | move_left = v_0_ 265 | end 266 | local move_right = nil 267 | do 268 | local v_0_ = nil 269 | do 270 | local v_0_0 = nil 271 | local function move_right0() 272 | local _let_0_ = piece_pivot 273 | local col = _let_0_[1] 274 | local row = _let_0_[2] 275 | local new_pivot = {a.inc(col), row} 276 | if not util["piece_collides_or_out_of_bounds?"](util.get_piece_squares(new_pivot, piece, piece_rotation), occupied_squares) then 277 | piece_pivot = new_pivot 278 | if (game_state == states.locking) then 279 | return init_falling() 280 | end 281 | end 282 | end 283 | v_0_0 = move_right0 284 | _0_0["move_right"] = v_0_0 285 | v_0_ = v_0_0 286 | end 287 | local t_0_ = (_0_0)["aniseed/locals"] 288 | t_0_["move_right"] = v_0_ 289 | move_right = v_0_ 290 | end 291 | local rotate = nil 292 | do 293 | local v_0_ = nil 294 | do 295 | local v_0_0 = nil 296 | local function rotate0() 297 | local rotation_offset = util.get_rotation_offset(piece_pivot, piece, piece_rotation, a.inc(piece_rotation), occupied_squares) 298 | if not a["nil?"](rotation_offset) then 299 | local _let_0_ = rotation_offset 300 | local d_x = _let_0_[1] 301 | local d_y = _let_0_[2] 302 | local _let_1_ = piece_pivot 303 | local x = _let_1_[1] 304 | local y = _let_1_[2] 305 | local new_pivot = {(x + d_x), (y + d_y)} 306 | piece_pivot = new_pivot 307 | piece_rotation = a.inc(piece_rotation) 308 | if (game_state == states.locking) then 309 | return init_falling() 310 | end 311 | end 312 | end 313 | v_0_0 = rotate0 314 | _0_0["rotate"] = v_0_0 315 | v_0_ = v_0_0 316 | end 317 | local t_0_ = (_0_0)["aniseed/locals"] 318 | t_0_["rotate"] = v_0_ 319 | rotate = v_0_ 320 | end 321 | local soft_drop = nil 322 | do 323 | local v_0_ = nil 324 | do 325 | local v_0_0 = nil 326 | local function soft_drop0() 327 | local _let_0_ = piece_pivot 328 | local col = _let_0_[1] 329 | local row = _let_0_[2] 330 | local new_pivot = {col, a.dec(row)} 331 | if not util["piece_collides_or_out_of_bounds?"](util.get_piece_squares(new_pivot, piece, piece_rotation), occupied_squares) then 332 | piece_pivot = new_pivot 333 | return nil 334 | end 335 | end 336 | v_0_0 = soft_drop0 337 | _0_0["soft_drop"] = v_0_0 338 | v_0_ = v_0_0 339 | end 340 | local t_0_ = (_0_0)["aniseed/locals"] 341 | t_0_["soft_drop"] = v_0_ 342 | soft_drop = v_0_ 343 | end 344 | local hard_drop = nil 345 | do 346 | local v_0_ = nil 347 | do 348 | local v_0_0 = nil 349 | local function hard_drop0() 350 | local _let_0_ = piece_pivot 351 | local col = _let_0_[1] 352 | local row = _let_0_[2] 353 | local new_pivot = {col, (row - shadow_offset)} 354 | if not util["piece_collides_or_out_of_bounds?"](util.get_piece_squares(new_pivot, piece, piece_rotation), occupied_squares) then 355 | piece_pivot = new_pivot 356 | return nil 357 | end 358 | end 359 | v_0_0 = hard_drop0 360 | _0_0["hard_drop"] = v_0_0 361 | v_0_ = v_0_0 362 | end 363 | local t_0_ = (_0_0)["aniseed/locals"] 364 | t_0_["hard_drop"] = v_0_ 365 | hard_drop = v_0_ 366 | end 367 | local do_appearing_frame = nil 368 | do 369 | local v_0_ = nil 370 | local function do_appearing_frame0() 371 | if (remaining_appearing_frames > 0) then 372 | remaining_appearing_frames = a.dec(remaining_appearing_frames) 373 | return nil 374 | else 375 | return init_falling() 376 | end 377 | end 378 | v_0_ = do_appearing_frame0 379 | local t_0_ = (_0_0)["aniseed/locals"] 380 | t_0_["do_appearing_frame"] = v_0_ 381 | do_appearing_frame = v_0_ 382 | end 383 | local do_falling_frame = nil 384 | do 385 | local v_0_ = nil 386 | local function do_falling_frame0() 387 | if (falling_delay_frames > 0) then 388 | falling_delay_frames = a.dec(falling_delay_frames) 389 | return nil 390 | else 391 | local _let_0_ = piece_pivot 392 | local col = _let_0_[1] 393 | local row = _let_0_[2] 394 | local new_pivot = {col, a.dec(row)} 395 | local new_squares = util.get_piece_squares(new_pivot, piece, piece_rotation) 396 | if not util["piece_collides_or_out_of_bounds?"](new_squares, occupied_squares) then 397 | piece_pivot = new_pivot 398 | return reset_falling_delay() 399 | else 400 | return init_locking() 401 | end 402 | end 403 | end 404 | v_0_ = do_falling_frame0 405 | local t_0_ = (_0_0)["aniseed/locals"] 406 | t_0_["do_falling_frame"] = v_0_ 407 | do_falling_frame = v_0_ 408 | end 409 | local do_locking_frame = nil 410 | do 411 | local v_0_ = nil 412 | local function do_locking_frame0() 413 | if (locking_delay_frames > 0) then 414 | locking_delay_frames = a.dec(locking_delay_frames) 415 | return nil 416 | else 417 | lock_piece() 418 | return init_appearing() 419 | end 420 | end 421 | v_0_ = do_locking_frame0 422 | local t_0_ = (_0_0)["aniseed/locals"] 423 | t_0_["do_locking_frame"] = v_0_ 424 | do_locking_frame = v_0_ 425 | end 426 | local do_intro_frame = nil 427 | do 428 | local v_0_ = nil 429 | local function do_intro_frame0() 430 | -- TODO 431 | return init_appearing() 432 | end 433 | v_0_ = do_intro_frame0 434 | local t_0_ = (_0_0)["aniseed/locals"] 435 | t_0_["do_intro_frame"] = v_0_ 436 | do_intro_frame = v_0_ 437 | end 438 | local do_paused_frame = nil 439 | do 440 | local v_0_ = nil 441 | local function do_paused_frame0() 442 | -- TODO 443 | return nil 444 | end 445 | v_0_ = do_paused_frame0 446 | local t_0_ = (_0_0)["aniseed/locals"] 447 | t_0_["do_paused_frame"] = v_0_ 448 | do_paused_frame = v_0_ 449 | end 450 | local do_gameover_frame = nil 451 | do 452 | local v_0_ = nil 453 | local function do_gameover_frame0() 454 | -- TODO 455 | return nil 456 | end 457 | v_0_ = do_gameover_frame0 458 | local t_0_ = (_0_0)["aniseed/locals"] 459 | t_0_["do_gameover_frame"] = v_0_ 460 | do_gameover_frame = v_0_ 461 | end 462 | local draw_all_pieces = nil 463 | do 464 | local v_0_ = nil 465 | local function draw_all_pieces0() 466 | local piece_squares = util.get_piece_squares(piece_pivot, piece, piece_rotation) 467 | local vert_dist = util.get_shadow_offset(piece_squares, occupied_squares) 468 | local shadow_squares = util.get_shadow_squares(piece_squares, vert_dist) 469 | shadow_offset = vert_dist 470 | tetris_io.clear_piece_ns() 471 | tetris_io.clear_shadow_ns() 472 | tetris_io.draw_shadow_squares(shadow_squares) 473 | return tetris_io.draw_piece_squares(piece_squares) 474 | end 475 | v_0_ = draw_all_pieces0 476 | local t_0_ = (_0_0)["aniseed/locals"] 477 | t_0_["draw_all_pieces"] = v_0_ 478 | draw_all_pieces = v_0_ 479 | end 480 | local do_frame = nil 481 | do 482 | local v_0_ = nil 483 | local function do_frame0() 484 | print("Level:", level) 485 | do 486 | local _2_0 = game_state 487 | if (_2_0 == states.appearing) then 488 | do_appearing_frame() 489 | elseif (_2_0 == states.falling) then 490 | do_falling_frame() 491 | elseif (_2_0 == states.locking) then 492 | do_locking_frame() 493 | elseif (_2_0 == states.intro) then 494 | do_intro_frame() 495 | elseif (_2_0 == states.paused) then 496 | do_paused_frame() 497 | elseif (_2_0 == states.gameover) then 498 | do_gameover_frame() 499 | end 500 | end 501 | return draw_all_pieces() 502 | end 503 | v_0_ = do_frame0 504 | local t_0_ = (_0_0)["aniseed/locals"] 505 | t_0_["do_frame"] = v_0_ 506 | do_frame = v_0_ 507 | end 508 | local start_timer = nil 509 | do 510 | local v_0_ = nil 511 | local function start_timer0() 512 | return timer:start(const.frame_delay, const.frame_delay, vim.schedule_wrap(do_frame)) 513 | end 514 | v_0_ = start_timer0 515 | local t_0_ = (_0_0)["aniseed/locals"] 516 | t_0_["start_timer"] = v_0_ 517 | start_timer = v_0_ 518 | end 519 | local init_occupied_squares = nil 520 | do 521 | local v_0_ = nil 522 | local function init_occupied_squares0() 523 | for i = 1, const.rows do 524 | occupied_squares[i] = {} 525 | for j = 1, const.columns do 526 | occupied_squares[i][j] = false 527 | end 528 | end 529 | return nil 530 | end 531 | v_0_ = init_occupied_squares0 532 | local t_0_ = (_0_0)["aniseed/locals"] 533 | t_0_["init_occupied_squares"] = v_0_ 534 | init_occupied_squares = v_0_ 535 | end 536 | local init_timer = nil 537 | do 538 | local v_0_ = nil 539 | local function init_timer0() 540 | timer = vim.loop.new_timer() 541 | return nil 542 | end 543 | v_0_ = init_timer0 544 | local t_0_ = (_0_0)["aniseed/locals"] 545 | t_0_["init_timer"] = v_0_ 546 | init_timer = v_0_ 547 | end 548 | local init_globals = nil 549 | do 550 | local v_0_ = nil 551 | local function init_globals0() 552 | occupied_squares = {} 553 | piece = {} 554 | piece_pivot = {5, 20} 555 | shadow_offset = 0 556 | piece_rotation = 0 557 | game_state = states.intro 558 | timer = nil 559 | remaining_appearing_frames = 0 560 | falling_delay_frames = 0 561 | locking_delay_frames = 0 562 | level = 0 563 | lines_cleared = 0 564 | next_piece = 1 565 | saved_piece = 1 566 | return nil 567 | end 568 | v_0_ = init_globals0 569 | local t_0_ = (_0_0)["aniseed/locals"] 570 | t_0_["init_globals"] = v_0_ 571 | init_globals = v_0_ 572 | end 573 | local init_game = nil 574 | do 575 | local v_0_ = nil 576 | local function init_game0() 577 | init_globals() 578 | init_occupied_squares() 579 | init_timer() 580 | return start_timer() 581 | end 582 | v_0_ = init_game0 583 | local t_0_ = (_0_0)["aniseed/locals"] 584 | t_0_["init_game"] = v_0_ 585 | init_game = v_0_ 586 | end 587 | local start = nil 588 | do 589 | local v_0_ = nil 590 | do 591 | local v_0_0 = nil 592 | local function start0() 593 | tetris_io.init_window() 594 | tetris_io.set_game_maps() 595 | tetris_io.prepare_game_cleanup() 596 | return init_game() 597 | end 598 | v_0_0 = start0 599 | _0_0["start"] = v_0_0 600 | v_0_ = v_0_0 601 | end 602 | local t_0_ = (_0_0)["aniseed/locals"] 603 | t_0_["start"] = v_0_ 604 | start = v_0_ 605 | end 606 | return nil -------------------------------------------------------------------------------- /lua/nvim-tetris/aniseed/core.lua: -------------------------------------------------------------------------------- 1 | local _0_0 = nil 2 | do 3 | local name_0_ = "nvim-tetris.aniseed.core" 4 | local module_0_ = nil 5 | do 6 | local x_0_ = package.loaded[name_0_] 7 | if ("table" == type(x_0_)) then 8 | module_0_ = x_0_ 9 | else 10 | module_0_ = {} 11 | end 12 | end 13 | module_0_["aniseed/module"] = name_0_ 14 | module_0_["aniseed/locals"] = ((module_0_)["aniseed/locals"] or {}) 15 | module_0_["aniseed/local-fns"] = ((module_0_)["aniseed/local-fns"] or {}) 16 | package.loaded[name_0_] = module_0_ 17 | _0_0 = module_0_ 18 | end 19 | local function _1_(...) 20 | local ok_3f_0_, val_0_ = nil, nil 21 | local function _1_() 22 | return {require("nvim-tetris.aniseed.view")} 23 | end 24 | ok_3f_0_, val_0_ = pcall(_1_) 25 | if ok_3f_0_ then 26 | _0_0["aniseed/local-fns"] = {require = {view = "nvim-tetris.aniseed.view"}} 27 | return val_0_ 28 | else 29 | return print(val_0_) 30 | end 31 | end 32 | local _local_0_ = _1_(...) 33 | local view = _local_0_[1] 34 | local _2amodule_2a = _0_0 35 | local _2amodule_name_2a = "nvim-tetris.aniseed.core" 36 | do local _ = ({nil, _0_0, {{}, nil, nil, nil}})[2] end 37 | math.randomseed(os.time()) 38 | local rand = nil 39 | do 40 | local v_0_ = nil 41 | do 42 | local v_0_0 = nil 43 | local function rand0(n) 44 | return (math.random() * (n or 1)) 45 | end 46 | v_0_0 = rand0 47 | _0_0["rand"] = v_0_0 48 | v_0_ = v_0_0 49 | end 50 | local t_0_ = (_0_0)["aniseed/locals"] 51 | t_0_["rand"] = v_0_ 52 | rand = v_0_ 53 | end 54 | local string_3f = nil 55 | do 56 | local v_0_ = nil 57 | do 58 | local v_0_0 = nil 59 | local function string_3f0(x) 60 | return ("string" == type(x)) 61 | end 62 | v_0_0 = string_3f0 63 | _0_0["string?"] = v_0_0 64 | v_0_ = v_0_0 65 | end 66 | local t_0_ = (_0_0)["aniseed/locals"] 67 | t_0_["string?"] = v_0_ 68 | string_3f = v_0_ 69 | end 70 | local nil_3f = nil 71 | do 72 | local v_0_ = nil 73 | do 74 | local v_0_0 = nil 75 | local function nil_3f0(x) 76 | return (nil == x) 77 | end 78 | v_0_0 = nil_3f0 79 | _0_0["nil?"] = v_0_0 80 | v_0_ = v_0_0 81 | end 82 | local t_0_ = (_0_0)["aniseed/locals"] 83 | t_0_["nil?"] = v_0_ 84 | nil_3f = v_0_ 85 | end 86 | local table_3f = nil 87 | do 88 | local v_0_ = nil 89 | do 90 | local v_0_0 = nil 91 | local function table_3f0(x) 92 | return ("table" == type(x)) 93 | end 94 | v_0_0 = table_3f0 95 | _0_0["table?"] = v_0_0 96 | v_0_ = v_0_0 97 | end 98 | local t_0_ = (_0_0)["aniseed/locals"] 99 | t_0_["table?"] = v_0_ 100 | table_3f = v_0_ 101 | end 102 | local count = nil 103 | do 104 | local v_0_ = nil 105 | do 106 | local v_0_0 = nil 107 | local function count0(xs) 108 | if table_3f(xs) then 109 | return table.maxn(xs) 110 | elseif not xs then 111 | return 0 112 | else 113 | return #xs 114 | end 115 | end 116 | v_0_0 = count0 117 | _0_0["count"] = v_0_0 118 | v_0_ = v_0_0 119 | end 120 | local t_0_ = (_0_0)["aniseed/locals"] 121 | t_0_["count"] = v_0_ 122 | count = v_0_ 123 | end 124 | local empty_3f = nil 125 | do 126 | local v_0_ = nil 127 | do 128 | local v_0_0 = nil 129 | local function empty_3f0(xs) 130 | return (0 == count(xs)) 131 | end 132 | v_0_0 = empty_3f0 133 | _0_0["empty?"] = v_0_0 134 | v_0_ = v_0_0 135 | end 136 | local t_0_ = (_0_0)["aniseed/locals"] 137 | t_0_["empty?"] = v_0_ 138 | empty_3f = v_0_ 139 | end 140 | local first = nil 141 | do 142 | local v_0_ = nil 143 | do 144 | local v_0_0 = nil 145 | local function first0(xs) 146 | if xs then 147 | return xs[1] 148 | end 149 | end 150 | v_0_0 = first0 151 | _0_0["first"] = v_0_0 152 | v_0_ = v_0_0 153 | end 154 | local t_0_ = (_0_0)["aniseed/locals"] 155 | t_0_["first"] = v_0_ 156 | first = v_0_ 157 | end 158 | local second = nil 159 | do 160 | local v_0_ = nil 161 | do 162 | local v_0_0 = nil 163 | local function second0(xs) 164 | if xs then 165 | return xs[2] 166 | end 167 | end 168 | v_0_0 = second0 169 | _0_0["second"] = v_0_0 170 | v_0_ = v_0_0 171 | end 172 | local t_0_ = (_0_0)["aniseed/locals"] 173 | t_0_["second"] = v_0_ 174 | second = v_0_ 175 | end 176 | local last = nil 177 | do 178 | local v_0_ = nil 179 | do 180 | local v_0_0 = nil 181 | local function last0(xs) 182 | if xs then 183 | return xs[count(xs)] 184 | end 185 | end 186 | v_0_0 = last0 187 | _0_0["last"] = v_0_0 188 | v_0_ = v_0_0 189 | end 190 | local t_0_ = (_0_0)["aniseed/locals"] 191 | t_0_["last"] = v_0_ 192 | last = v_0_ 193 | end 194 | local inc = nil 195 | do 196 | local v_0_ = nil 197 | do 198 | local v_0_0 = nil 199 | local function inc0(n) 200 | return (n + 1) 201 | end 202 | v_0_0 = inc0 203 | _0_0["inc"] = v_0_0 204 | v_0_ = v_0_0 205 | end 206 | local t_0_ = (_0_0)["aniseed/locals"] 207 | t_0_["inc"] = v_0_ 208 | inc = v_0_ 209 | end 210 | local dec = nil 211 | do 212 | local v_0_ = nil 213 | do 214 | local v_0_0 = nil 215 | local function dec0(n) 216 | return (n - 1) 217 | end 218 | v_0_0 = dec0 219 | _0_0["dec"] = v_0_0 220 | v_0_ = v_0_0 221 | end 222 | local t_0_ = (_0_0)["aniseed/locals"] 223 | t_0_["dec"] = v_0_ 224 | dec = v_0_ 225 | end 226 | local even_3f = nil 227 | do 228 | local v_0_ = nil 229 | do 230 | local v_0_0 = nil 231 | local function even_3f0(n) 232 | return ((n % 2) == 0) 233 | end 234 | v_0_0 = even_3f0 235 | _0_0["even?"] = v_0_0 236 | v_0_ = v_0_0 237 | end 238 | local t_0_ = (_0_0)["aniseed/locals"] 239 | t_0_["even?"] = v_0_ 240 | even_3f = v_0_ 241 | end 242 | local odd_3f = nil 243 | do 244 | local v_0_ = nil 245 | do 246 | local v_0_0 = nil 247 | local function odd_3f0(n) 248 | return not even_3f(n) 249 | end 250 | v_0_0 = odd_3f0 251 | _0_0["odd?"] = v_0_0 252 | v_0_ = v_0_0 253 | end 254 | local t_0_ = (_0_0)["aniseed/locals"] 255 | t_0_["odd?"] = v_0_ 256 | odd_3f = v_0_ 257 | end 258 | local keys = nil 259 | do 260 | local v_0_ = nil 261 | do 262 | local v_0_0 = nil 263 | local function keys0(t) 264 | local result = {} 265 | if t then 266 | for k, _ in pairs(t) do 267 | table.insert(result, k) 268 | end 269 | end 270 | return result 271 | end 272 | v_0_0 = keys0 273 | _0_0["keys"] = v_0_0 274 | v_0_ = v_0_0 275 | end 276 | local t_0_ = (_0_0)["aniseed/locals"] 277 | t_0_["keys"] = v_0_ 278 | keys = v_0_ 279 | end 280 | local vals = nil 281 | do 282 | local v_0_ = nil 283 | do 284 | local v_0_0 = nil 285 | local function vals0(t) 286 | local result = {} 287 | if t then 288 | for _, v in pairs(t) do 289 | table.insert(result, v) 290 | end 291 | end 292 | return result 293 | end 294 | v_0_0 = vals0 295 | _0_0["vals"] = v_0_0 296 | v_0_ = v_0_0 297 | end 298 | local t_0_ = (_0_0)["aniseed/locals"] 299 | t_0_["vals"] = v_0_ 300 | vals = v_0_ 301 | end 302 | local kv_pairs = nil 303 | do 304 | local v_0_ = nil 305 | do 306 | local v_0_0 = nil 307 | local function kv_pairs0(t) 308 | local result = {} 309 | if t then 310 | for k, v in pairs(t) do 311 | table.insert(result, {k, v}) 312 | end 313 | end 314 | return result 315 | end 316 | v_0_0 = kv_pairs0 317 | _0_0["kv-pairs"] = v_0_0 318 | v_0_ = v_0_0 319 | end 320 | local t_0_ = (_0_0)["aniseed/locals"] 321 | t_0_["kv-pairs"] = v_0_ 322 | kv_pairs = v_0_ 323 | end 324 | local run_21 = nil 325 | do 326 | local v_0_ = nil 327 | do 328 | local v_0_0 = nil 329 | local function run_210(f, xs) 330 | if xs then 331 | local nxs = count(xs) 332 | if (nxs > 0) then 333 | for i = 1, nxs do 334 | f(xs[i]) 335 | end 336 | return nil 337 | end 338 | end 339 | end 340 | v_0_0 = run_210 341 | _0_0["run!"] = v_0_0 342 | v_0_ = v_0_0 343 | end 344 | local t_0_ = (_0_0)["aniseed/locals"] 345 | t_0_["run!"] = v_0_ 346 | run_21 = v_0_ 347 | end 348 | local filter = nil 349 | do 350 | local v_0_ = nil 351 | do 352 | local v_0_0 = nil 353 | local function filter0(f, xs) 354 | local result = {} 355 | local function _2_(x) 356 | if f(x) then 357 | return table.insert(result, x) 358 | end 359 | end 360 | run_21(_2_, xs) 361 | return result 362 | end 363 | v_0_0 = filter0 364 | _0_0["filter"] = v_0_0 365 | v_0_ = v_0_0 366 | end 367 | local t_0_ = (_0_0)["aniseed/locals"] 368 | t_0_["filter"] = v_0_ 369 | filter = v_0_ 370 | end 371 | local map = nil 372 | do 373 | local v_0_ = nil 374 | do 375 | local v_0_0 = nil 376 | local function map0(f, xs) 377 | local result = {} 378 | local function _2_(x) 379 | local mapped = f(x) 380 | local function _3_() 381 | if (0 == select("#", mapped)) then 382 | return nil 383 | else 384 | return mapped 385 | end 386 | end 387 | return table.insert(result, _3_()) 388 | end 389 | run_21(_2_, xs) 390 | return result 391 | end 392 | v_0_0 = map0 393 | _0_0["map"] = v_0_0 394 | v_0_ = v_0_0 395 | end 396 | local t_0_ = (_0_0)["aniseed/locals"] 397 | t_0_["map"] = v_0_ 398 | map = v_0_ 399 | end 400 | local map_indexed = nil 401 | do 402 | local v_0_ = nil 403 | do 404 | local v_0_0 = nil 405 | local function map_indexed0(f, xs) 406 | return map(f, kv_pairs(xs)) 407 | end 408 | v_0_0 = map_indexed0 409 | _0_0["map-indexed"] = v_0_0 410 | v_0_ = v_0_0 411 | end 412 | local t_0_ = (_0_0)["aniseed/locals"] 413 | t_0_["map-indexed"] = v_0_ 414 | map_indexed = v_0_ 415 | end 416 | local identity = nil 417 | do 418 | local v_0_ = nil 419 | do 420 | local v_0_0 = nil 421 | local function identity0(x) 422 | return x 423 | end 424 | v_0_0 = identity0 425 | _0_0["identity"] = v_0_0 426 | v_0_ = v_0_0 427 | end 428 | local t_0_ = (_0_0)["aniseed/locals"] 429 | t_0_["identity"] = v_0_ 430 | identity = v_0_ 431 | end 432 | local reduce = nil 433 | do 434 | local v_0_ = nil 435 | do 436 | local v_0_0 = nil 437 | local function reduce0(f, init, xs) 438 | local result = init 439 | local function _2_(x) 440 | result = f(result, x) 441 | return nil 442 | end 443 | run_21(_2_, xs) 444 | return result 445 | end 446 | v_0_0 = reduce0 447 | _0_0["reduce"] = v_0_0 448 | v_0_ = v_0_0 449 | end 450 | local t_0_ = (_0_0)["aniseed/locals"] 451 | t_0_["reduce"] = v_0_ 452 | reduce = v_0_ 453 | end 454 | local some = nil 455 | do 456 | local v_0_ = nil 457 | do 458 | local v_0_0 = nil 459 | local function some0(f, xs) 460 | local result = nil 461 | local n = 1 462 | while (nil_3f(result) and (n <= count(xs))) do 463 | local candidate = f(xs[n]) 464 | if candidate then 465 | result = candidate 466 | end 467 | n = inc(n) 468 | end 469 | return result 470 | end 471 | v_0_0 = some0 472 | _0_0["some"] = v_0_0 473 | v_0_ = v_0_0 474 | end 475 | local t_0_ = (_0_0)["aniseed/locals"] 476 | t_0_["some"] = v_0_ 477 | some = v_0_ 478 | end 479 | local butlast = nil 480 | do 481 | local v_0_ = nil 482 | do 483 | local v_0_0 = nil 484 | local function butlast0(xs) 485 | local total = count(xs) 486 | local function _2_(_3_0) 487 | local _arg_0_ = _3_0 488 | local n = _arg_0_[1] 489 | local v = _arg_0_[2] 490 | return (n ~= total) 491 | end 492 | return map(second, filter(_2_, kv_pairs(xs))) 493 | end 494 | v_0_0 = butlast0 495 | _0_0["butlast"] = v_0_0 496 | v_0_ = v_0_0 497 | end 498 | local t_0_ = (_0_0)["aniseed/locals"] 499 | t_0_["butlast"] = v_0_ 500 | butlast = v_0_ 501 | end 502 | local rest = nil 503 | do 504 | local v_0_ = nil 505 | do 506 | local v_0_0 = nil 507 | local function rest0(xs) 508 | local function _2_(_3_0) 509 | local _arg_0_ = _3_0 510 | local n = _arg_0_[1] 511 | local v = _arg_0_[2] 512 | return (n ~= 1) 513 | end 514 | return map(second, filter(_2_, kv_pairs(xs))) 515 | end 516 | v_0_0 = rest0 517 | _0_0["rest"] = v_0_0 518 | v_0_ = v_0_0 519 | end 520 | local t_0_ = (_0_0)["aniseed/locals"] 521 | t_0_["rest"] = v_0_ 522 | rest = v_0_ 523 | end 524 | local concat = nil 525 | do 526 | local v_0_ = nil 527 | do 528 | local v_0_0 = nil 529 | local function concat0(...) 530 | local result = {} 531 | local function _2_(xs) 532 | local function _3_(x) 533 | return table.insert(result, x) 534 | end 535 | return run_21(_3_, xs) 536 | end 537 | run_21(_2_, {...}) 538 | return result 539 | end 540 | v_0_0 = concat0 541 | _0_0["concat"] = v_0_0 542 | v_0_ = v_0_0 543 | end 544 | local t_0_ = (_0_0)["aniseed/locals"] 545 | t_0_["concat"] = v_0_ 546 | concat = v_0_ 547 | end 548 | local mapcat = nil 549 | do 550 | local v_0_ = nil 551 | do 552 | local v_0_0 = nil 553 | local function mapcat0(f, xs) 554 | return concat(unpack(map(f, xs))) 555 | end 556 | v_0_0 = mapcat0 557 | _0_0["mapcat"] = v_0_0 558 | v_0_ = v_0_0 559 | end 560 | local t_0_ = (_0_0)["aniseed/locals"] 561 | t_0_["mapcat"] = v_0_ 562 | mapcat = v_0_ 563 | end 564 | local pr_str = nil 565 | do 566 | local v_0_ = nil 567 | do 568 | local v_0_0 = nil 569 | local function pr_str0(...) 570 | local s = nil 571 | local function _2_(x) 572 | return view.serialise(x, {["one-line"] = true}) 573 | end 574 | s = table.concat(map(_2_, {...}), " ") 575 | if (nil_3f(s) or ("" == s)) then 576 | return "nil" 577 | else 578 | return s 579 | end 580 | end 581 | v_0_0 = pr_str0 582 | _0_0["pr-str"] = v_0_0 583 | v_0_ = v_0_0 584 | end 585 | local t_0_ = (_0_0)["aniseed/locals"] 586 | t_0_["pr-str"] = v_0_ 587 | pr_str = v_0_ 588 | end 589 | local println = nil 590 | do 591 | local v_0_ = nil 592 | do 593 | local v_0_0 = nil 594 | local function println0(...) 595 | local function _2_(acc, s) 596 | return (acc .. s) 597 | end 598 | local function _3_(_4_0) 599 | local _arg_0_ = _4_0 600 | local i = _arg_0_[1] 601 | local s = _arg_0_[2] 602 | if (1 == i) then 603 | return s 604 | else 605 | return (" " .. s) 606 | end 607 | end 608 | local function _5_(s) 609 | if string_3f(s) then 610 | return s 611 | else 612 | return pr_str(s) 613 | end 614 | end 615 | return print(reduce(_2_, "", map_indexed(_3_, map(_5_, {...})))) 616 | end 617 | v_0_0 = println0 618 | _0_0["println"] = v_0_0 619 | v_0_ = v_0_0 620 | end 621 | local t_0_ = (_0_0)["aniseed/locals"] 622 | t_0_["println"] = v_0_ 623 | println = v_0_ 624 | end 625 | local pr = nil 626 | do 627 | local v_0_ = nil 628 | do 629 | local v_0_0 = nil 630 | local function pr0(...) 631 | return println(pr_str(...)) 632 | end 633 | v_0_0 = pr0 634 | _0_0["pr"] = v_0_0 635 | v_0_ = v_0_0 636 | end 637 | local t_0_ = (_0_0)["aniseed/locals"] 638 | t_0_["pr"] = v_0_ 639 | pr = v_0_ 640 | end 641 | local slurp = nil 642 | do 643 | local v_0_ = nil 644 | do 645 | local v_0_0 = nil 646 | local function slurp0(path, silent_3f) 647 | local _2_0, _3_0 = io.open(path, "r") 648 | if ((_2_0 == nil) and (nil ~= _3_0)) then 649 | local msg = _3_0 650 | return nil 651 | elseif (nil ~= _2_0) then 652 | local f = _2_0 653 | local content = f:read("*all") 654 | f:close() 655 | return content 656 | end 657 | end 658 | v_0_0 = slurp0 659 | _0_0["slurp"] = v_0_0 660 | v_0_ = v_0_0 661 | end 662 | local t_0_ = (_0_0)["aniseed/locals"] 663 | t_0_["slurp"] = v_0_ 664 | slurp = v_0_ 665 | end 666 | local spit = nil 667 | do 668 | local v_0_ = nil 669 | do 670 | local v_0_0 = nil 671 | local function spit0(path, content) 672 | local _2_0, _3_0 = io.open(path, "w") 673 | if ((_2_0 == nil) and (nil ~= _3_0)) then 674 | local msg = _3_0 675 | return error(("Could not open file: " .. msg)) 676 | elseif (nil ~= _2_0) then 677 | local f = _2_0 678 | f:write(content) 679 | f:close() 680 | return nil 681 | end 682 | end 683 | v_0_0 = spit0 684 | _0_0["spit"] = v_0_0 685 | v_0_ = v_0_0 686 | end 687 | local t_0_ = (_0_0)["aniseed/locals"] 688 | t_0_["spit"] = v_0_ 689 | spit = v_0_ 690 | end 691 | local merge_21 = nil 692 | do 693 | local v_0_ = nil 694 | do 695 | local v_0_0 = nil 696 | local function merge_210(base, ...) 697 | local function _2_(acc, m) 698 | if m then 699 | for k, v in pairs(m) do 700 | acc[k] = v 701 | end 702 | end 703 | return acc 704 | end 705 | return reduce(_2_, (base or {}), {...}) 706 | end 707 | v_0_0 = merge_210 708 | _0_0["merge!"] = v_0_0 709 | v_0_ = v_0_0 710 | end 711 | local t_0_ = (_0_0)["aniseed/locals"] 712 | t_0_["merge!"] = v_0_ 713 | merge_21 = v_0_ 714 | end 715 | local merge = nil 716 | do 717 | local v_0_ = nil 718 | do 719 | local v_0_0 = nil 720 | local function merge0(...) 721 | return merge_21({}, ...) 722 | end 723 | v_0_0 = merge0 724 | _0_0["merge"] = v_0_0 725 | v_0_ = v_0_0 726 | end 727 | local t_0_ = (_0_0)["aniseed/locals"] 728 | t_0_["merge"] = v_0_ 729 | merge = v_0_ 730 | end 731 | local select_keys = nil 732 | do 733 | local v_0_ = nil 734 | do 735 | local v_0_0 = nil 736 | local function select_keys0(t, ks) 737 | if (t and ks) then 738 | local function _2_(acc, k) 739 | if k then 740 | acc[k] = t[k] 741 | end 742 | return acc 743 | end 744 | return reduce(_2_, {}, ks) 745 | else 746 | return {} 747 | end 748 | end 749 | v_0_0 = select_keys0 750 | _0_0["select-keys"] = v_0_0 751 | v_0_ = v_0_0 752 | end 753 | local t_0_ = (_0_0)["aniseed/locals"] 754 | t_0_["select-keys"] = v_0_ 755 | select_keys = v_0_ 756 | end 757 | local get = nil 758 | do 759 | local v_0_ = nil 760 | do 761 | local v_0_0 = nil 762 | local function get0(t, k, d) 763 | local res = nil 764 | if table_3f(t) then 765 | local val = t[k] 766 | if not nil_3f(val) then 767 | res = val 768 | else 769 | res = nil 770 | end 771 | else 772 | res = nil 773 | end 774 | if nil_3f(res) then 775 | return d 776 | else 777 | return res 778 | end 779 | end 780 | v_0_0 = get0 781 | _0_0["get"] = v_0_0 782 | v_0_ = v_0_0 783 | end 784 | local t_0_ = (_0_0)["aniseed/locals"] 785 | t_0_["get"] = v_0_ 786 | get = v_0_ 787 | end 788 | local get_in = nil 789 | do 790 | local v_0_ = nil 791 | do 792 | local v_0_0 = nil 793 | local function get_in0(t, ks, d) 794 | local res = nil 795 | local function _2_(acc, k) 796 | if table_3f(acc) then 797 | return get(acc, k) 798 | end 799 | end 800 | res = reduce(_2_, t, ks) 801 | if nil_3f(res) then 802 | return d 803 | else 804 | return res 805 | end 806 | end 807 | v_0_0 = get_in0 808 | _0_0["get-in"] = v_0_0 809 | v_0_ = v_0_0 810 | end 811 | local t_0_ = (_0_0)["aniseed/locals"] 812 | t_0_["get-in"] = v_0_ 813 | get_in = v_0_ 814 | end 815 | local assoc = nil 816 | do 817 | local v_0_ = nil 818 | do 819 | local v_0_0 = nil 820 | local function assoc0(t, ...) 821 | local _let_0_ = {...} 822 | local k = _let_0_[1] 823 | local v = _let_0_[2] 824 | local xs = {(table.unpack or unpack)(_let_0_, 3)} 825 | local rem = count(xs) 826 | local t0 = (t or {}) 827 | if odd_3f(rem) then 828 | error("assoc expects even number of arguments after table, found odd number") 829 | end 830 | if not nil_3f(k) then 831 | t0[k] = v 832 | end 833 | if (rem > 0) then 834 | assoc0(t0, unpack(xs)) 835 | end 836 | return t0 837 | end 838 | v_0_0 = assoc0 839 | _0_0["assoc"] = v_0_0 840 | v_0_ = v_0_0 841 | end 842 | local t_0_ = (_0_0)["aniseed/locals"] 843 | t_0_["assoc"] = v_0_ 844 | assoc = v_0_ 845 | end 846 | local assoc_in = nil 847 | do 848 | local v_0_ = nil 849 | do 850 | local v_0_0 = nil 851 | local function assoc_in0(t, ks, v) 852 | local path = butlast(ks) 853 | local final = last(ks) 854 | local t0 = (t or {}) 855 | local function _2_(acc, k) 856 | local step = get(acc, k) 857 | if nil_3f(step) then 858 | return get(assoc(acc, k, {}), k) 859 | else 860 | return step 861 | end 862 | end 863 | assoc(reduce(_2_, t0, path), final, v) 864 | return t0 865 | end 866 | v_0_0 = assoc_in0 867 | _0_0["assoc-in"] = v_0_0 868 | v_0_ = v_0_0 869 | end 870 | local t_0_ = (_0_0)["aniseed/locals"] 871 | t_0_["assoc-in"] = v_0_ 872 | assoc_in = v_0_ 873 | end 874 | local update = nil 875 | do 876 | local v_0_ = nil 877 | do 878 | local v_0_0 = nil 879 | local function update0(t, k, f) 880 | return assoc(t, k, f(get(t, k))) 881 | end 882 | v_0_0 = update0 883 | _0_0["update"] = v_0_0 884 | v_0_ = v_0_0 885 | end 886 | local t_0_ = (_0_0)["aniseed/locals"] 887 | t_0_["update"] = v_0_ 888 | update = v_0_ 889 | end 890 | local update_in = nil 891 | do 892 | local v_0_ = nil 893 | do 894 | local v_0_0 = nil 895 | local function update_in0(t, ks, f) 896 | return assoc_in(t, ks, f(get_in(t, ks))) 897 | end 898 | v_0_0 = update_in0 899 | _0_0["update-in"] = v_0_0 900 | v_0_ = v_0_0 901 | end 902 | local t_0_ = (_0_0)["aniseed/locals"] 903 | t_0_["update-in"] = v_0_ 904 | update_in = v_0_ 905 | end 906 | local constantly = nil 907 | do 908 | local v_0_ = nil 909 | do 910 | local v_0_0 = nil 911 | local function constantly0(v) 912 | local function _2_() 913 | return v 914 | end 915 | return _2_ 916 | end 917 | v_0_0 = constantly0 918 | _0_0["constantly"] = v_0_0 919 | v_0_ = v_0_0 920 | end 921 | local t_0_ = (_0_0)["aniseed/locals"] 922 | t_0_["constantly"] = v_0_ 923 | constantly = v_0_ 924 | end 925 | return nil 926 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------